Compare commits

..

55 Commits

Author SHA1 Message Date
sathwikcs
92feb5d353 Merge remote-tracking branch 'origin/dev-server-2.1.130-review-retryUsb' into dev-server-2.1.130-review-retryUsb 2025-01-20 12:31:17 +05:30
sathwikcs
f4387871fb Merge remote-tracking branch 'origin/dev-server-2.1.130-review-retryUsb' into dev-server-2.1.130-review-retryUsb 2025-01-20 12:31:00 +05:30
sathwikcs
0e2d1daaf6 Merge remote-tracking branch 'origin/dev-server-2.1.130-review-retryUsb' into dev-server-2.1.130-review-retryUsb 2025-01-13 16:09:14 +05:30
sathwikcs
83354e37d9 Merge remote-tracking branch 'origin/dev-server-2.1.130-review-retryUsb' into dev-server-2.1.130-review-retryUsb 2025-01-13 16:08:44 +05:30
sathwikcs
bd8df47262 optimised to retry usb 2025-01-13 16:08:21 +05:30
Sathwik C S
91e2032af7 Update .gitlab-ci.yml file 2025-01-08 06:17:48 +00:00
sathwikcs
0179173860 optimised to retry usb 2025-01-06 17:51:54 +05:30
sathwikcs
36dc7e68a2 optimised to retry usb 2024-12-31 11:43:51 +05:30
chandrashekhar reddy
0886f000bf new branch for review, refactored the code 2024-12-13 12:10:51 +05:30
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
chandrashekhar reddy
735afbf3c0 new 125 version, changes in HemoCubeFragment, latest version 2024-07-08 14:29:10 +05:30
chandrashekhar reddy
5c8d6581b6 new 125 version 2024-06-27 17:24:31 +05:30
chandrashekhar reddy
1f9784aea6 new 125 version 2024-06-27 17:18:39 +05:30
chandrashekhar reddy
81b799d9c1 new 125 version 2024-06-27 17:11:50 +05:30
chandrashekhar reddy
b89139d571 new 125 version 2024-06-27 17:07:38 +05:30
chandrashekhar reddy
0de4b71866 new 124 version 2024-06-27 16:49:32 +05:30
chandrashekhar reddy
331726682f new 124 version 2024-06-25 13:06:20 +05:30
chandrashekhar reddy
c41a2f5139 new 124 version with cuvette size option, pipeline fixed 2024-06-11 18:35:14 +05:30
chandrashekhar reddy
262f334f40 new 124 version with cuvette size option 2024-06-11 18:13:27 +05:30
chandrashekhar reddy
50fd8c0632 new 124 version with cuvette size option 2024-06-06 12:05:49 +05:30
chandrashekhar reddy
bdb58f9b49 new 124 version with cuvette size option 2024-06-05 16:22:12 +05:30
chandrashekhar reddy
7fe72b0371 new 124 version with cuvette size option 2024-05-22 13:22:30 +05:30
chandrashekhar reddy
d620aa9e0d new 124 version with cuvette size option 2024-05-22 12:54:32 +05:30
chandrashekhar reddy
238debae85 device Diagnostics updated the screen with progress bar 2024-04-30 17:56:51 +05:30
chandrashekhar reddy
4ba2f38583 device Diagnostics for user has been integrated 2024-04-29 18:15:20 +05:30
chandrashekhar reddy
0b6e3749c3 constants value added molbio integration 2024-04-25 12:48:52 +05:30
chandrashekhar reddy
f2e9bf2eed Merge remote-tracking branch 'origin/dev' into dev 2024-04-15 12:20:16 +05:30
chandrashekhar reddy
7fcfd58544 quality version bulid for V1 device 2024-04-15 12:20:04 +05:30
Mariya
628b84bfef changed the time zone for result upload for molbio 2024-04-05 14:23:51 +05:30
chandrashekhar reddy
c825ebbda3 Removed the finish activity in HomeFragment while calling kit activity so onback pressed app will not exit instead come back to home 2024-04-03 17:13:15 +05:30
chandrashekhar reddy
fe8a340021 Added details in AboutFragment about SMI 2024-04-03 17:04:51 +05:30
chandrashekhar reddy
6bbbcea227 For security added sql cipher to room and removed bug in ActivitiesFragment 2024-04-03 13:45:41 +05:30
chandrashekhar reddy
ad237e75ae Duplicate test data in local database removed by adding update query in HemoCubeDao 2024-03-31 00:03:48 +05:30
chandrashekhar reddy
5cfb04c680 HemoCubeFragment test cases updated 2024-03-30 14:19:47 +05:30
119 changed files with 6496 additions and 3388 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
variables:
# ANDROID_COMPILE_SDK is the version of Android you're compiling with.
# It should match compileSdkVersion.
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"
# 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"
# Keystore credentials stored as GitLab CI/CD variables
KEYSTORE_PASSWORD: $KS_PASSWORD
KEY_ALIAS: $KS_ALIAS
KEY_PASSWORD: $KS_KEY_PASSWORD
# Packages installation before running script
before_script:
- apt-get --quiet update --yes
- 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"
# Create a new directory at specified location
- 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
- 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"
- export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/cmdline-tools/tools/bin
# Nothing fancy here, just checking sdkManager version
- sdkmanager --version
# use yes to accept all licenses
- yes | sdkmanager --licenses > /dev/null || true
- sdkmanager "platforms;android-${ANDROID_COMPILE_SDK}"
- sdkmanager "platform-tools"
- sdkmanager "build-tools;${ANDROID_BUILD_TOOLS}"
# Not necessary, but just for surity
- chmod +x ./gradlew
# Basic android and gradle stuff
# Check linting
lintDebug:
interruptible: true
stage: build
@@ -69,7 +37,6 @@ lintDebug:
expose_as: "lint-report"
when: always
# Make Project
assembleDebug:
interruptible: true
stage: build
@@ -78,8 +45,68 @@ assembleDebug:
artifacts:
paths:
- app/build/outputs/
# 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
# Run all tests, if any fails, interrupt the pipeline(fail it)
debugTests:
needs: [lintDebug, assembleDebug]
interruptible: true

View File

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

View File

@@ -15,13 +15,13 @@ android {
namespace 'in.sminnovations.hpostesting'
// dev -> development, quality -> qc, uat -> User Acceptance Testing, preprod -> preproduction, prod -> production, iocl -> iocl-iisc production
// server -> for server switching for internal test
defaultConfig {
applicationId "in.sminnovations.hpostesting.dev"
applicationId "in.sminnovations.hpostesting.server"
minSdk 21
targetSdk 34
versionCode 122
versionName "2.1.122"
versionCode 130
versionName "2.1.130 -usb"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@@ -30,6 +30,7 @@ android {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.debug
}
}
compileOptions {
@@ -63,6 +64,7 @@ android {
dependencies {
implementation "com.google.dagger:hilt-android:2.46"
implementation 'androidx.activity:activity:1.8.0'
implementation 'androidx.compose.ui:ui-android:1.7.6'
kapt "com.google.dagger:hilt-android-compiler:2.46"
implementation 'androidx.core:core-ktx:1.12.0'
@@ -76,6 +78,7 @@ dependencies {
implementation platform('com.google.firebase:firebase-bom:32.1.0')
implementation("com.google.firebase:firebase-perf-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-firestore-ktx'
implementation 'com.google.firebase:firebase-auth-ktx'
@@ -89,7 +92,6 @@ dependencies {
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 'com.google.android.play:core:1.10.3'
implementation 'io.nats:jnats:2.11.4'
@@ -121,10 +123,9 @@ dependencies {
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0"
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"
// CSV read, write
implementation 'com.opencsv:opencsv:5.9'
@@ -164,10 +165,12 @@ dependencies {
implementation("androidx.work:work-runtime-ktx:2.9.0")
// 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 'io.nats:jnats:2.11.4'
implementation 'org.apache.commons:commons-math3:3.6.1'
implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.17'
implementation 'androidx.security:security-crypto:1.1.0-alpha03'
}

View File

@@ -7,178 +7,9 @@
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:650071678820:android:f1435a1c07f710036c6471",
"mobilesdk_app_id": "1:650071678820:android:f6fd45e2f6a63aef6c6471",
"android_client_info": {
"package_name": "com.example.hposconsentform"
}
},
"oauth_client": [
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyAVdNGCev_AFX0qmuZJF6kxzRzXUTeAW5I"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:650071678820:android:7865bef608cdee6f6c6471",
"android_client_info": {
"package_name": "com.smi.counselling"
}
},
"oauth_client": [
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyAVdNGCev_AFX0qmuZJF6kxzRzXUTeAW5I"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:650071678820:android:2925e9ce3417d2386c6471",
"android_client_info": {
"package_name": "in.sminnovations.hemocube"
}
},
"oauth_client": [
{
"client_id": "650071678820-srhm9spm9hjn4frcd3r6o02gdhdbtd15.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "in.sminnovations.hemocube",
"certificate_hash": "7714b9268a81d0cf0fb178b0af8dbb630f8fc70a"
}
},
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyAVdNGCev_AFX0qmuZJF6kxzRzXUTeAW5I"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:650071678820:android:7569c1cad4fc99916c6471",
"android_client_info": {
"package_name": "in.sminnovations.hposregistration"
}
},
"oauth_client": [
{
"client_id": "650071678820-70kp5jvjda4r5diqch2kn4lc40p4f42g.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "in.sminnovations.hposregistration",
"certificate_hash": "7714b9268a81d0cf0fb178b0af8dbb630f8fc70a"
}
},
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyAVdNGCev_AFX0qmuZJF6kxzRzXUTeAW5I"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:650071678820:android:f96be19e5d43102b6c6471",
"android_client_info": {
"package_name": "in.sminnovations.hpostesting"
}
},
"oauth_client": [
{
"client_id": "650071678820-l87dnr0bdj95get0khgnvfv2an1k6ogq.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "in.sminnovations.hpostesting",
"certificate_hash": "7714b9268a81d0cf0fb178b0af8dbb630f8fc70a"
}
},
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyAVdNGCev_AFX0qmuZJF6kxzRzXUTeAW5I"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:650071678820:android:a53292637abb7c0d6c6471",
"android_client_info": {
"package_name": "in.sminnovations.hpostesting.dev"
"package_name": "in.sminnovations.hpostesting.server"
}
},
"oauth_client": [

View File

@@ -4,17 +4,34 @@
"type": "APK",
"kind": "Directory"
},
"applicationId": "in.sminnovations.hpostesting.quality",
"applicationId": "in.sminnovations.hpostesting.dev",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 101,
"versionName": "2.1.101",
"versionCode": 127,
"versionName": "2.1.127",
"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

@@ -2,6 +2,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission
android:name="android.permission.AUTHENTICATE_ACCOUNTS"
android:maxSdkVersion="22" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
@@ -22,6 +25,12 @@
<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
android:name="com.example.hpostesting.HPOSTestingApplication"
android:allowBackup="true"
@@ -34,13 +43,37 @@
android:supportsRtl="true"
android:theme="@style/Theme.HPOSTesting"
tools:targetApi="31">
<activity
android:name="com.example.hpostesting.presentation.dashboard.UpdateValuesActivity"
android:exported="false"
android:screenOrientation="portrait"/>
<service
android:name="com.example.hpostesting.util.MyAuthenticatorService"
android:exported="true"
android:permission="android.permission.BIND_AUTOFILL_SERVICE">
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator" />
</intent-filter>
<meta-data
android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/authenticator" />
</service>
<activity
android:name="com.example.hpostesting.presentation.dashboard.ui.PasswordResetActivity"
android:exported="false"
android:screenOrientation="portrait" />
<activity
android:name="com.example.hpostesting.presentation.usb_teminal.UsbTerminalActivity"
android:screenOrientation="portrait"
android:exported="false" />
android:exported="false"
android:launchMode="singleInstance"
android:screenOrientation="portrait" />
<activity
android:name="com.example.hpostesting.presentation.deviceinfo.DeviceActivity"
android:exported="false" />
android:exported="false"
android:theme="@style/Theme.HPOS.NoActionBar" />
<activity
android:name="com.example.hpostesting.presentation.hemocube.DigitalCardActivity"
android:exported="false" />
@@ -48,6 +81,10 @@
android:name="com.example.hpostesting.presentation.diagnostics.DiagnosticsActivity"
android:exported="false"
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
android:name="com.example.hpostesting.presentation.autodac.AutoDacActivity"
android:exported="false"
@@ -98,12 +135,12 @@
android:theme="@style/Theme.HPOS.NoActionBar" />
<activity
android:name="com.example.hpostesting.presentation.dashboard.DashboardActivity"
android:exported="false"
android:exported="true"
android:permission=""
android:label="@string/title_activity_dashboard"
android:screenOrientation="portrait"
android:theme="@style/Theme.HPOS.NoActionBar"
tools:ignore="AppLinkUrlError,MissingClass">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
@@ -125,13 +162,14 @@
android:exported="true"
android:noHistory="true"
android:theme="@style/AppTheme.NoActionBar">
<!-- <intent-filter>-->
<!-- <action android:name="android.intent.action.MAIN" />-->
<!-- <category android:name="android.intent.category.HOME" />-->
<!-- <category android:name="android.intent.category.DEFAULT" />-->
<!-- <category android:name="android.intent.category.MONKEY"/>-->
<!-- <category android:name="android.intent.category.LAUNCHER_APP" />-->
<!-- </intent-filter>-->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.MONKEY" />
<category android:name="android.intent.category.LAUNCHER_APP" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -140,8 +178,9 @@
</activity>
<activity
android:name="com.example.hpostesting.presentation.testRight.TestRightActivity"
android:exported="false"
android:exported="true"
android:noHistory="true"
android:permission=""
android:parentActivityName="com.example.hpostesting.presentation.MainActivity"
android:theme="@style/Theme.HPOS.NoActionBar"
android:windowSoftInputMode="adjustPan">
@@ -158,7 +197,9 @@
<activity
android:name="com.example.hpostesting.presentation.MainActivity"
android:exported="true"
android:permission=""
android:screenOrientation="portrait"
android:launchMode="singleInstance"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />

View File

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

View File

@@ -14,6 +14,13 @@
package com.example.hpostesting.data.constant
object Constants {
const val CENTER_NAME =""
const val DISTRICT =""
const val BUFFER_FLAGS_ENABLED = true//testing flag disable then pass buffer and sample checks
const val ABS_FLAGS_ENABLED = false
const val IP_ADDRESS="ip_address"
const val QUICK_CAPTURE="quick_capture"
const val KIT_TIME = "kit_time"
const val ACTION_USB_PERMISSION = "shanmukha.in.sickle_cell.USB_PERMISSION"
const val HEMOCUBE_USB_PERMISSION = "shanmukha.in.sickle_cell_homocube.USB_PERMISSION"
const val passphrase = "smi_#@sql"
@@ -21,8 +28,8 @@ object Constants {
const val DOCUMENT_ID_FOR_UPDATE ="2o71vBKLqdgEKYtFG8Lb"
const val ABHA_APP_PACKAGE = "in.ndhm.phr"
const val MOLBIO_INTEGRATION = true
const val FIREBASE_INTEGRATION = false
const val MOLBIO_INTEGRATION = false
const val FIREBASE_INTEGRATION = true
const val deviceProvisionEmail = "HPOS_provisioner@bigtec.co.in"
const val deviceProvisionPassword = "f2ab0e7f9d69"
const val DEVICE_ID_API = "deviceIDAPI"
@@ -38,7 +45,8 @@ object Constants {
const val TEST_RIGHT_TOTAL_PIXEL = 3694
const val MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE = 40
const val MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE = 34
const val MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE10MM = 9
const val RANGE_IN_RESULT_CALCULATIONS = 10
@@ -79,178 +87,16 @@ object Constants {
// jig
const val NAVIGATE_TO_TEST_JIG_DIRECTLY = false
val STATICID = listOf(
"FACTORY",
"ADMIN",
"PQUSER",
"QCUSER",
"VIZ-1000-0004",
"VIZ-1000-0005",
"VIZ-1000-0006",
"HC-V1-001",
"HC-V1-002",
"HC-V1-003",
"HC-V1-004",
"HC-V1-005",
"HC-V1-006",
"HC-V1-007",
"HC-V1-008",
"HC-V1-009",
"HC-V1-010",
"HC-V1-011",
"HC-V1-012",
"HC-V1-013",
"HC-V1-014",
"HC-V1-015",
"HC-V1-016",
"HC-V1-017",
"HC-V1-018",
"HC-V1-019",
"HC-V1-020",
"HCV-000-1015",
"HCV-000-3002",
"HCV-000-3003",
"HCV-000-3004",
"HCV-000-3005",
"HCV-000-3006",
"HCV-000-3007",
"HCV-000-3008",
"HCV-000-3009",
"HCV-000-3010",
"HCV-000-3011",
"HCV-000-3012",
"HCV-000-3013",
"HCV-000-3014",
"HCV-000-3015",
"HCV-000-3016",
"HCV-000-3017",
"HCV-000-3018",
"HCV-000-3019",
"HCV-000-3020",
"HCV-000-3021",
"HCV-000-3022",
"HCV-000-3023",
"HCV-000-3024",
"HCV-000-3025",
"HCV-000-3026",
"HCV-000-3027",
"HCV-000-3028",
"HCV-000-3029",
"HCV-000-3030",
"HPP1-0124-0001",
"HPP1-0124-0002",
"HPP1-0124-0003",
"HPP1-0124-0004",
"HPP1-0124-0005",
"HPP1-0124-0006",
"HPP1-0124-0007",
"HPP1-0124-0008",
"HPP1-0124-0009",
"HPP1-0124-0010",
"HPP1-0124-0011",
"HPP1-0124-0012",
"HPP1-0124-0013",
"HPP1-0124-0014",
"HPP1-0124-0015",
"HPP1-0124-0016",
"HPP1-0124-0017",
"HPP1-0124-0018",
"HPP1-0124-0019",
"HPP1-0124-0020",
"HPP1-0124-0021",
"HPP1-0124-0022",
"HPP1-0124-0023",
"HPP1-0124-0024",
"HPP1-0124-0025",
"HPP1-0124-0026",
"HPP1-0124-0027",
"HPP1-0124-0028",
"HPP1-0124-0029",
"HPP1-0124-0030",
"HPP1-0124-0031",
"HPP1-0124-0032",
"HPP1-0124-0033",
"HPP1-0124-0034",
"HPP1-0124-0035",
"HPP1-0124-0036",
"HPP1-0124-0037",
"HPP1-0124-0038",
"HPP1-0124-0039",
"HPP1-0124-0040",
"HPP1-0124-0041",
"HPP1-0124-0042",
"HPP1-0124-0043",
"HPP1-0124-0044",
"HPP1-0124-0045",
"HPP1-0124-0046",
"HPP1-0124-0047",
"HPP1-0124-0048",
"HPP1-0124-0049",
"HPP1-0124-0050",
"HCV-001-0001",
"HCV-001-0002",
"HCV-001-0003",
"HCV-001-0004",
"HCV-001-0005",
"HCV-001-0006",
"HCV-001-0007",
"HCV-001-0008",
"HCV-001-0009",
"HCV-001-0010",
"HCV-001-0011",
"HCV-001-0012",
"HCV-001-0013",
"HCV-001-0014",
"HCV-001-0015",
"HCV-001-0016",
"HCV-001-0017",
"HCV-001-0018",
"HCV-001-0019",
"HCV-001-0020",
"HCV-001-0021",
"HCV-001-0022",
"HCV-001-0023",
"HCV-001-0024",
"HCV-001-0025",
"HCV-001-0026",
"HCV-001-0027",
"HCV-001-0028",
"HCV-001-0029",
"HCV-001-0030",
"HCV-001-0031",
"HCV-001-0032",
"HCV-001-0033",
"HCV-001-0034",
"HCV-001-0003",
"HCV-001-0035",
"HCV-001-0036",
"HCV-001-0037",
"HCV-001-0038",
"HCV-001-0039",
"HCV-001-0040",
"HCV-001-0041",
"HCV-001-0042",
"HCV-001-0043",
"HCV-001-0044",
"HCV-001-0045",
"HCV-001-0046",
"HCV-001-0047",
"HCV-001-0048",
"HCV-001-0049",
"HCV-001-0050",
"HCV-000-6001",
"HCV-000-6002",
"HCV-000-6003",
"HCV-000-6004",
"HCV-000-6005",
"HCV-000-6006",
"HCV-000-6007",
"HCV-000-6008",
"HCV-000-6009",
"HCV-000-6010",
)
//update values of abs
const val ABS2LED1MMLL = "ABS2LED1MMLL"
const val ABS2LED1MMUL = "ABS2LED1MMUL"
const val ABS2LED2MMLL = "ABS2LED2MMLL"
const val ABS2LED2MMUL = "ABS2LED2MMUL"
const val password = "SMI@12345"
const val ABS10LED1MMLL = "ABS10LED1MMLL"
const val ABS10LED1MMUL = "ABS10LED1MMUL"
const val ABS10LED2MMLL = "ABS10LED2MMLL"
const val ABS10LED2MMUL = "ABS10LED2MMUL"
const val KIT_NUMBER = "KitNumber"
const val KIT_COUNT = "KitCount"
@@ -261,7 +107,8 @@ object Constants {
const val BUFFER_VALUE_4 = "BufferValue4"
const val DEVICE_ID = "DEVICE_ID"
const val LABNAME = "LAB_NAME"
const val CUVETTE_SIZE = "CUVETTE_SIZE"
const val LAST_UPDATED = "LAST_UPDATED"
const val IS_TOKEN_AVAILABLE = "IS_TOKEN_AVAILABLE"
const val BUFFER_LED_LOWER_BOUND = 21000
const val BUFFER_LED_UPPER_BOUND = 23500
@@ -1239,13 +1086,14 @@ object Constants {
)
const val INCUBATION_TIME_MIN = 0
const val INCUBATION_TIME_MAX = 1400
const val INCUBATION_TIME_MAX = 300
const val MAX_KIT_TIME = 240
const val BATTERY_LEVEL_MIN = Int.MIN_VALUE
const val PQ_MODE = true
const val READINGS_PER_SAMPLE = 1
const val MINIMUM_BATTERY_LEVEL = 40F
const val MINIMUM_BATTERY_LEVEL = 0
val BUFFER_INTENSITY_THRESHOLDS: Map<String, List<List<Int>>> = mapOf<String, List<List<Int>>>(
"HCV-000-3001" to listOf(
@@ -1736,5 +1584,48 @@ object Constants {
listOf(0.0, 0.0)
)
)
//Hemocube for 10mm
const val positiveBoderLine10mm1 = 1.3
const val positiveBoderLine10mm2 = 1.66
const val negativeBoderLine10mm1 = 2.0
const val negativeBoderLine10mm2 = 2.4
const val normalMin10mm = 0.07
const val normalMax10mm = 0.23
const val negativeBorderlineMin10mm = 0.23
const val negativeBorderlineMax10mm = 0.27
const val sickleCellTraitMin10mm = 0.27
const val sickleCellTraitMax10mm = 0.31
const val positiveForSickleCellMin10mm = 0.31
const val positiveForSickleCellMax10mm = 0.39
const val sickleCellDiseaseMin10mm = 0.39
const val sickleCellDiseaseMax10mm = 0.7
//Hemocube for 2mm
const val positiveBoderLine2mm1 = 0.8
const val positiveBoderLine2mm2 = 1.1
const val negativeBoderLine2mm1 = 1.5
const val negativeBoderLine2mm2 = 1.9
const val normalMin2mm = 0.1
const val normalMax2mm = 0.23
const val negativeBorderlineMin2mm = 0.23
const val negativeBorderlineMax2mm = 0.25
const val sickleCellTraitMin2mm = 0.25
const val sickleCellTraitMax2mm = 0.31
const val positiveForSickleCellMin2mm = 0.31
const val positiveForSickleCellMax2mm = 0.45
const val sickleCellDiseaseMin2mm = 0.45
const val sickleCellDiseaseMax2mm = 0.7
const val min2mmLed1 = 0.34
const val max2mmLed1 = 1.48
const val min2mmLed2 = 0.04
const val max2mmLed2 = 0.33
const val min10mmLed1 = 0.22
const val max10mmLed1 = 1.12
const val min10mmLed2 = 0.05
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
}

View File

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

View File

@@ -30,4 +30,5 @@ enum class HemoCubeCommands(val command: String) {
FORTH_GAIN_COMMAND("W\r"),
CHECK_CUVETTE_COMMAND("L\r"),
CHECK_TEMP_COMMAND("A\r"),
J_COMMAND("J\r"),
}

View File

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

View File

@@ -40,7 +40,8 @@ interface HemoCubeDao {
@Query("DELETE FROM hemo_cube_test_table WHERE _id = :id")
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")
suspend fun updateFieldById(id: String, newValue: Boolean)
@@ -50,8 +51,11 @@ interface HemoCubeDao {
@Query("UPDATE hemo_cube_test_table SET isCSVCreated = :newValue WHERE _id = :id")
suspend fun updateCSVFieldById(id: String, newValue: Boolean)
@Query("SELECT * from hemo_cube_test_table WHERE molbioFlag = 0")
@Query("SELECT * from hemo_cube_test_table WHERE localFlag = 0")
fun getPendingUser(): LiveData<List<HemoCubeTestData>>
@Update
suspend fun updateTest(hemoCubeTestData: HemoCubeTestData)
}

View File

@@ -19,12 +19,11 @@ import androidx.room.TypeConverters
import com.example.hpostesting.data.model.patient.BufferCheckData
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.MolbioHemocubeData
import com.example.hpostesting.data.model.patient.UserData
@Database(
entities = [UserData::class, HemoCubeTestData::class, DeviceData::class, BufferCheckData::class,MolbioHemocubeData::class],
version = 34,
entities = [UserData::class, HemoCubeTestData::class, DeviceData::class, BufferCheckData::class],
version = 38,
exportSchema = false
)
@TypeConverters(Converters::class)
@@ -32,5 +31,4 @@ abstract class MyDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
abstract fun hemoCubeDao(): HemoCubeDao
abstract fun hemoCubeBufferDao(): HemoCubeBufferDao
}

View File

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

View File

@@ -14,16 +14,15 @@
package com.example.hpostesting.data.model.molbioresult
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.MolbioHemocubeData
data class MolbioV2Result(
// val age: Int? = 31,
val age: Int? = 31,
val analysisDate: String? = "2024-02-08 16:33:56",
val analysisId: String? = "",
val analysisStatus: String? = "",
val analysisType: String? = "HPOS",
val analysisTypeMethod: String? = "",
// val bloodGroup: String? = "",
val bloodGroup: String? = "",
val coefficients: List<Int>? = listOf(22, 22),
val collectionLocation: List<Any>? = listOf(),
val collectionTime: String? = "2024-02-08 16:33:56",
@@ -31,12 +30,12 @@ data class MolbioV2Result(
val curveFitting: String? = "Linear",
val deviceName: String? = "HPOS",
val expiryTime: String? = "2024-02-08 16:33:56",
// val gender: String? = "",
val gender: String? = "",
val interpretation: String? = "",
val `operator`: String? = "",
val patientId: Int? = 4545,
val pregnancy: Boolean? = false,
val rawData: MolbioHemocubeData? = HemoCubeTestData().MolbioHemocubeData(),
val rawData: HemoCubeTestData? = HemoCubeTestData(),
val recommendation: String? = "NA",
val sampleId: String? = "",
val sampleType: String? = "",

View File

@@ -14,15 +14,14 @@
package com.example.hpostesting.data.model.molbioresult
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.MolbioHemocubeData
data class MolbioV2ResultData(
// val age: Int? = 0,
val age: Int? = 0,
val analysisDate: String? = "2024-02-08 16:33:56",
val analysisStatus: String? = "",
val analysisType: String? = "",
val analysisTypeMethod: String? = "",
// val bloodGroup: String? = "",
val bloodGroup: String? = "",
val coefficients: List<Int>? = listOf(),
val collectionLocation: List<Any>? = listOf(),
val collectionTime: String? = "2024-02-08 16:33:56",
@@ -32,13 +31,13 @@ data class MolbioV2ResultData(
val curveFitting: String? = "",
val deviceId: Int? = 0,
val expiryTime: String? = "2024-02-08 16:33:56",
// val gender: String? = "",
val gender: String? = "",
val id: Int? = 0,
val interpretation: String? = "",
val `operator`: String? = "",
val patientId: Int? = 0,
val pregnancy: Boolean? = false,
val rawData: MolbioHemocubeData? = HemoCubeTestData().MolbioHemocubeData(),
val rawData: HemoCubeTestData? = HemoCubeTestData(),
val recommendation: String? = "",
val sampleId: String? = "",
val sampleType: String? = "",

View File

@@ -24,7 +24,7 @@ data class HemoCubeTestData(
var name: String = "",
var incubationTime: String = "",
var bloodGroup: String = "",
var birthYear: String = "",
var age: String = "",
var state: String = "",
var abhaId: String = "",
var userImageURL: String = "",
@@ -106,91 +106,10 @@ data class HemoCubeTestData(
var filter: String? = "",
var volume: String? = "",
var isCSVCreated: Boolean = false,
var labName: String? = ""
)
fun HemoCubeTestData.MolbioHemocubeData() = MolbioHemocubeData(
sampleid = sampleid,
_id = _id,
name = name,
incubationTime = incubationTime,
state = state,
location = location,
reportUploadTime = reportUploadTime,
testType = testType,
testTime = testTime,
testStatus = testStatus,
localFlag = localFlag,
deviceId = deviceId,
appVersion = appVersion,
deviceSerialNumber = deviceSerialNumber,
deviceType = deviceType,
kitSerial = kitSerial,
resultData = resultData,
led1Buffer = led1Buffer,
led2Buffer = led2Buffer,
led3Buffer = led3Buffer,
led4Buffer = led4Buffer,
led1Sample = led1Sample,
led2Sample = led2Sample,
led3Sample = led3Sample,
led4Sample = led4Sample,
led1Average = led1Average,
led2Average = led2Average,
led3Average = led3Average,
led4Average = led4Average,
abs1 = abs1,
abs2 = abs2,
abs3 = abs3,
abs4 = abs4,
hb3 = hb3,
hb4 = hb4,
led1Gain1 = led1Gain1,
led2Gain1 = led2Gain1,
led3Gain1 = led3Gain1,
led4Gain1 = led4Gain1,
led1Gain2 = led1Gain2,
led2Gain2 = led2Gain2,
led3Gain2 = led3Gain2,
led4Gain2 = led4Gain2,
led1Gain3 = led1Gain3,
led2Gain3 = led2Gain3,
led3Gain3 = led3Gain3,
led4Gain3 = led4Gain3,
led1Gain4 = led1Gain4,
led2Gain4 = led2Gain4,
led3Gain4 = led3Gain4,
led4Gain4 = led4Gain4,
led1Air1 = led1Air1,
led2Air1 = led2Air1,
led3Air1 = led3Air1,
led4Air1 = led4Air1,
led1Air2 = led1Air2,
led2Air2 = led2Air2,
led3Air2 = led3Air2,
led4Air2 = led4Air2,
deviceRatio = deviceRatio,
calculatedRatio = calculatedRatio,
predictedDenovixRatio = predictedDenovixRatio,
slopeRatio = slopeRatio,
coefficients = coefficients,
classificationResult = classificationResult,
prdClassification = prdClassification,
deviceRatioClass = deviceRatioClass,
slopeRatioClass = slopeRatioClass,
borderlineMethod2Class = borderlineMethod2Class,
errorMessages = errorMessages,
batteryLevel = batteryLevel,
batteryCapacity = batteryCapacity,
batteryMaxCapacity = batteryMaxCapacity,
batteryTemperature = batteryTemperature,
batteryVoltage = batteryVoltage,
molbioFlag = molbioFlag,
quickCapture = quickCapture,
solution = solution,
concentration = concentration,
filter = filter,
volume = volume,
isCSVCreated = isCSVCreated,
labName = labName
var labName: String? = "",
var cuvetteSize: String? = "",
var district: String? = "",
var centerName: String? = "",
var ipAddress:String?= "",
var configUpdatedRecent:String?= ""
)

View File

@@ -1,93 +0,0 @@
package com.example.hpostesting.data.model.patient
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "molbio_hemo_cube_test_table")
data class MolbioHemocubeData(
@PrimaryKey(autoGenerate = true)
var sampleid: Int = 0,
var _id: String = "",
var name: String = "",
var incubationTime: String = "",
var state: String = "",
var location: UserData.Location? = null,
var reportUploadTime: String? = "",
var testType: String? = "HEMOCUBE",
var testTime: String? = "",
var testStatus: Boolean? = false,
var localFlag: Boolean = false,
var deviceId: String? = "",
var appVersion: String? = "",
var deviceSerialNumber: String = "",
var deviceType: String = "HEMOCUBE",
var kitSerial: String = "",
var resultData: String = "",
var led1Buffer: Double? = null,
var led2Buffer: Double? = null,
var led3Buffer: Double? = null,
var led4Buffer: Double? = null,
var led1Sample: Double? = null,
var led2Sample: Double? = null,
var led3Sample: Double? = null,
var led4Sample: Double? = null,
var led1Average: Double? = null,
var led2Average: Double? = null,
var led3Average: Double? = null,
var led4Average: Double? = null,
var abs1: Double? = null,
var abs2: Double? = null,
var abs3: Double? = null,
var abs4: Double? = null,
var hb3: Double? = null,
var hb4: Double? = null,
var led1Gain1: Double? = null,
var led2Gain1: Double? = null,
var led3Gain1: Double? = null,
var led4Gain1: Double? = null,
var led1Gain2: Double? = null,
var led2Gain2: Double? = null,
var led3Gain2: Double? = null,
var led4Gain2: Double? = null,
var led1Gain3: Double? = null,
var led2Gain3: Double? = null,
var led3Gain3: Double? = null,
var led4Gain3: Double? = null,
var led1Gain4: Double? = null,
var led2Gain4: Double? = null,
var led3Gain4: Double? = null,
var led4Gain4: Double? = null,
var led1Air1: Double? = null,
var led2Air1: Double? = null,
var led3Air1: Double? = null,
var led4Air1: Double? = null,
var led1Air2: Double? = null,
var led2Air2: Double? = null,
var led3Air2: Double? = null,
var led4Air2: Double? = null,
var deviceRatio: Double? = null,
var calculatedRatio: Double? = null,
var predictedDenovixRatio: Double? = null,
var slopeRatio: Double? = null,
var coefficients: String? = "",
var classificationResult: String = "",
var prdClassification: String = "",
var deviceRatioClass: String = "",
var slopeRatioClass: String = "",
var borderlineMethod2Class: String = "",
var errorMessages: String = "",
var batteryLevel: String = "",
var batteryCapacity: String = "",
var batteryMaxCapacity: String = "",
var batteryTemperature: String = "",
var batteryVoltage: String = "",
var molbioFlag: Boolean = false,
var quickCapture: Boolean = false,
var solution: String? = "",
var concentration: String? = "",
var filter: String? = "",
var volume: String? = "",
var isCSVCreated: Boolean = false,
var labName: String? = ""
)

View File

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

View File

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

View File

@@ -14,7 +14,6 @@
package com.example.hpostesting.data.repository
import android.net.Uri
import com.example.hpostesting.util.Result
import com.example.hpostesting.data.api.MolbioAuthApi
import com.example.hpostesting.data.api.MolbioResultApi
import com.example.hpostesting.data.model.PendingUploads
@@ -37,15 +36,15 @@ import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.data.model.updates.CheckUpdateRequest
import com.example.hpostesting.data.model.updates.CheckUpdateResponse
import com.example.hpostesting.data.model.updates.DeviceUpdateRequest
import com.example.hpostesting.firebase.FirebaseManager
import com.example.hpostesting.util.Result
import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.firestore.ktx.firestore
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 okhttp3.MultipartBody
import okhttp3.ResponseBody
import retrofit2.HttpException
import java.io.File
import java.net.ConnectException
import java.net.SocketTimeoutException
@@ -53,21 +52,23 @@ import javax.inject.Inject
import javax.inject.Named
class NetworkException(message: String, cause: Throwable) : Exception(message, cause)
class ValidationException(message: String) : Exception(message)
class DatabaseRepository @Inject constructor(
@Named("Auth") private val molbioAuthApi: MolbioAuthApi,
private val molbioResultApi: MolbioResultApi,
private val firebaseManager: FirebaseManager,
) : Repository {
private val db: FirebaseFirestore = Firebase.firestore
private val storage = Firebase.storage
private val localdb: FirebaseFirestore
get() = firebaseManager.getCurrentFirestoreF()
private val localStg: FirebaseStorage
get() = firebaseManager.getCurrentStorageF()
private suspend fun <T : Any> safeApiCall(apiCall: suspend () -> T): Result<T> {
return try {
val response = apiCall.invoke()
Result.Success(response)
}catch (e: HttpException) {
Result.Error(ValidationException("Device Already Registered /"+e.message))
} catch (e: SocketTimeoutException) {
Result.Error(NetworkException("Network timeout", e))
} catch (e: ConnectException) {
@@ -112,18 +113,28 @@ class DatabaseRepository @Inject constructor(
override suspend fun addTestToDatabase(data: HemoCubeTestData?): Response<String> {
return try {
val userdata =
db.collection("patientData").whereEqualTo("_id", data!!._id).get().await()
localdb.collection("patientData").whereEqualTo("_id", data!!._id).get().await()
if (userdata.documents.isNotEmpty()) {
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)
} catch (e: Exception) {
Response.Error(e)
}
}
override suspend fun addQcTestToDatabase(data: HemoCubeTestData?): Response<String> {
return try {
localdb.collection("qcData").add(data!!).await()
Response.Success(data._id)
} catch (e: Exception) {
Response.Error(e)
}
}
override suspend fun addTestToDatabase(data: UserData?): Response<String> {
TODO("Not yet implemented")
@@ -131,7 +142,7 @@ class DatabaseRepository @Inject constructor(
override suspend fun addTestToDatabaseforBufferCheck(data: BufferCheckData?): Response<String> {
return try {
db.collection("buffers").add(data!!).await()
localdb.collection("buffers").add(data!!).await()
Response.Success(data.kitno)
} catch (e: Exception) {
Firebase.crashlytics.recordException(e)
@@ -141,7 +152,7 @@ class DatabaseRepository @Inject constructor(
override suspend fun addDiagnostics(data: DiagnosticsData?): Response<String> {
return try {
db.collection("diagnostics").add(data!!).await()
localdb.collection("diagnostics").add(data!!).await()
Response.Success(data.deviceId)
} catch (e: Exception) {
Firebase.crashlytics.recordException(e)
@@ -149,9 +160,10 @@ class DatabaseRepository @Inject constructor(
}
}
override suspend fun addTestJigData(data: JigData?): Response<String> {
return try {
db.collection("jigs").add(data!!).await()
localdb.collection("jigs").add(data!!).await()
Response.Success(data.deviceId)
} catch (e: Exception) {
Firebase.crashlytics.recordException(e)
@@ -165,7 +177,7 @@ class DatabaseRepository @Inject constructor(
try {
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()
return Response.Success(true)
} catch (e: Exception) {
@@ -176,7 +188,7 @@ class DatabaseRepository @Inject constructor(
suspend fun addToPendingQueue(pendingUploads: PendingUploads): Response<Boolean> {
return try {
db.collection("pendingUploads").document(pendingUploads.pendingId).set(pendingUploads)
localdb.collection("pendingUploads").document(pendingUploads.pendingId).set(pendingUploads)
.await()
Response.Success(true)
@@ -189,7 +201,7 @@ class DatabaseRepository @Inject constructor(
suspend fun getAllFromPendingQueue(): List<PendingUploads> {
val pendingList = mutableListOf<PendingUploads>()
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) {
val pendingFile = doc.toObject(PendingUploads::class.java)
@@ -207,7 +219,7 @@ class DatabaseRepository @Inject constructor(
suspend fun removeFromPendingQueue(fileName: String): Response<Boolean> {
return try {
db.collection("pendingUploads").document(fileName).delete().await()
localdb.collection("pendingUploads").document(fileName).delete().await()
Response.Success(true)
} catch (e: Exception) {
@@ -217,11 +229,11 @@ class DatabaseRepository @Inject constructor(
}
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? {
val querySnapshot = db.collection("devices").get().await()
val querySnapshot = localdb.collection("devices").get().await()
val allDeviceDataList = querySnapshot.toObjects(DeviceData::class.java)
// Find the DeviceData object with the specified deviceId
@@ -230,7 +242,7 @@ class DatabaseRepository @Inject constructor(
override suspend fun getDeviceResponse(data: DeviceData?): Response<String> {
return try {
db.collection("devices").add(data!!).await()
localdb.collection("devices").add(data!!).await()
Response.Success(data.deviceProvisionResponse)
} catch (e: Exception) {
Firebase.crashlytics.recordException(e)
@@ -240,7 +252,7 @@ class DatabaseRepository @Inject constructor(
override suspend fun uploadDeviceId(data: DeviceData): Response<String>? {
return try {
db.collection("devices").add(data!!).await()
localdb.collection("devices").add(data!!).await()
Response.Success(data.deviceId)
} catch (e: Exception) {
Firebase.crashlytics.recordException(e)
@@ -255,13 +267,13 @@ class DatabaseRepository @Inject constructor(
override suspend fun addTestToDatabasefornew(data: HemoCubeTestData?): Response<String> {
return try {
val userdata =
db.collection("patientData").whereEqualTo("_id", data!!._id).get().await()
localdb.collection("patientData").whereEqualTo("_id", data!!._id).get().await()
if (userdata.documents.isNotEmpty()) {
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)
} catch (e: Exception) {
Firebase.crashlytics.recordException(e)

View File

@@ -13,13 +13,7 @@
package com.example.hpostesting.data.repository
import android.os.Environment
import com.example.hpostesting.data.datasource.LocalFileDataSource
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.opencsv.CSVWriter
import java.io.File
import java.io.FileWriter
import java.io.IOException
class LocalFileRepository(private val localFileDataSource: LocalFileDataSource) {
fun saveCsvToDisk(filepath: String, contents: ArrayList<Array<String>>) =

View File

@@ -38,6 +38,7 @@ import okhttp3.ResponseBody
interface Repository {
suspend fun addTestToDatabase(data: HemoCubeTestData?): Response<String>
suspend fun addQcTestToDatabase(data: HemoCubeTestData?): Response<String>
suspend fun addTestToDatabasefornew(data: HemoCubeTestData?): Response<String>
suspend fun addTestToDatabase(data: UserData?): Response<String>

View File

@@ -35,10 +35,13 @@ import com.example.hpostesting.domain.LogFileManager
import com.example.hpostesting.domain.LogFileManagerImpl
import com.example.hpostesting.domain.SaveRawData
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.UsbServiceListenerImpl
import com.example.hpostesting.util.PropertyProvider
import com.example.hpostesting.util.PropertyProviderImpl
import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.storage.FirebaseStorage
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@@ -53,7 +56,6 @@ import java.util.concurrent.TimeUnit
import javax.inject.Named
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
@@ -108,22 +110,52 @@ object AppModule {
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
@Singleton
fun provideDatabaseRepository(
firebaseManager: FirebaseManager,
@Named("Auth") molbioAuthApi: MolbioAuthApi,
molbioResultApi: MolbioResultApi
): DatabaseRepository {
return DatabaseRepository(molbioAuthApi = molbioAuthApi, molbioResultApi = molbioResultApi)
return DatabaseRepository(
firebaseManager = firebaseManager,
molbioAuthApi = molbioAuthApi,
molbioResultApi = molbioResultApi
)
}
@Provides
@Singleton
fun provideRepository(
firebaseManager: FirebaseManager,
@Named("Auth") molbioAuthApi: MolbioAuthApi,
molbioResultApi: MolbioResultApi
): Repository {
return DatabaseRepository(molbioAuthApi, molbioResultApi)
return DatabaseRepository(
firebaseManager = firebaseManager,
molbioAuthApi = molbioAuthApi,
molbioResultApi = molbioResultApi
)
}
@Provides
@@ -207,4 +239,9 @@ object AppModule {
fun provideUsbServiceListener(context: Context): UsbServiceListener {
return UsbServiceListenerImpl(context)
}
}

View File

@@ -44,7 +44,6 @@ class LogFileManagerImpl @Inject constructor(private val context: Context) : Log
file
} catch (e: IOException) {
// Log.e("LogFileManager", "Error creating log file: ${e.message}")
null
}
}

View File

@@ -38,17 +38,21 @@ class ResultCalculationWithMaxImpl : TestRightResultCalculation {
var wavelengthOfAbsorbanceTwo = 0.0
for (each in wavelengthToAbsorbance) {
if (each[0] >= startWavelengthOne && each[0] < endWavelengthOne) {
if (each[1] > maxAbsorbanceAtOne) {
maxAbsorbanceAtOne = each[1]
wavelengthOfAbsorbanceOne = each[0]
when {
each[0] >= startWavelengthOne && each[0] < endWavelengthOne -> {
if (each[1] > maxAbsorbanceAtOne) {
maxAbsorbanceAtOne = each[1]
wavelengthOfAbsorbanceOne = each[0]
}
}
}
if (each[0] >= startWavelengthTwo && each[0] < endWavelengthTwo) {
// maxAbsorbanceAtTwo = max(maxAbsorbanceAtTwo, each[1])
if (each[1] > maxAbsorbanceAtTwo) {
maxAbsorbanceAtTwo = each[1]
wavelengthOfAbsorbanceTwo = each[0]
when {
each[0] >= startWavelengthTwo && each[0] < endWavelengthTwo -> {
// maxAbsorbanceAtTwo = max(maxAbsorbanceAtTwo, each[1])
if (each[1] > maxAbsorbanceAtTwo) {
maxAbsorbanceAtTwo = each[1]
wavelengthOfAbsorbanceTwo = each[0]
}
}
}
}
@@ -70,26 +74,32 @@ class ResultCalculationWithMaxImpl : TestRightResultCalculation {
val value = absorbanceAtWaveTwo / absorbanceAtWaveOne
testRightCalculationData.ratioValue = value
if (value <= 0.29) {
testRightCalculationData.ratioMinRange = 0.0
testRightCalculationData.ratioMaxRange = 0.29
return TestRightResultType.NORMAL
} else if (value > 0.29 && value <= 0.32) {
testRightCalculationData.ratioMinRange = 0.29
testRightCalculationData.ratioMaxRange = 0.32
return TestRightResultType.NEGATIVEBORDERLINE
} else if (value > 0.32 && value <= 0.50) {
testRightCalculationData.ratioMinRange = 0.32
testRightCalculationData.ratioMaxRange = 0.50
return TestRightResultType.SICKLECELLTRAIT
} else if (value > 0.50 && value <= 0.55) {
testRightCalculationData.ratioMinRange = 0.50
testRightCalculationData.ratioMaxRange = 0.55
return TestRightResultType.POSITIVEBORDERLINE
}else if (value > 0.55) {
testRightCalculationData.ratioMinRange = 0.55
testRightCalculationData.ratioMaxRange = 999.0
return TestRightResultType.SICKLECELLDISEASE
when {
value <= 0.29 -> {
testRightCalculationData.ratioMinRange = 0.0
testRightCalculationData.ratioMaxRange = 0.29
return TestRightResultType.NORMAL
}
value > 0.29 && value <= 0.32 -> {
testRightCalculationData.ratioMinRange = 0.29
testRightCalculationData.ratioMaxRange = 0.32
return TestRightResultType.NEGATIVEBORDERLINE
}
value > 0.32 && value <= 0.50 -> {
testRightCalculationData.ratioMinRange = 0.32
testRightCalculationData.ratioMaxRange = 0.50
return TestRightResultType.SICKLECELLTRAIT
}
value > 0.50 && value <= 0.55 -> {
testRightCalculationData.ratioMinRange = 0.50
testRightCalculationData.ratioMaxRange = 0.55
return TestRightResultType.POSITIVEBORDERLINE
}
value > 0.55 -> {
testRightCalculationData.ratioMinRange = 0.55
testRightCalculationData.ratioMaxRange = 999.0
return TestRightResultType.SICKLECELLDISEASE
}
}
}

View File

@@ -27,7 +27,6 @@ class SaveRawData(private val localFileRepository: LocalFileRepository) {
fun saveCsv(folderPath: String, fileName: String, matrix: ArrayList<ArrayList<Double>>) {
// try {
val fullPath = "$folderPath/$fileName"
// val writer = CSVWriter(FileWriter(fullPath))
sort(matrix) { one: ArrayList<Double>, two: ArrayList<Double> ->
one[0].compareTo(two[0])
@@ -39,7 +38,6 @@ class SaveRawData(private val localFileRepository: LocalFileRepository) {
for (eachRow in matrix) {
if (eachRow[0] >= Constants.MIN_WAVELENGTH_RANGE_TO_RECORD && eachRow[0] < Constants.MAX_WAVELENGTH_RANGE_TO_RECORD + 1) {
// val rowContent = arrayOf(String.format("%.3f", eachRow[0]), String.format("%.3f", eachRow[1]))
val rowContent =
arrayOf(
String.format("%.10f", eachRow[0]),
@@ -50,22 +48,9 @@ class SaveRawData(private val localFileRepository: LocalFileRepository) {
}
localFileRepository.saveCsvToDisk(fullPath, content)
// writer.writeAll(content) // data is adding to csv
// writer.close()
// } catch (e: Exception) {
// Log.e(TAG, e.toString())
// }
}
fun saveLog(folderPath: String, fileName: String, calculationData: TestRightCalculationData) {
// val fileObj = File(folderPath, fileName)
// val writer = FileWriter(fileObj)
// writer.append(getLogStringFromObj(calculationData))
// writer.flush()
// writer.close()
val fullPath = folderPath + fileName
localFileRepository.saveTextToDisk(fullPath, getLogStringFromObj(calculationData))
}
@@ -113,13 +98,6 @@ class SaveRawData(private val localFileRepository: LocalFileRepository) {
calculationData: TestRightCalculationData,
testDetails: UserData?,
) {
// val fileObj = File(folderPath, fileName)
// val writer = FileWriter(fileObj)
// writer.append(getLogStringFromObjWithPatientData(calculationData, patientData))
// writer.flush()
// writer.close()
val fullPath = folderPath + fileName
localFileRepository.saveTextToDisk(
fullPath,

View File

@@ -24,7 +24,6 @@ class SaveRawDataTest(private val localFileRepository: LocalFileRepository) {
// try {
val fullPath = "$folderPath/$fileName"
// val writer = CSVWriter(FileWriter(fullPath))
val content = ArrayList<Array<String>>()
// Header
@@ -53,19 +52,6 @@ class SaveRawDataTest(private val localFileRepository: LocalFileRepository) {
}
fun saveLog(folderPath: String, fileName: String, isReference: Boolean, fullString: String) {
// val fileObj = File(folderPath, fileName)
// Log.d(TAG, "$folderPath --- $fileName")
// val writer = FileWriter(fileObj)
// if (isReference)
// writer.append("\nREFERENCE OUTPUT\n")
// else
// writer.append("\nSAMPLE OUTPUT\n")
//
// writer.append(fullString)
// writer.flush()
// writer.close()
val filePath = folderPath + fileName
var stringToWrite = ""

View File

@@ -38,17 +38,21 @@ class SickleFindResultCaluculationWithMaxImpl : TestRightResultCalculation{
var wavelengthOfAbsorbanceTwo = 0.0
for (each in wavelengthToAbsorbance) {
if (each[0] >= startWavelengthOne && each[0] < endWavelengthOne) {
if (each[1] > maxAbsorbanceAtOne) {
maxAbsorbanceAtOne = each[1]
wavelengthOfAbsorbanceOne = each[0]
when {
each[0] >= startWavelengthOne && each[0] < endWavelengthOne -> {
if (each[1] > maxAbsorbanceAtOne) {
maxAbsorbanceAtOne = each[1]
wavelengthOfAbsorbanceOne = each[0]
}
}
}
if (each[0] >= startWavelengthTwo && each[0] < endWavelengthTwo) {
// maxAbsorbanceAtTwo = max(maxAbsorbanceAtTwo, each[1])
if (each[1] > maxAbsorbanceAtTwo) {
maxAbsorbanceAtTwo = each[1]
wavelengthOfAbsorbanceTwo = each[0]
when {
each[0] >= startWavelengthTwo && each[0] < endWavelengthTwo -> {
// maxAbsorbanceAtTwo = max(maxAbsorbanceAtTwo, each[1])
if (each[1] > maxAbsorbanceAtTwo) {
maxAbsorbanceAtTwo = each[1]
wavelengthOfAbsorbanceTwo = each[0]
}
}
}
}
@@ -70,18 +74,22 @@ class SickleFindResultCaluculationWithMaxImpl : TestRightResultCalculation{
val value = absorbanceAtWaveTwo / absorbanceAtWaveOne
testRightCalculationData.ratioValue = value
if (value < 0.30 || value == 0.0) {
testRightCalculationData.ratioMinRange = 0.0
testRightCalculationData.ratioMaxRange = 0.30
return TestRightResultType.NORMAL
} else if (value >= 0.30 && value < 0.31) {
testRightCalculationData.ratioMinRange = 0.30
testRightCalculationData.ratioMaxRange = 0.31
return TestRightResultType.UNDEFINED
} else if (value >= 0.31) {
testRightCalculationData.ratioMinRange = 0.31
testRightCalculationData.ratioMaxRange = 999.0
return TestRightResultType.SICKLECELLDISEASE
when {
value < 0.30 || value == 0.0 -> {
testRightCalculationData.ratioMinRange = 0.0
testRightCalculationData.ratioMaxRange = 0.30
return TestRightResultType.NORMAL
}
value >= 0.30 && value < 0.31 -> {
testRightCalculationData.ratioMinRange = 0.30
testRightCalculationData.ratioMaxRange = 0.31
return TestRightResultType.UNDEFINED
}
value >= 0.31 -> {
testRightCalculationData.ratioMinRange = 0.31
testRightCalculationData.ratioMaxRange = 999.0
return TestRightResultType.SICKLECELLDISEASE
}
}
}

View File

@@ -14,6 +14,7 @@
package com.example.hpostesting.encryption
import android.util.Base64
import java.security.SecureRandom
import javax.crypto.Cipher
import javax.crypto.SecretKeyFactory
import javax.crypto.spec.IvParameterSpec
@@ -21,7 +22,8 @@ import javax.crypto.spec.PBEKeySpec
import javax.crypto.spec.SecretKeySpec
object Encryption {
private const val AES_MODE = "AES/CBC/PKCS5Padding"
//private const val AES_MODE = "AES/CBC/PKCS5Padding"
private const val AES_MODE= "AES/GCM/NoPadding"
private const val KEY_SPEC_ALGORITHM = "PBKDF2WithHmacSHA1"
private const val SALT = "Bigtec"
private const val ITERATION_COUNT = 10000
@@ -29,7 +31,8 @@ object Encryption {
private val FIXED_IV = byteArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)
fun encrypt(textToEncrypt: String, password: String): String {
val salt = SALT.toByteArray()
val salt = ByteArray(16)
SecureRandom().nextBytes(salt)
val factory = SecretKeyFactory.getInstance(KEY_SPEC_ALGORITHM)
val spec = PBEKeySpec(password.toCharArray(), salt, ITERATION_COUNT, KEY_LENGTH)
val tmp = factory.generateSecret(spec)
@@ -37,12 +40,12 @@ object Encryption {
val cipher = Cipher.getInstance(AES_MODE)
cipher.init(Cipher.ENCRYPT_MODE, key, IvParameterSpec(FIXED_IV))
val encryptedBytes = cipher.doFinal(textToEncrypt.toByteArray(Charsets.UTF_8))
return Base64.encodeToString(encryptedBytes, Base64.NO_WRAP)
return Base64.encodeToString(salt + encryptedBytes, Base64.NO_WRAP)
}
fun decrypt(encryptedText: String, password: String): String {
val salt = SALT.toByteArray()
val encryptedBytes = Base64.decode(encryptedText, Base64.NO_WRAP)
val salt = encryptedText.substring(0, 24).toByteArray()
val encryptedBytes = Base64.decode(encryptedText.substring(24), Base64.NO_WRAP)
val factory = SecretKeyFactory.getInstance(KEY_SPEC_ALGORITHM)
val spec = PBEKeySpec(password.toCharArray(), salt, ITERATION_COUNT, KEY_LENGTH)
val tmp = factory.generateSecret(spec)
@@ -52,4 +55,29 @@ object Encryption {
val decryptedBytes = cipher.doFinal(encryptedBytes)
return String(decryptedBytes, Charsets.UTF_8)
}
// fun encrypt(textToEncrypt: String, password: String): String {
// val salt = SALT.toByteArray()
// val factory = SecretKeyFactory.getInstance(KEY_SPEC_ALGORITHM)
// val spec = PBEKeySpec(password.toCharArray(), salt, ITERATION_COUNT, KEY_LENGTH)
// val tmp = factory.generateSecret(spec)
// val key = SecretKeySpec(tmp.encoded, "AES")
// val cipher = Cipher.getInstance(AES_MODE)
// cipher.init(Cipher.ENCRYPT_MODE, key, IvParameterSpec(FIXED_IV))
// val encryptedBytes = cipher.doFinal(textToEncrypt.toByteArray(Charsets.UTF_8))
// return Base64.encodeToString(encryptedBytes, Base64.NO_WRAP)
// }
//
// fun decrypt(encryptedText: String, password: String): String {
// val salt = SALT.toByteArray()
// val encryptedBytes = Base64.decode(encryptedText, Base64.NO_WRAP)
// val factory = SecretKeyFactory.getInstance(KEY_SPEC_ALGORITHM)
// val spec = PBEKeySpec(password.toCharArray(), salt, ITERATION_COUNT, KEY_LENGTH)
// val tmp = factory.generateSecret(spec)
// val key = SecretKeySpec(tmp.encoded, "AES")
// val cipher = Cipher.getInstance(AES_MODE)
// cipher.init(Cipher.DECRYPT_MODE, key, IvParameterSpec(FIXED_IV))
// val decryptedBytes = cipher.doFinal(encryptedBytes)
// return String(decryptedBytes, Charsets.UTF_8)
// }
}

View File

@@ -0,0 +1,156 @@
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.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
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)
var currentFirestore: FirebaseFirestore = FirebaseFirestore.getInstance()
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 getCurrentFirestoreF(): FirebaseFirestore = currentFirestore
fun getCurrentStorageF(): 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())
}
fun delayedRestart(
context: Context,
coroutineScope: CoroutineScope = CoroutineScope(Dispatchers.Main),
dispatcher: CoroutineDispatcher = Dispatchers.Main
) {
coroutineScope.launch(dispatcher) {
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

@@ -19,21 +19,19 @@ import android.content.SharedPreferences
import android.os.Bundle
import android.text.Editable
import android.util.Log
import android.view.View
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.data.model.test.TestType
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.testRight.TestRightActivity
import com.google.android.material.snackbar.Snackbar
import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.journeyapps.barcodescanner.ScanContract
import com.journeyapps.barcodescanner.ScanIntentResult
import com.journeyapps.barcodescanner.ScanOptions
import com.zebra.barcode.sdk.sms.ConfigurationUpdateEvent
import com.zebra.scannercontrol.DCSSDKDefs
import com.zebra.scannercontrol.DCSSDKDefs.DCSSDK_COMMAND_OPCODE
@@ -44,9 +42,15 @@ import com.zebra.scannercontrol.IDcsSdkApiDelegate
import com.zebra.scannercontrol.SDKHandler
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityKitScanBinding
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import java.util.Locale
class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
private var fromWhere = "Home"
private val forD10 = "SMI/SC-2-D10/"
private val forD35 = "SMI/SC/"
private val TAG = "KitScanActivity"
private lateinit var binding: ActivityKitScanBinding
@@ -67,8 +71,24 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
}
}
private fun processScannedData(contents: String) {
binding.nameEditText.setText(contents)
private fun processScannedData(contents: String) {//edited auto selection of cuvette size
if(contents.contains(forD35)){
with(sharedPreference.edit()) {
putString(Constants.CUVETTE_SIZE, "2mm")
apply()
}
Toast.makeText(this, "Selected cuvette size: 2mm", Toast.LENGTH_SHORT).show()
binding.nameEditText.setText(contents)
}else if(contents.contains(forD10)){
with(sharedPreference.edit()) {
putString(Constants.CUVETTE_SIZE, "10mm")
apply()
}
Toast.makeText(this, "Selected cuvette size: 10mm", Toast.LENGTH_SHORT).show()
binding.nameEditText.setText(contents)
}else{
Toast.makeText(this, R.string.invalid_kit, Toast.LENGTH_LONG).show()
}
}
override fun attachBaseContext(newBase: Context?) {
@@ -78,33 +98,51 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
}
override fun dcssdkEventScannerAppeared(dcsScannerInfo: DCSScannerInfo?) {}
override fun dcssdkEventScannerAppeared(dcsScannerInfo: DCSScannerInfo?) {
//nothing
}
override fun dcssdkEventScannerDisappeared(i: Int) {}
override fun dcssdkEventScannerDisappeared(i: Int) {
//nothing
}
override fun dcssdkEventCommunicationSessionEstablished(dcsScannerInfo: DCSScannerInfo?) {}
override fun dcssdkEventCommunicationSessionEstablished(dcsScannerInfo: DCSScannerInfo?) {
//nothing
}
override fun dcssdkEventCommunicationSessionTerminated(i: Int) {}
override fun dcssdkEventCommunicationSessionTerminated(i: Int) {
//nothing
}
// override fun dcssdkEventBarcode(p0: ByteArray?, p1: Int, p2: Int) {
// TODO("Not yet implemented")
// }
override fun dcssdkEventImage(bytes: ByteArray?, i: Int) {}
override fun dcssdkEventImage(bytes: ByteArray?, i: Int) {
//nothing
}
override fun dcssdkEventVideo(bytes: ByteArray?, i: Int) {}
override fun dcssdkEventVideo(bytes: ByteArray?, i: Int) {
//nothing
}
override fun dcssdkEventBinaryData(bytes: ByteArray?, i: Int) {}
override fun dcssdkEventBinaryData(bytes: ByteArray?, i: Int) {
//nothing
}
override fun dcssdkEventFirmwareUpdate(firmwareUpdateEvent: FirmwareUpdateEvent?) {}
override fun dcssdkEventFirmwareUpdate(firmwareUpdateEvent: FirmwareUpdateEvent?) {
//nothing
}
override fun dcssdkEventAuxScannerAppeared(
dcsScannerInfo: DCSScannerInfo?,
dcsScannerInfo1: DCSScannerInfo?,
) {
//nothing
}
override fun dcssdkEventConfigurationUpdate(configurationUpdateEvent: ConfigurationUpdateEvent?) {}
override fun dcssdkEventConfigurationUpdate(configurationUpdateEvent: ConfigurationUpdateEvent?) {
//nothing
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -112,10 +150,30 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
binding = ActivityKitScanBinding.inflate(layoutInflater)
sharedPreference = this.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
setContentView(binding.root)
binding.toolbar.title = "Kit Serial Number"
fromWhere = intent.getStringExtra("fromWhere").toString()
val maxTest = if(sharedPreference.getString(Constants.CUVETTE_SIZE, "10mm").toString() == "2mm"){
Constants.MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE
}else{
Constants.MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE10MM
}
val time = timeDifference(sharedPreference.getString(Constants.KIT_TIME, "").toString())
val kitNum = sharedPreference.getString(Constants.KIT_NUMBER, "").toString()
// Toast.makeText(this@KitScanActivity,"Test MAx time"+ time+"-Test count-"+kitNum,Toast.LENGTH_SHORT).show()
if (DataHolder.sampleReadCounter <= Constants.MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE && DataHolder.isReferenceTaken) {
DataHolder.selectedTest!!.kitSerial = DataHolder.kitSerial
if (DataHolder.sampleReadCounter <= maxTest && kitNum != "" && time < Constants.MAX_KIT_TIME) {
moveToNext()
} else {
Toast.makeText(this@KitScanActivity, "Limit Reached, Use New KIT for testing", Toast.LENGTH_SHORT).show()
DataHolder.sampleReadCounter = 0
DataHolder.kitSerial = ""
with(sharedPreference.edit()) {
putString(Constants.KIT_NUMBER, "")
putString(Constants.BUFFER_VALUE_1, "")
putString(Constants.BUFFER_VALUE_2, "")
apply()
}
}
// if (checkHemoCubeKitData()) {
@@ -132,35 +190,31 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
// }
// }
try {
if (checkHemoCubeKitData()) {
DataHolder.selectedTest!!.kitSerial =
sharedPreference.getString(Constants.KIT_NUMBER, "").toString()
moveToNext()
} else {
// Handle the case when checkHemoCubeKitData() returns false
with(sharedPreference.edit()) {
putString(Constants.KIT_NUMBER, "")
putInt(Constants.KIT_COUNT, 0)
putString(Constants.BUFFER_VALUE_1, "")
putString(Constants.BUFFER_VALUE_2, "")
apply()
}
}
} catch (e: NullPointerException) {
// Handle the NullPointerException here
e.printStackTrace() // You can log the exception for debugging
FirebaseCrashlytics.getInstance().recordException(e)
val errorMessage = "An error occurred: ${e.message}"
val rootView = findViewById<View>(android.R.id.content)
Snackbar.make(rootView, errorMessage, Snackbar.LENGTH_LONG).show()
// Optionally, show a user-friendly error message to the user
// Toast.makeText(applicationContext, "An error occurred", Toast.LENGTH_SHORT).show()
}
binding.nameEditText.setText("SMI/SC/")
// try {
// if (checkHemoCubeKitData()) {
// DataHolder.selectedTest!!.kitSerial =
// sharedPreference.getString(Constants.KIT_NUMBER, "").toString()
// moveToNext()
// } else {
// // Handle the case when checkHemoCubeKitData() returns false
// with(sharedPreference.edit()) {
// putString(Constants.KIT_NUMBER, "")
// putInt(Constants.KIT_COUNT, 0)
// putString(Constants.BUFFER_VALUE_1, "")
// putString(Constants.BUFFER_VALUE_2, "")
// apply()
// }
// }
// } catch (e: NullPointerException) {
// // Handle the NullPointerException here
// e.printStackTrace() // You can log the exception for debugging
// FirebaseCrashlytics.getInstance().recordException(e)
// val errorMessage = "An error occurred: ${e.message}"
// val rootView = findViewById<View>(android.R.id.content)
// Snackbar.make(rootView, errorMessage, Snackbar.LENGTH_LONG).show()
// // Optionally, show a user-friendly error message to the user
// // Toast.makeText(applicationContext, "An error occurred", Toast.LENGTH_SHORT).show()
// }
setSupportActionBar(binding.toolbar)
binding.btnScanNow.setOnClickListener {
@@ -171,26 +225,39 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
binding.btnGo.setOnClickListener {
val serialNumber = binding.nameEditText.text.toString().trim()
if (serialNumber.isNotEmpty() && isSerialValid(serialNumber)) {
Toast.makeText(
applicationContext,
R.string.kit_update,
Toast.LENGTH_LONG
).show()
if(serialNumber.contains(forD35)){
with(sharedPreference.edit()) {
putString(Constants.CUVETTE_SIZE, "2mm")
apply()
}
Toast.makeText(this, "Selected cuvette size: 2mm", Toast.LENGTH_SHORT).show()
}else if(serialNumber.contains(forD10)){
with(sharedPreference.edit()) {
putString(Constants.CUVETTE_SIZE, "10mm")
apply()
}
Toast.makeText(this, "Selected cuvette size: 10mm", Toast.LENGTH_SHORT).show()
}
val kitTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time).toString()
if (DataHolder.selectedTest == null) {
with(sharedPreference.edit()) {
putString(
Constants.KIT_NUMBER, binding.nameEditText.text.toString()
)
putString(Constants.BUFFER_VALUE_1, "")
putString(Constants.BUFFER_VALUE_2, "")
putString(Constants.KIT_TIME, kitTime)
putInt(Constants.KIT_COUNT, 1)
apply()
}
DataHolder.kitSerial = binding.nameEditText.text.toString()
Toast.makeText(
applicationContext,
R.string.kit_updated,
Toast.LENGTH_SHORT
).show()
val i = Intent(applicationContext, DashboardActivity::class.java)
startActivity(i)
finish()
@@ -198,6 +265,9 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
DataHolder.kitSerial = binding.nameEditText.text.toString()
DataHolder.selectedTest?.kitSerial = binding.nameEditText.text.toString()
with(sharedPreference.edit()) {
putString(Constants.BUFFER_VALUE_1, "")
putString(Constants.BUFFER_VALUE_2, "")
putString(Constants.KIT_TIME, kitTime)
putString(Constants.KIT_NUMBER, binding.nameEditText.text.toString())
putInt(Constants.KIT_COUNT, 1)
apply()
@@ -208,21 +278,21 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
Toast.makeText(this, R.string.invalid_kit_number, Toast.LENGTH_LONG).show()
return@setOnClickListener
}
if (serialNumber.isNotEmpty() && checkDataNotNull() && isSerialValid(
serialNumber
)
) {
DataHolder.kitSerial = binding.nameEditText.text.toString()
DataHolder.selectedTest?.kitSerial = binding.nameEditText.text.toString()
with(sharedPreference.edit()) {
putString(Constants.KIT_NUMBER, binding.nameEditText.text.toString())
putInt(Constants.KIT_COUNT, 1)
apply()
}
moveToNext()
} else {
Toast.makeText(this, R.string.invalid_kit_number, Toast.LENGTH_LONG).show()
}
// if (serialNumber.isNotEmpty() && checkDataNotNull() && isSerialValid(
// serialNumber
// )
// ) {
// DataHolder.kitSerial = binding.nameEditText.text.toString()
// DataHolder.selectedTest?.kitSerial = binding.nameEditText.text.toString()
// with(sharedPreference.edit()) {
// putString(Constants.KIT_NUMBER, binding.nameEditText.text.toString())
// putInt(Constants.KIT_COUNT, 1)
// apply()
// }
// moveToNext()
// } else {
// Toast.makeText(this, R.string.invalid_kit_number, Toast.LENGTH_LONG).show()
// }
}
//Setting up the SDK handler
@@ -234,11 +304,11 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
//deciding what kind of notifications we want to receive. Explained more in the function
//first we use bitmapping to set these values into the notifications_mask.
var notifications_mask = 0
var notificationsMask = 0
// We would like to subscribe to all barcode events
notifications_mask =
notifications_mask or DCSSDKDefs.DCSSDK_EVENT.DCSSDK_EVENT_BARCODE.value
sdkHandler!!.dcssdkSubsribeForEvents(notifications_mask)
notificationsMask =
notificationsMask or DCSSDKDefs.DCSSDK_EVENT.DCSSDK_EVENT_BARCODE.value
sdkHandler!!.dcssdkSubsribeForEvents(notificationsMask)
mScannerInfoList.addAll(sdkHandler!!.dcssdkGetAvailableScannersList())
Log.e("scannersize", sdkHandler!!.dcssdkGetAvailableScannersList().size.toString())
if (mScannerInfoList.isNotEmpty()) {
@@ -280,76 +350,100 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
val result = String(barcodeData!!)
Log.d("BARCODE", result)
runOnUiThread {
val editableResult: Editable = Editable.Factory.getInstance().newEditable(result)
binding.nameEditText.text = editableResult
Editable.Factory.getInstance().newEditable(result)
processScannedData(result)
// binding.nameEditText.text = editableResult
}
}
private fun checkHemoCubeKitData(): Boolean {
return sharedPreference.getString(Constants.KIT_NUMBER, "")
?.isNotBlank() == true && sharedPreference.getInt(
Constants.KIT_COUNT, 0
) > 0 && sharedPreference.getInt(Constants.KIT_COUNT, 0) < Constants.KIT_CAPACITY
}
// private fun checkHemoCubeKitData(): Boolean {
// return sharedPreference.getString(Constants.KIT_NUMBER, "")
// ?.isNotBlank() == true && sharedPreference.getInt(
// Constants.KIT_COUNT, 0
// ) > 0 && sharedPreference.getInt(Constants.KIT_COUNT, 0) < Constants.KIT_CAPACITY
// }
private fun isSerialValid(s: String): Boolean {
if (s.length != 17) {
binding.nameEditText.error = getString(R.string.invalid_kit)
if (s.contains(forD35)) {
if(s.length != 17){
binding.nameEditText.error = "Invalid Kit Serial Number, correct example SMI/SC/000/00/000"
return false
}
}else if(s.contains(forD10)){
if(s.length != 27){
binding.nameEditText.error = "Invalid Kit Serial Number, correct example SMI/SC-2-D10/000000/000/000"
return false
}
}else{
return false
}
return true
}
private fun moveToNext() {
DataHolder.deviceType.observe(this) { deviceType ->
when (deviceType) {
Constants.DEVICE_TYPE_HEMOCUBE -> {
val i = Intent(applicationContext, HemocubeActivity::class.java)
startActivity(i)
}
Constants.DEVICE_TYPE_TEST_RIGHT -> {
val i = Intent(applicationContext, TestRightActivity::class.java)
startActivity(i)
}
Constants.DEVICE_TYPE_TRUEHEME -> {
val i = Intent(applicationContext, HemocubeActivity::class.java)
startActivity(i)
if(fromWhere == "Main"){
if(DataHolder.selectedTestType == TestType.HB_EST){
val i = Intent(applicationContext, HBTestActivity::class.java)
startActivity(i)
}else{
DataHolder.deviceType.observe(this) { deviceType ->
when (deviceType) {
Constants.DEVICE_TYPE_HEMOCUBE ,Constants.DEVICE_TYPE_TRUEHEME -> {
val i = Intent(applicationContext, HemocubeActivity::class.java)
startActivity(i)
}
Constants.DEVICE_TYPE_TEST_RIGHT -> {
val i = Intent(applicationContext, TestRightActivity::class.java)
startActivity(i)
}
}
}
}
}
}
private fun startScanningNow() {
val options = ScanOptions()
options.setDesiredBarcodeFormats(ScanOptions.QR_CODE)
options.setPrompt("Scan a barcode")
options.setCameraId(0) // Use a specific camera of the device
// private fun startScanningNow() {
// val options = ScanOptions()
// options.setDesiredBarcodeFormats(ScanOptions.QR_CODE)
// options.setPrompt("Scan a barcode")
// options.setCameraId(0) // Use a specific camera of the device
//
// options.setBeepEnabled(true)
// options.setBarcodeImageEnabled(true)
//
// options.setPrompt("Start Scanning")
// options.setOrientationLocked(false)
//// options.setTimeout(10000) // in ms
//
// barcodeLauncher.launch(options)
// }
//
// private fun checkDataNotNull(): Boolean {
// return if (DataHolder.selectedTest?._id == null) {
// Toast.makeText(
// applicationContext, R.string.select_patient, Toast.LENGTH_SHORT
// ).show()
//
// val i = Intent(applicationContext, DashboardActivity::class.java)
// startActivity(i)
//
// false
// } else {
// true
// }
// }
private fun timeDifference(createdAt: String): Long {
val currentTime = Calendar.getInstance().time
val formatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
options.setBeepEnabled(true)
options.setBarcodeImageEnabled(true)
options.setPrompt("Start Scanning")
options.setOrientationLocked(false)
// options.setTimeout(10000) // in ms
barcodeLauncher.launch(options)
}
private fun checkDataNotNull(): Boolean {
return if (DataHolder.selectedTest?._id == null) {
Toast.makeText(
applicationContext, R.string.select_patient, Toast.LENGTH_SHORT
).show()
val i = Intent(applicationContext, DashboardActivity::class.java)
startActivity(i)
false
val createdAtDate: Date = if (createdAt.isEmpty()) {
currentTime
} else {
true
formatter.parse(createdAt) ?: currentTime
}
val diffMillis = currentTime.time - createdAtDate.time
return diffMillis / (60 * 1000) // Convert milliseconds to minutes
}
}

View File

@@ -18,6 +18,7 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.hardware.usb.UsbManager
import android.location.Location
@@ -30,10 +31,9 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
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.DataHolder
import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.data.model.test.TestType
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.google.android.gms.location.FusedLocationProviderClient
@@ -48,12 +48,12 @@ import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private var myMenu: Menu? = null
private val TAG = "MainActivity"
private lateinit var fusedLocationClient: FusedLocationProviderClient
private lateinit var locationCallback: LocationCallback
private lateinit var sharedPreference: SharedPreferences
private val usbReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent) {
@@ -73,14 +73,28 @@ class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
sharedPreference = getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
val action = intent?.action
if (action == UsbManager.ACTION_USB_DEVICE_ATTACHED || action == UsbManager.ACTION_USB_DEVICE_DETACHED) {
// If the activity is triggered by USB events, simply finish it
checkAndUpdateUsbConnection()
finish()
return
}
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.myToolbar.title = "Test Type"
setSupportActionBar(binding.myToolbar)
if ((sharedPreference.getString(Constants.USER_ID, "").toString() == "ADMIN")) {
binding.cvItem3.visibility = View.VISIBLE
}else{
binding.cvItem3.visibility = View.GONE
}
setupListeners()
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
getLocation()
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
locationResult.lastLocation?.let { location ->
@@ -92,7 +106,6 @@ class MainActivity : AppCompatActivity() {
}
}
}
val usbFilter = IntentFilter().apply {
addAction(UsbManager.ACTION_USB_DEVICE_DETACHED)
addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED)
@@ -111,15 +124,22 @@ class MainActivity : AppCompatActivity() {
}
}
if (DataHolder.selectedTest == null) {
startActivity(Intent(this, DashboardActivity::class.java))
finish()
}
// if (DataHolder.selectedTest == null) {
// startActivity(Intent(this, DashboardActivity::class.java))
// finish()
// }
}
private fun changeUI(){
binding.cvItem1.visibility = View.VISIBLE
binding.cvItem3.visibility = View.VISIBLE
binding.cvItem2.visibility = View.GONE
binding.cvItem4.visibility = View.GONE
}
private fun checkAndUpdateUsbConnection() {
val availableDrivers = UsbSerialProber.getDefaultProber()
.findAllDrivers(getSystemService(Context.USB_SERVICE) as UsbManager)
.toList()
val deviceType = when {
availableDrivers.isNotEmpty() -> {
@@ -130,51 +150,18 @@ class MainActivity : AppCompatActivity() {
Toast.LENGTH_SHORT
).show()
when {
device.productId == Constants.HOMO_CUBE_ID && device.vendorId == Constants.VENDOR_ID -> {
binding.cvItem1.visibility = View.VISIBLE
binding.cvItem3.visibility = View.VISIBLE
binding.cvItem2.visibility = View.GONE
binding.cvItem4.visibility = View.GONE
(device.productId == Constants.HOMO_CUBE_ID && device.vendorId == Constants.VENDOR_ID) || (device.productId == Constants.HEMO_CUBE_V2_PRODUCT_ID && device.vendorId == Constants.HEMO_CUBE_V2_VENDOR_ID) -> {
changeUI()
DataHolder.deviceType.postValue(Constants.DEVICE_TYPE_HEMOCUBE)
Constants.DEVICE_TYPE_HEMOCUBE
}
device.productId == Constants.HEMO_CUBE_V2_PRODUCT_ID && device.vendorId == Constants.HEMO_CUBE_V2_VENDOR_ID -> {
binding.cvItem1.visibility = View.VISIBLE
binding.cvItem3.visibility = View.VISIBLE
binding.cvItem2.visibility = View.GONE
binding.cvItem4.visibility = View.GONE
DataHolder.deviceType.postValue(Constants.DEVICE_TYPE_HEMOCUBE)
Constants.DEVICE_TYPE_HEMOCUBE
}
device.productId == 24577 && device.vendorId == 1027 -> {
binding.cvItem1.visibility = View.VISIBLE
binding.cvItem3.visibility = View.VISIBLE
binding.cvItem2.visibility = View.GONE
binding.cvItem4.visibility = View.GONE
(device.productId == 24577 && device.vendorId == 1027) || (device.productId == 8963 && device.vendorId == 1659) || (device.productId == 4614 && device.vendorId == 7111) -> {
// changeUI()
DataHolder.deviceType.postValue(Constants.DEVICE_TYPE_TRUEHEME)
Constants.DEVICE_TYPE_TRUEHEME
}
device.productId == 8963 && device.vendorId == 1659 -> {
binding.cvItem1.visibility = View.VISIBLE
binding.cvItem3.visibility = View.VISIBLE
binding.cvItem2.visibility = View.GONE
binding.cvItem4.visibility = View.GONE
DataHolder.deviceType.postValue(Constants.DEVICE_TYPE_HEMOCUBE)
Constants.DEVICE_TYPE_HEMOCUBE
}
device.productId == 4614 && device.vendorId == 7111 -> {
binding.cvItem1.visibility = View.VISIBLE
binding.cvItem3.visibility = View.VISIBLE
binding.cvItem2.visibility = View.GONE
binding.cvItem4.visibility = View.GONE
DataHolder.deviceType.postValue(Constants.DEVICE_TYPE_HEMOCUBE)
Constants.DEVICE_TYPE_HEMOCUBE
}
device.productId == Constants.DEVICE_PRODUCT_ID && device.vendorId == Constants.DEVICE_VENDOR_ID -> {
Log.d(
TAG,
@@ -220,6 +207,7 @@ class MainActivity : AppCompatActivity() {
binding.cvItem1.setOnClickListener {
DataHolder.selectedTestType = TestType.SICKLECERT
val i = Intent(applicationContext, KitScanActivity::class.java)
i.putExtra("fromWhere","Main")
startActivity(i)
finish()
}
@@ -227,6 +215,14 @@ class MainActivity : AppCompatActivity() {
binding.cvItem2.setOnClickListener {
DataHolder.selectedTestType = TestType.SICKLEFIND
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)
finish()
}

View File

@@ -14,7 +14,6 @@
package com.example.hpostesting.presentation
import android.Manifest
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
@@ -34,7 +33,6 @@ import com.example.hpostesting.util.MyUtils
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivitySplashBinding
@SuppressLint("CustomSplashScreen")
class SplashActivity : AppCompatActivity() {
private lateinit var binding: ActivitySplashBinding
@@ -66,7 +64,6 @@ class SplashActivity : AppCompatActivity() {
requestPermissions()
}
@SuppressLint("HardwareIds")
private fun setupStaticConstants() {
DataHolder.mobileUniqueId =
Settings.Secure.getString(
@@ -96,7 +93,7 @@ class SplashActivity : AppCompatActivity() {
handlePermissionsResult(true)
} else {
val requestPermissionLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { _ ->
if (Environment.isExternalStorageManager()) {
handlePermissionsResult(true)
} else {

View File

@@ -15,20 +15,17 @@ package com.example.hpostesting.presentation.adapter
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.res.Resources
import android.os.BatteryManager
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.annotation.StringRes
import androidx.navigation.findNavController
import androidx.recyclerview.widget.AsyncListDiffer
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.example.hpostesting.data.constant.DataHolder
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.data.model.patient.UserData
import `in`.sminnovations.hpostesting.R
@@ -38,7 +35,7 @@ import java.util.Calendar
import java.util.Date
import java.util.Locale
class OfflineUserListAdapter(private val view: View, private val batLevel: Int, private val fromWhere:String) :
class OfflineUserListAdapter(private val view: View, private val batLevel: Int,private val fromWhere:String) :
RecyclerView.Adapter<OfflineUserListAdapter.OfflineUserListViewHolder>() {
inner class OfflineUserListViewHolder(val binding: OfflineUserListViewBinding) :
@@ -74,82 +71,96 @@ class OfflineUserListAdapter(private val view: View, private val batLevel: Int,
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: OfflineUserListViewHolder, position: Int) {
val userList = differ.currentList[position]
holder.binding.apply {
userID.text = "User ID: ${userList._id}"
bloodGroup.text = "Blood group: ${userList.bloodGroup}"
time.text = "Time: ${isBetween15And30Minutes(userList.incubationTime)} \n Started at: ${
SimpleDateFormat("HH:mm:ss").format(
SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).parse(userList.incubationTime)!!
)
}"
if (userList.testStatus!!) {
teststatus.text = view.context.getString(R.string.test_concluded)
} else {
teststatus.text = view.context.getString(R.string.test_pending)
}
if(fromWhere == "Home"){
userCard.setOnClickListener {
var batLevel = 50F
batLevel = getBatteryLevel()!!.toFloat()
if (batLevel < Constants.MINIMUM_BATTERY_LEVEL) {
Toast.makeText(
view.context,
view.context.getString(R.string.low_battery_warning),
Toast.LENGTH_SHORT
).show()
return@setOnClickListener
}
if (userList.testStatus != null) {
if (userList.testStatus!!) {
Toast.makeText(
view.context,
view.context.getString(R.string.test_already_conducted),
Toast.LENGTH_SHORT
).show()
} else {
if (userList.incubationTime != "") {
if (isBetween15And30Minutes(userList.incubationTime) < Constants.INCUBATION_TIME_MIN) {
Toast.makeText(
view.context,
view.context.getString(R.string.incubation_not_completed),
Toast.LENGTH_SHORT
).show()
} else
if (isBetween15And30Minutes(userList.incubationTime) > Constants.INCUBATION_TIME_MAX) {
Toast.makeText(
view.context,
view.context.getString(R.string.incubation_crossed_30_minutes),
Toast.LENGTH_SHORT
).show()
} else {
DataHolder.selectedTest = UserData(
sampleid = userList.sampleid,
_id = userList._id,
bloodGroup = userList.bloodGroup,
incubationTime = userList.incubationTime
)
view.findNavController()
.navigate(R.id.action_nav_home_to_mainActivity)
}
} else {
Toast.makeText(
view.context,
view.context.getString(R.string.incubation_not_started),
Toast.LENGTH_SHORT
).show()
}
}
}
}
}
updateHolderBinding(holder, userList)
}
private fun formatTime(incubationTime: String): String {
val formatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
val incubationTimeDate = formatter.parse(incubationTime)!!
val timeFormatter = SimpleDateFormat("HH:mm:ss", Locale.getDefault())
return "Time: ${isBetween15And30Minutes(incubationTime)} \n Started at: ${timeFormatter.format(incubationTimeDate)}"
}
private fun getSampleIdText(userList: HemoCubeTestData): String {
return "Sample ID: ${userList._id}"
}
private fun getBloodGroupText(userList: HemoCubeTestData): String {
return "Blood group: ${userList.bloodGroup}"
}
private fun getTestStatusText(userList: HemoCubeTestData): String {
return if (userList.testStatus!!) {
view.context.getString(R.string.test_concluded)
} else {
view.context.getString(R.string.test_pending)
}
}
private fun updateHolderBinding(holder: OfflineUserListViewHolder, userList: HemoCubeTestData) {
holder.binding.apply {
updateBasicUserInfo(this, userList)
if (fromWhere == "Home") {
setupUserCardClickListener(userCard, userList)
}
}
}
private fun updateBasicUserInfo(binding: OfflineUserListViewBinding, userList: HemoCubeTestData) {
binding.apply {
userID.text = getSampleIdText(userList)
bloodGroup.text = getBloodGroupText(userList)
time.text = formatTime(userList.incubationTime)
teststatus.text = getTestStatusText(userList)
}
}
private fun setupUserCardClickListener(userCard: View, userList: HemoCubeTestData) {
userCard.setOnClickListener {
when {
isLowBattery(userList.batteryLevel) -> showToast(R.string.low_battery_warning)
isTestAlreadyCompleted(userList.testStatus) -> showToast(R.string.test_already_conducted)
else -> handleIncubationCheck(userList)
}
}
}
private fun isLowBattery(batteryLevel: String): Boolean =
batteryLevel < "20"
private fun isTestAlreadyCompleted(testStatus: Boolean?): Boolean =
testStatus == true
private fun handleIncubationCheck(userList: HemoCubeTestData) {
if (userList.incubationTime.isEmpty()) {
showToast(R.string.incubation_not_started)
return
}
val incubationMinutes = isBetween15And30Minutes(userList.incubationTime)
when {
incubationMinutes < Constants.INCUBATION_TIME_MIN ->
showToast(R.string.incubation_not_completed)
incubationMinutes > Constants.INCUBATION_TIME_MAX ->
showToast(R.string.incubation_crossed_30_minutes)
else -> navigateToMainActivity(userList)
}
}
private fun showToast(@StringRes messageResId: Int) {
Toast.makeText(
view.context,
view.context.getString(messageResId),
Toast.LENGTH_SHORT
).show()
}
private fun navigateToMainActivity(userList: HemoCubeTestData) {
DataHolder.selectedTest = UserData(
sampleid = userList.sampleid,
_id = userList._id,
bloodGroup = userList.bloodGroup,
incubationTime = userList.incubationTime
)
view.findNavController().navigate(R.id.action_nav_home_to_mainActivity)
}
private fun isBetween15And30Minutes(createdAt: String): Long {
val formatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
@@ -162,40 +173,19 @@ class OfflineUserListAdapter(private val view: View, private val batLevel: Int,
return diffMillis / (60 * 1000)
}
private fun showWarningToast(resId: Int) {
val contextToUse = view.context ?: return
val message = try {
contextToUse.getString(resId)
} catch (e: Resources.NotFoundException) {
"Resource not found for ID: $resId"
}
Toast.makeText(
contextToUse,
message,
Toast.LENGTH_SHORT
).show()
}
fun getBatteryLevel(): Float? {
val batteryPct: Float? = batteryStatus?.let { intent ->
val level: Int =
intent.getIntExtra(
BatteryManager.EXTRA_LEVEL,
-1
)
val scale: Int =
intent.getIntExtra(
BatteryManager.EXTRA_SCALE,
-1
)
level * 100 / scale.toFloat()
}
return batteryPct
}
private val batteryStatus: Intent? =
IntentFilter(Intent.ACTION_BATTERY_CHANGED).let { ifilter ->
view.context.registerReceiver(null, ifilter)
}
// private fun showWarningToast(resId: Int) {
// val contextToUse = view.context ?: return
//
// val message = try {
// contextToUse.getString(resId)
// } catch (e: Resources.NotFoundException) {
// "Resource not found for ID: $resId"
// }
//
// Toast.makeText(
// contextToUse,
// message,
// Toast.LENGTH_SHORT
// ).show()
// }
}

View File

@@ -33,6 +33,7 @@ import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.firebase.ui.firestore.FirestoreRecyclerAdapter
import com.firebase.ui.firestore.FirestoreRecyclerOptions
import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.firestore.QuerySnapshot
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.UserItemViewBinding
import java.text.SimpleDateFormat
@@ -41,7 +42,6 @@ import java.util.Date
import java.util.Locale
class UserListAdapter(
private val context: Context,
private val hemoCubeViewModel: HemoCubeViewModel,
options: FirestoreRecyclerOptions<UserData>,
@@ -62,212 +62,274 @@ class UserListAdapter(
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: OrderItemViewHolder, position: Int, model: UserData) {
holder.binding.apply {
setupUserInfo(this, model)
setupBloodGroupButton(this, model)
setupTestStatusAndImage(this, model)
setupStartIncubationButton(this)
setupUserCardClickListener(this, model)
}
}
private fun setupUserInfo(binding: UserItemViewBinding, model: UserData) {
binding.apply {
userName.text = "Name: ${model.name}"
userId.text = "User ID:${model._id}"
if (model.incubationTime == "") {
if (model.incubationTime.isEmpty()) {
userId.text = "User ID:${model._id}"
btnBlood.visibility = View.VISIBLE
} else {
userId.text =
"User ID:${model._id} \n Time: ${isBetween15And30Minutes(model.incubationTime)} \n Started at: ${
SimpleDateFormat("HH:mm:ss").format(
SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).parse(model.incubationTime)!!
)
}"
val timeFormatted = SimpleDateFormat("HH:mm:ss").format(
SimpleDateFormat(context.resources.getString(R.string.DateTimeFormat), Locale.getDefault())
.parse(model.incubationTime)!!
)
userId.text = "User ID:${model._id} \n Time: ${isBetween15And30Minutes(model.incubationTime)} \n Started at: $timeFormatted"
btnBlood.visibility = View.GONE
}
}
}
private fun setupTestStatusAndImage(binding: UserItemViewBinding, model: UserData) {
binding.apply {
Glide.with(view).load(model.userImageURL).into(userImage)
if (model.testStatus!!) {
teststatus.text = view.context.getString(R.string.test_concluded)
teststatus.text = if (model.testStatus!!) {
view.context.getString(R.string.test_concluded)
} else {
teststatus.text = view.context.getString(R.string.test_pending)
view.context.getString(R.string.test_pending)
}
}
}
holder.binding.btnBlood.setOnClickListener {
val view: View? = requireActivity.currentFocus
private fun setupBloodGroupButton(binding: UserItemViewBinding, model: UserData) {
binding.btnBlood.setOnClickListener {
hideKeyboard()
showBloodGroupDialog(model, binding)
}
}
// on below line checking if view is not null.
if (view != null) {
// on below line we are creating a variable
// for input manager and initializing it.
val inputMethodManager =
context.getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
private fun hideKeyboard() {
val view: View? = requireActivity.currentFocus
view?.let {
val inputMethodManager =
context.getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
inputMethodManager.hideSoftInputFromWindow(it.windowToken, 0)
}
}
// on below line hiding our keyboard.
inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0)
}
val inflater = LayoutInflater.from(context)
val dialogView = inflater.inflate(R.layout.dialog_custom, null)
private fun showBloodGroupDialog(model: UserData, binding: UserItemViewBinding) {
val dialogView = LayoutInflater.from(context).inflate(R.layout.dialog_custom, null)
val builder = AlertDialog.Builder(context)
.setView(dialogView)
.setTitle(R.string.blood_group)
val builder = AlertDialog.Builder(context)
.setView(dialogView)
.setTitle(R.string.blood_group)
val etBloodGroup = dialogView.findViewById<AutoCompleteTextView>(R.id.et_blood_group)
setupDialogButtons(builder, etBloodGroup, model, binding)
}
val etBloodGroup =
dialogView.findViewById<AutoCompleteTextView>(R.id.et_blood_group)
private fun setupDialogButtons(
builder: AlertDialog.Builder,
etBloodGroup: AutoCompleteTextView,
model: UserData,
binding: UserItemViewBinding
) {
builder.setPositiveButton(R.string.ok) { _, _ ->
handleBloodGroupSelection(etBloodGroup, model, binding)
}
builder.setPositiveButton(R.string.ok) { dialog, which ->
val bloodGroup = etBloodGroup.text.toString()
if (bloodGroup.equals("Select Blood Group") || bloodGroup.equals("ರಕ್ತ ಗುಂಪು ಆಯ್ಕೆಮಾಡಿ") || bloodGroup.isNullOrBlank()) {
if (view != null) {
etBloodGroup.error = view.context.getString(R.string.blood_group_error)
}
if (view != null) {
Toast.makeText(
context,
view.context.getString(R.string.blood_group_toast),
Toast.LENGTH_SHORT
).show()
}
} else {
// Check if hemoCubeViewModel and testDetails are not null
val db: FirebaseFirestore = FirebaseFirestore.getInstance()
builder.setNegativeButton(R.string.cancel) { dialog, _ -> dialog.dismiss() }
builder.create().show()
}
db.collection("patientData")
.whereEqualTo("_id", model._id)
.get()
.addOnSuccessListener { userdata ->
try {
val document = userdata.documents[0]
db.collection("patientData")
.document(document.id)
.update(
"bloodGroup", bloodGroup,
"incubationTime", SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time).toString()
)
.addOnSuccessListener {
if (view != null) {
Toast.makeText(
view.context,
context?.getString(R.string.blood_group_updated_successfully),
Toast.LENGTH_SHORT
).show()
}
btnBlood.visibility = View.GONE
}
.addOnFailureListener { e ->
if (view != null) {
Toast.makeText(
view.context,
context?.getString(R.string.failed_to_update_blood_group),
Toast.LENGTH_SHORT
).show()
}
}
} catch (e: IndexOutOfBoundsException) {
// Handle the case where no documents are found for the specified ID
if (view != null) {
Toast.makeText(
view.context,
context?.getString(R.string.no_user_data_found),
Toast.LENGTH_SHORT
).show()
}
}
private fun handleBloodGroupSelection(
etBloodGroup: AutoCompleteTextView,
model: UserData,
binding: UserItemViewBinding
) {
val bloodGroup = etBloodGroup.text.toString()
if (isInvalidBloodGroup(bloodGroup)) {
showBloodGroupError(etBloodGroup)
return
}
updateBloodGroupInFirestore(bloodGroup, model, binding)
}
}
.addOnFailureListener { e ->
Toast.makeText(
context,
"Error fetching user data: ${e.message}",
Toast.LENGTH_SHORT
).show()
}
}
// Handle the selected blood group here
}
private fun isInvalidBloodGroup(bloodGroup: String): Boolean {
return bloodGroup == "Select Blood Group" ||
bloodGroup == "ರಕ್ತ ಗುಂಪು ಆಯ್ಕೆಮಾಡಿ" ||
bloodGroup.isBlank()
}
builder.setNegativeButton(R.string.cancel) { dialog, which ->
dialog.dismiss()
}
private fun showBloodGroupError(etBloodGroup: AutoCompleteTextView) {
etBloodGroup.error = view.context.getString(R.string.blood_group_error)
Toast.makeText(
context,
view.context.getString(R.string.blood_group_toast),
Toast.LENGTH_SHORT
).show()
}
val alertDialog = builder.create()
alertDialog.show()
private fun updateBloodGroupInFirestore(
bloodGroup: String,
model: UserData,
binding: UserItemViewBinding
) {
val db = FirebaseFirestore.getInstance()
db.collection("patientData")
.whereEqualTo("_id", model._id)
.get()
.addOnSuccessListener { userdata ->
handleFirestoreUpdate(userdata, bloodGroup, binding)
}
.addOnFailureListener { e ->
Toast.makeText(
context,
"Error fetching user data: ${e.message}",
Toast.LENGTH_SHORT
).show()
}
}
btnStartIncubation.setOnClickListener {
// it.visibility = View.GONE
// Firebase.firestore.collection("patientData").whereEqualTo("_id", model._id).get()
// .addOnSuccessListener { data ->
// if (data.documents.isNotEmpty()) {
// data.documents.forEach { userData ->
// Firebase.firestore.collection("patientData").document(userData.id)
// .update(
// "incubationTime", SimpleDateFormat(
// "yyyy-MM-dd HH:mm:ss", Locale.getDefault()
// ).format(Calendar.getInstance().time).toString()
// ).addOnSuccessListener {
// Toast.makeText(
// view.context, "Incubation started", Toast.LENGTH_SHORT
// ).show()
// startListening()
// }
// }
private fun handleFirestoreUpdate(
userdata: QuerySnapshot,
bloodGroup: String,
binding: UserItemViewBinding
) {
try {
val document = userdata.documents[0]
updateDocument(document.id, bloodGroup, binding)
} catch (e: IndexOutOfBoundsException) {
Toast.makeText(
view.context,
context.getString(R.string.no_user_data_found),
Toast.LENGTH_SHORT
).show()
}
}
private fun updateDocument(
documentId: String,
bloodGroup: String,
binding: UserItemViewBinding
) {
FirebaseFirestore.getInstance().collection("patientData")
.document(documentId)
.update(
"bloodGroup", bloodGroup,
"incubationTime", getCurrentTimeFormatted()
)
.addOnSuccessListener {
Toast.makeText(
view.context,
context.getString(R.string.blood_group_updated_successfully),
Toast.LENGTH_SHORT
).show()
binding.btnBlood.visibility = View.GONE
}
.addOnFailureListener {
Toast.makeText(
view.context,
context.getString(R.string.failed_to_update_blood_group),
Toast.LENGTH_SHORT
).show()
}
}
private fun getCurrentTimeFormatted(): String {
return SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
.format(Calendar.getInstance().time)
}
private fun setupStartIncubationButton(binding: UserItemViewBinding) {
// Commented code preserved as per requirement
binding.btnStartIncubation.setOnClickListener {
// it.visibility = View.GONE
// Firebase.firestore.collection("patientData").whereEqualTo("_id", model._id).get()
// .addOnSuccessListener { data ->
// if (data.documents.isNotEmpty()) {
// data.documents.forEach { userData ->
// Firebase.firestore.collection("patientData").document(userData.id)
// .update(
// "incubationTime", SimpleDateFormat(
// "yyyy-MM-dd HH:mm:ss", Locale.getDefault()
// ).format(Calendar.getInstance().time).toString()
// ).addOnSuccessListener {
// Toast.makeText(
// view.context, "Incubation started", Toast.LENGTH_SHORT
// ).show()
// startListening()
// }
// }
// }
}
userCard.setOnClickListener {
if (false) {
Toast.makeText(
view.context,
context?.getString(R.string.low_battery_warning),
Toast.LENGTH_SHORT
).show()
return@setOnClickListener
}
if (model.testStatus != null) {
if (model.testStatus!!) {
Toast.makeText(
view.context,
context?.getString(R.string.test_already_conducted),
Toast.LENGTH_SHORT
).show()
} else {
if (model.incubationTime != "") {
if (isBetween15And30Minutes(model.incubationTime) < -15000) {
Toast.makeText(
view.context,
context?.getString(R.string.incubation_not_completed),
Toast.LENGTH_SHORT
).show()
} else if (isBetween15And30Minutes(model.incubationTime) > 300000) {
Toast.makeText(
view.context,
context?.getString(R.string.incubation_crossed_30_minutes),
Toast.LENGTH_SHORT
).show()
} else {
DataHolder.selectedTest = model
view.findNavController()
.navigate(R.id.action_nav_home_to_mainActivity)
}
} else {
Toast.makeText(
view.context,
context?.getString(R.string.incubation_not_started),
Toast.LENGTH_SHORT
).show()
}
}
// }
}
}
private fun setupUserCardClickListener(binding: UserItemViewBinding, model: UserData) {
binding.userCard.setOnClickListener {
model.testStatus?.let { testStatus ->
if (testStatus) {
showTestAlreadyConductedMessage()
} else {
handleIncubationTimeCheck(model)
}
}
}
}
private fun showTestAlreadyConductedMessage() {
Toast.makeText(
view.context,
context.getString(R.string.test_already_conducted),
Toast.LENGTH_SHORT
).show()
}
private fun handleIncubationTimeCheck(model: UserData) {
if (model.incubationTime.isEmpty()) {
showIncubationNotStartedMessage()
return
}
val incubationTime = isBetween15And30Minutes(model.incubationTime)
when {
incubationTime < -15000 -> showIncubationNotCompletedMessage()
incubationTime > 300000 -> showIncubationCrossedMessage()
else -> navigateToMainActivity(model)
}
}
private fun showIncubationNotStartedMessage() {
Toast.makeText(
view.context,
context.getString(R.string.incubation_not_started),
Toast.LENGTH_SHORT
).show()
}
private fun showIncubationNotCompletedMessage() {
Toast.makeText(
view.context,
context.getString(R.string.incubation_not_completed),
Toast.LENGTH_SHORT
).show()
}
private fun showIncubationCrossedMessage() {
Toast.makeText(
view.context,
context.getString(R.string.incubation_crossed_30_minutes),
Toast.LENGTH_SHORT
).show()
}
private fun navigateToMainActivity(model: UserData) {
DataHolder.selectedTest = model
view.findNavController().navigate(R.id.action_nav_home_to_mainActivity)
}
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

@@ -36,234 +36,277 @@ import `in`.sminnovations.hpostesting.databinding.FragmentAssuranceControlsBindi
import java.time.Instant
class AssuranceControlsFragment : Fragment() {
lateinit var binding: FragmentAssuranceControlsBinding
private val selectConcentration = "Select concentration"
private val selectSolution = "Select solution"
private lateinit var binding: FragmentAssuranceControlsBinding
private lateinit var sharedPreferences: SharedPreferences
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
binding = FragmentAssuranceControlsBinding.inflate(inflater, container, false)
sharedPreferences =
requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
DataHolder.hemoCubeTestData!!.solution = ""
DataHolder.hemoCubeTestData!!.volume = ""
initializeSharedPreferences()
resetTestData()
return binding.root
}
private fun initializeSharedPreferences() {
sharedPreferences = requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
}
private fun resetTestData() {
DataHolder.hemoCubeTestData?.apply {
solution = ""
volume = ""
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initViews()
}
private fun initViews() {
// binding.btnSubmit.visibility = View.GONE
val solutionSpinner: Spinner = binding.spinnerSolutions
val solutionOptions = arrayOf("Select solution", "Tartrazine", "Acid Red","Sickle-Cert-Buffer", "1 Abs Holo Filter", "0.25 Abs Holo Filter", "Air Blank")
val solutionAdapter =
ArrayAdapter(requireContext(), R.layout.simple_spinner_item, solutionOptions)
solutionAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
solutionSpinner.adapter = solutionAdapter
solutionSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long,
) {
val selectedSolution: String = solutionOptions[position]
if (selectedSolution != "Select solution") {
DataHolder.hemoCubeTestData!!.solution = selectedSolution
setupSolutionSpinner()
setupConcentrationSpinner()
setupVolumeSpinner()
setupAdminSpinner()
loadSavedValues()
setupSubmitButton()
}
// Update visibility and name based on selected solution
if(selectedSolution == "Tartrazine" || selectedSolution == "Acid Red"){
activity?.runOnUiThread {
binding.spinnerConcentration.visibility = View.VISIBLE
// Ensure the name is updated only after concentration is selected.
// You might need to adjust this logic based on how and when you want to update the name.
// For now, it simply shows that the visibility is being handled.
}
} else {
activity?.runOnUiThread {
binding.spinnerConcentration.visibility = View.GONE
}
}
} else {
activity?.runOnUiThread {
binding.spinnerConcentration.visibility = View.GONE
}
}
}
override fun onNothingSelected(parent: AdapterView<*>?) {
}
}
val concentrationSpinner: Spinner = binding.spinnerConcentration
val concentrationOptions = arrayOf(
"Select concentration",
"65umol",
"45umol",
"22.5umol",
"12.25umol",
"6.125umol",
"75umol",
"50umol",
"25umol",
"12.5umol",
"6.25umol"
)
val concentrationAdapter =
ArrayAdapter(requireContext(), R.layout.simple_spinner_item, concentrationOptions)
concentrationAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
concentrationSpinner.adapter = concentrationAdapter
concentrationSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long,
) {
val selectedValue: String = concentrationOptions[position]
if (!selectedValue.equals("Select concentration")) {
DataHolder.hemoCubeTestData!!.concentration = selectedValue
}
}
override fun onNothingSelected(parent: AdapterView<*>?) {
}
}
val volumeSpinner: Spinner = binding.spinnerVolume
val volumeOptions = arrayOf("Select volume", "1uml", "2uml", "4uml", "4.5uml", "5uml")
val volumeAdapter =
ArrayAdapter(requireContext(), R.layout.simple_spinner_item, volumeOptions)
volumeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
volumeSpinner.adapter = volumeAdapter
volumeSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long,
) {
val selectedValue: String = volumeOptions[position]
}
override fun onNothingSelected(parent: AdapterView<*>?) {
}
}
val adminspinner: Spinner = binding.spinnerAdmin
val adminOptions = arrayOf("Select options", "Sickle-Cert-Buffer", "1 Abs Holo Filter", "0.25 Abs Holo Filter", "Air Blank")
val adminAdapter =
ArrayAdapter(requireContext(), R.layout.simple_spinner_item, adminOptions)
adminAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
adminspinner.adapter =adminAdapter
adminspinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long,
) {
val selectedValue: String = adminOptions[position]
}
override fun onNothingSelected(parent: AdapterView<*>?) {
}
}
// load saved values
val savedSolution =
sharedPreferences.getString(Constants.QUICK_CAPTURE_SOLUTION, "").toString()
val solutionPosition = getPositionOfValue(savedSolution, solutionOptions.toList())
solutionSpinner.setSelection(solutionPosition)
val savedConcentration =
sharedPreferences.getString(Constants.QUICK_CAPTURE_CONCENTRATION, "").toString()
val concentrationPosition =
getPositionOfValue(savedConcentration, concentrationOptions.toList())
concentrationSpinner.setSelection(concentrationPosition)
val savedVolume = sharedPreferences.getString(Constants.QUICK_CAPTURE_VOLUME, "").toString()
val volumePosition = getPositionOfValue(savedVolume, volumeOptions.toList())
volumeSpinner.setSelection(volumePosition)
val foradmin =
sharedPreferences.getString(Constants.QUICK_CAPTURE_FOR_ADMIN, "").toString()
val adminPosition = getPositionOfValue(foradmin, adminOptions.toList())
adminspinner.setSelection(adminPosition)
binding.btnSubmit.setOnClickListener {
val selectedSolution = binding.spinnerSolutions.selectedItem.toString()
val selectedConcentration = binding.spinnerConcentration.selectedItem.toString()
val selectedadminOption = binding.spinnerAdmin.selectedItem.toString()
// Check if any of the selections are default values
if (selectedSolution == "Select solution") {
Toast.makeText(requireContext(), "Please select a solution", Toast.LENGTH_LONG).show()
return@setOnClickListener // Prevent further execution
}else{
DataHolder.hemoCubeTestData!!.name = selectedSolution
}
if (selectedConcentration == "Select concentration" && binding.spinnerConcentration.isVisible) {
Toast.makeText(requireContext(), "Please select a concentration", Toast.LENGTH_LONG).show()
return@setOnClickListener // Prevent further execution
}else if(binding.spinnerConcentration.isVisible){
DataHolder.hemoCubeTestData!!.name = "$selectedSolution $selectedConcentration"
}else{
DataHolder.hemoCubeTestData!!.name = selectedSolution
}
if (selectedadminOption == "Select options" && binding.spinnerAdmin.isVisible) {
Toast.makeText(requireContext(), "Please select a option", Toast.LENGTH_LONG).show()
return@setOnClickListener // Prevent further execution
}
DataHolder.hemoCubeTestData!!.quickCapture = true
val currentUnixTime = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Instant.now().epochSecond
} else {
""
}
DataHolder.hemoCubeTestData!!._id = currentUnixTime.toString() + "SMI"
DataHolder.hemoCubeTestData!!.solution = binding.spinnerSolutions.selectedItem.toString()
DataHolder.hemoCubeTestData!!.concentration = binding.spinnerConcentration.selectedItem.toString()
DataHolder.hemoCubeTestData!!.filter = binding.spinnerAdmin.selectedItem.toString()
// if(binding.spinnerAdmin.selectedItem.toString().equals("Select options") && binding.spinnerAdmin.isVisible){
// Toast.makeText(requireContext(), "Please select a option", Toast.LENGTH_LONG).show()
// }else {
// DataHolder.hemoCubeTestData!!.name = DataHolder.hemoCubeTestData!!.filter.toString()
// }
DataHolder.selectedTest = UserData()
DataHolder.selectedTest?._id = DataHolder.hemoCubeTestData!!._id
DataHolder.selectedTest?.name = DataHolder.hemoCubeTestData!!.name
with(sharedPreferences.edit()) {
putString(Constants.QUICK_CAPTURE_SOLUTION, DataHolder.hemoCubeTestData!!.solution)
putString(
Constants.QUICK_CAPTURE_CONCENTRATION,
DataHolder.hemoCubeTestData!!.concentration
)
putString(Constants.QUICK_CAPTURE_VOLUME, DataHolder.hemoCubeTestData!!.volume)
putString(Constants.QUICK_CAPTURE_FOR_ADMIN, DataHolder.hemoCubeTestData!!.filter)
apply()
}
val i = Intent(requireContext(), HemocubeActivity::class.java)
startActivity(i)
private fun setupSolutionSpinner() {
val solutionOptions = getSolutionOptions()
val solutionAdapter = createSpinnerAdapter(solutionOptions)
binding.spinnerSolutions.apply {
adapter = solutionAdapter
onItemSelectedListener = createSolutionSelectionListener(solutionOptions)
}
}
private fun getSolutionOptions() = arrayOf(
selectSolution, "Tartrazine", "Acid Red", "Sickle-Cert-Buffer",
"1 Abs Holo Filter", "0.25 Abs Holo Filter", "Air Blank"
)
private fun createSolutionSelectionListener(solutionOptions: Array<String>) =
object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?, view: View?, position: Int, id: Long
) {
handleSolutionSelection(solutionOptions[position])
}
override fun onNothingSelected(parent: AdapterView<*>?) {
//Nothing
}
}
private fun handleSolutionSelection(selectedSolution: String) {
if (selectedSolution != selectSolution) {
DataHolder.hemoCubeTestData?.solution = selectedSolution
updateConcentrationSpinnerVisibility(selectedSolution)
} else {
activity?.runOnUiThread {
binding.spinnerConcentration.visibility = View.GONE
}
}
}
private fun updateConcentrationSpinnerVisibility(selectedSolution: String) {
val shouldShowConcentration = selectedSolution in listOf("Tartrazine", "Acid Red")
activity?.runOnUiThread {
binding.spinnerConcentration.visibility =
if (shouldShowConcentration) View.VISIBLE else View.GONE
}
}
private fun setupConcentrationSpinner() {
val concentrationOptions = getConcentrationOptions()
val concentrationAdapter = createSpinnerAdapter(concentrationOptions)
binding.spinnerConcentration.apply {
adapter = concentrationAdapter
onItemSelectedListener = createConcentrationSelectionListener(concentrationOptions)
}
}
private fun getConcentrationOptions() = arrayOf(
selectConcentration, "65umol", "45umol", "22.5umol", "12.25umol",
"6.125umol", "75umol", "50umol", "25umol", "12.5umol", "6.25umol"
)
private fun createConcentrationSelectionListener(concentrationOptions: Array<String>) =
object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?, view: View?, position: Int, id: Long
) {
val selectedValue = concentrationOptions[position]
if (selectedValue != selectConcentration) {
DataHolder.hemoCubeTestData?.concentration = selectedValue
}
}
override fun onNothingSelected(parent: AdapterView<*>?) {
//Nothing
}
}
private fun setupVolumeSpinner() {
val volumeOptions = getVolumeOptions()
val volumeAdapter = createSpinnerAdapter(volumeOptions)
binding.spinnerVolume.apply {
adapter = volumeAdapter
onItemSelectedListener = createVolumeSelectionListener(volumeOptions)
}
}
private fun getVolumeOptions() =
arrayOf("Select volume", "1uml", "2uml", "4uml", "4.5uml", "5uml")
private fun setupAdminSpinner() {
val adminOptions = getAdminOptions()
val adminAdapter = createSpinnerAdapter(adminOptions)
binding.spinnerAdmin.apply {
adapter = adminAdapter
onItemSelectedListener = createAdminSelectionListener(adminOptions)
}
}
private fun getAdminOptions() = arrayOf(
"Select options", "Sickle-Cert-Buffer", "1 Abs Holo Filter",
"0.25 Abs Holo Filter", "Air Blank"
)
private fun createSpinnerAdapter(options: Array<String>): ArrayAdapter<String> {
return ArrayAdapter(requireContext(), R.layout.simple_spinner_item, options).apply {
setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
}
}
private fun loadSavedValues() {
loadSpinnerValue(Constants.QUICK_CAPTURE_SOLUTION, getSolutionOptions(), binding.spinnerSolutions)
loadSpinnerValue(Constants.QUICK_CAPTURE_CONCENTRATION, getConcentrationOptions(), binding.spinnerConcentration)
loadSpinnerValue(Constants.QUICK_CAPTURE_VOLUME, getVolumeOptions(), binding.spinnerVolume)
loadSpinnerValue(Constants.QUICK_CAPTURE_FOR_ADMIN, getAdminOptions(), binding.spinnerAdmin)
}
private fun loadSpinnerValue(key: String, options: Array<String>, spinner: Spinner) {
val savedValue = sharedPreferences.getString(key, "").toString()
val position = getPositionOfValue(savedValue, options.toList())
spinner.setSelection(position)
}
private fun setupSubmitButton() {
binding.btnSubmit.setOnClickListener {
if (!validateSelections()) return@setOnClickListener
updateTestData()
savePreferences()
navigateToHemocubeActivity()
}
}
private fun validateSelections(): Boolean {
val selectedSolution = binding.spinnerSolutions.selectedItem.toString()
val selectedConcentration = binding.spinnerConcentration.selectedItem.toString()
val selectedAdminOption = binding.spinnerAdmin.selectedItem.toString()
if (selectedSolution == selectSolution) {
showToast("Please select a solution")
return false
}
if (selectedConcentration == selectConcentration && binding.spinnerConcentration.isVisible) {
showToast("Please select a concentration")
return false
}
if (selectedAdminOption == "Select options" && binding.spinnerAdmin.isVisible) {
showToast("Please select a option")
return false
}
return true
}
private fun showToast(message: String) {
Toast.makeText(requireContext(), message, Toast.LENGTH_LONG).show()
}
private fun updateTestData() {
DataHolder.hemoCubeTestData?.apply {
quickCapture = true
_id = generateTestId()
solution = binding.spinnerSolutions.selectedItem.toString()
concentration = binding.spinnerConcentration.selectedItem.toString()
filter = binding.spinnerAdmin.selectedItem.toString()
name = determineTestName()
}
DataHolder.selectedTest = UserData().apply {
_id = DataHolder.hemoCubeTestData?._id.toString()
name = DataHolder.hemoCubeTestData?.name.toString()
}
}
private fun generateTestId(): String {
val currentUnixTime = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Instant.now().epochSecond
} else {
""
}
return "${currentUnixTime}SMI"
}
private fun determineTestName(): String {
val solution = binding.spinnerSolutions.selectedItem.toString()
return if (binding.spinnerConcentration.isVisible) {
"$solution ${binding.spinnerConcentration.selectedItem}"
} else {
solution
}
}
private fun savePreferences() {
with(sharedPreferences.edit()) {
putString(Constants.QUICK_CAPTURE_SOLUTION, DataHolder.hemoCubeTestData?.solution)
putString(Constants.QUICK_CAPTURE_CONCENTRATION, DataHolder.hemoCubeTestData?.concentration)
putString(Constants.QUICK_CAPTURE_VOLUME, DataHolder.hemoCubeTestData?.volume)
putString(Constants.QUICK_CAPTURE_FOR_ADMIN, DataHolder.hemoCubeTestData?.filter)
apply()
}
}
private fun navigateToHemocubeActivity() {
val intent = Intent(requireContext(), HemocubeActivity::class.java)
startActivity(intent)
}
private fun createVolumeSelectionListener(volumeOptions: Array<String>) =
object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?, view: View?, position: Int, id: Long
) {
volumeOptions[position]
}
override fun onNothingSelected(parent: AdapterView<*>?) {
//Nothing
}
}
private fun createAdminSelectionListener(adminOptions: Array<String>) =
object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?, view: View?, position: Int, id: Long
) {
adminOptions[position]
}
override fun onNothingSelected(parent: AdapterView<*>?) {
//Nothing
}
}
fun <T> getPositionOfValue(value: T, data: List<T>?): Int {
data?.let {
for (i in it.indices) {
@@ -272,7 +315,6 @@ class AssuranceControlsFragment : Fragment() {
}
}
}
return 0
}
}

View File

@@ -16,6 +16,7 @@ package com.example.hpostesting.presentation.autodac
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
@@ -36,69 +37,108 @@ import java.util.Calendar
import java.util.Locale
class AutoDacFragment : Fragment() {
private var readClick = false
private var testStatusCode = 0.0
private lateinit var binding: FragmentAutoDacBinding
private val autoDacViewModel: AutoDacViewModel 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?,
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
binding = FragmentAutoDacBinding.inflate(inflater, container, false)
sharedPreferences =
requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
initSharedPreferences()
return binding.root
}
private fun initSharedPreferences() {
sharedPreferences = requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initViews()
observeViewModel()
setupObservers()
}
private fun initViews() {
binding.btnSubmit.visibility = View.GONE
setupInitialViewState()
setupClickListeners()
setupAdminControls()
listenToHemoCube()
getDeviceId()
binding.btnSubmit.setOnClickListener {
binding.btnSubmit.visibility = View.GONE
runAutoDacCommand()
}
binding.btnReadDac.setOnClickListener {
binding.btnReadDac.visibility = View.GONE
readCurrentDACValuesCommand()
}
private fun setupInitialViewState() {
binding.apply {
btnSubmit.visibility = View.GONE
tvSubtitle4.movementMethod = ScrollingMovementMethod()
}
}
private fun observeViewModel() {
autoDacViewModel.deviceData.observe(viewLifecycleOwner) {
currentDeviceData = it
}
messages.observe(viewLifecycleOwner) {
binding.tvSubtitle4.text = it
}
autoDacViewModel.fireBaseUpload.observe(viewLifecycleOwner) { result ->
if (result == "Success") {
showToast("Auto Dac data uploaded successfully")
private fun setupClickListeners() {
binding.apply {
btnSubmit.setOnClickListener {
resultData += "Calibrating the device...\n"
autoDacViewModel.messages.postValue(resultData)
testStatusCode = 0.5
btnSubmit.visibility = View.GONE
sendHemoCubeCommand(HemoCubeCommands.J_COMMAND)
}
if (result == "Local") {
showToast("Auto Dac uploading failed, note it down manually")
btnReadDac.setOnClickListener {
readClick = true
btnReadDac.visibility = View.GONE
sendHemoCubeCommand(HemoCubeCommands.LOAD_DAC_VALUES)
}
}
}
binding.progressBar.visibility = View.GONE
private fun setupAdminControls() {
binding.btnReadDac.visibility =
if (isAdminUser()) View.VISIBLE else View.GONE
}
private fun isAdminUser(): Boolean =
sharedPreferences.getString(Constants.USER_ID, "") == "ADMIN"
private fun setupObservers() {
with(autoDacViewModel) {
deviceData.observe(viewLifecycleOwner) { currentDeviceData = it }
messages.observe(viewLifecycleOwner) { binding.tvSubtitle4.text = it }
fireBaseUpload.observe(viewLifecycleOwner) { handleFirebaseUploadResult(it) }
}
}
private fun handleFirebaseUploadResult(result: String) {
when (result) {
"Success" -> showToast("Auto Dac data uploaded successfully")
"Local" -> showToast("Auto Dac uploading failed, note it down manually")
}
binding.progressBar.visibility = View.GONE
}
private fun sendHemoCubeCommand(
command: HemoCubeCommands,
listener: UsbServiceListener = defaultUsbListener()
) {
autoDacViewModel.progressBar.postValue(true)
(activity as AutoDacActivity).mService.sendAndListenToHemoCube(command, listener)
}
private fun defaultUsbListener() = object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
//Nothing
}
override fun onUsbError(e: Exception?) {
autoDacViewModel.progressBar.postValue(false)
}
}
private fun getDeviceId() {
autoDacViewModel.progressBar.postValue(true)
(activity as AutoDacActivity).mService.sendAndListenToHemoCube(
sendHemoCubeCommand(
HemoCubeCommands.DEVICE_CONFIGURATION_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
@@ -112,138 +152,143 @@ class AutoDacFragment : Fragment() {
override fun onUsbError(e: Exception?) {
autoDacViewModel.progressBar.postValue(false)
}
})
}
private fun runAutoDacCommand() {
autoDacViewModel.progressBar.postValue(true)
(activity as AutoDacActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.AUTO_DAC_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
}
override fun onUsbError(e: Exception?) {
autoDacViewModel.progressBar.postValue(false)
}
})
}
private fun setAutoDacValuesCommand() {
autoDacViewModel.progressBar.postValue(true)
(activity as AutoDacActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.SET_AUTO_DAC_TO_EPROM_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
}
override fun onUsbError(e: Exception?) {
autoDacViewModel.progressBar.postValue(false)
}
})
}
private fun readCurrentDACValuesCommand() {
autoDacViewModel.progressBar.postValue(true)
(activity as AutoDacActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.READ_DAC_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
}
override fun onUsbError(e: Exception?) {
autoDacViewModel.progressBar.postValue(false)
}
})
}
)
}
private fun listenToHemoCube() {
val fullReadOutput = StringBuilder()
startListening.postValue(true)
try {
(activity as AutoDacActivity).mService.listenToHemoCube(object :
UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
data?.let {
val stringData = String(it)
autoDacViewModel.messages.postValue(stringData)
fullReadOutput.append(stringData)
resultData += stringData
binding.tvSubtitle4.text = resultData
if (stringData.contains("SN")) {
val slData = stringData.split(" ")
if (slData.size > 1) {
val hardwareId = slData[1].trim()
// with(sharedPreferences.edit()) {
// putString(Constants.DEVICE_ID, hardwareId)
// apply()
// }
}
activity?.runOnUiThread {
binding.btnSubmit.visibility = View.VISIBLE
}
}
(activity as AutoDacActivity).mService.listenToHemoCube(
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
data?.let { handleHemoCubeData(String(it)) }
}
if (resultData.contains("#CC")) {
setAutoDacValuesCommand()
autoDacViewModel.addAutoDacDataToDb(
DiagnosticsData(
deviceId = sharedPreferences.getString(Constants.DEVICE_ID, "")
.toString(),
devicePassword = sharedPreferences.getString(
Constants.DEVICE_PASSWORD_API,
""
).toString(),
deviceNatsToken = sharedPreferences.getString(
Constants.NATS_TOKEN,
""
).toString(),
accessToken = sharedPreferences.getString(
Constants.ACCESS_TOKEN,
""
).toString(),
deviceData = resultData,
runTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
)
)
activity?.runOnUiThread {
binding.ivCheck.visibility = View.VISIBLE
}
}
if (resultData.contains("#WC")) {
showToast("DAC Values saved to EPROM")
override fun onUsbError(e: Exception?) {
autoDacViewModel.progressBar.postValue(false)
}
}
override fun onUsbError(e: Exception?) {
autoDacViewModel.progressBar.postValue(false)
}
})
)
} catch (e: Exception) {
Firebase.crashlytics.recordException(e)
}
}
fun parseData(inputData: List<String>): List<Pair<String, String>> {
val pattern = Regex("([A-Z]+)\\s(\\d+)")
val parsedData = mutableListOf<Pair<String, String>>()
for (item in inputData) {
val matchResult = pattern.find(item)
if (matchResult != null) {
val (letters, numbers) = matchResult.destructured
parsedData.add(Pair(letters, numbers))
}
private fun handleHemoCubeData(stringData: String) {
resultData += stringData
if (isAdminUser()) {
autoDacViewModel.messages.postValue(resultData)
}
return parsedData
when {
stringData.contains("SN") -> handleSerialNumber(stringData)
resultData.contains("#JC") && testStatusCode < 1.0 -> handleJCommandResponse()
resultData.contains("#DC") && testStatusCode < 1.2 -> handleDCommandResponse()
resultData.contains("#GC") && testStatusCode < 1.6 -> handleGCommandResponse()
resultData.contains("#EC") && testStatusCode < 1.8 -> handleECommandResponse()
resultData.contains("#EC") && readClick && testStatusCode < 2.1 -> handleReadClickResponse()
resultData.contains("#CC") && testStatusCode < 1.4 -> handleCCommandResponse()
resultData.contains("#WC") -> showToast("DAC Values saved to EPROM")
}
}
private fun handleSerialNumber(stringData: String) {
stringData.split(" ").getOrNull(1)?.trim()?.let { _ ->
// Commented as per original code
// saveHardwareId(hardwareId)
}
activity?.runOnUiThread {
binding.btnSubmit.visibility = View.VISIBLE
}
}
private fun handleJCommandResponse() {
testStatusCode = 1.1
sendHemoCubeCommand(HemoCubeCommands.DIAGNOSTICS_COMMAND)
}
private fun handleDCommandResponse() {
testStatusCode = 1.3
if (validateDacValues()) {
val message = if (isAdminUser()) {
resultData += "Calibrating the device, Please wait...\n"
resultData
} else {
"Calibrating the device, Please wait...\n"
}
autoDacViewModel.messages.postValue(message)
sendHemoCubeCommand(HemoCubeCommands.AUTO_DAC_COMMAND)
} else {
handleCalibrationFailure()
}
}
private fun handleCalibrationFailure() {
activity?.runOnUiThread {
val message = if (isAdminUser()) {
resultData += "Calibration failed!\nContact us for help at support@sminnovations.in"
resultData
} else {
"Calibration failed!\nContact us for help at support@sminnovations.in"
}
autoDacViewModel.messages.postValue(message)
binding.btnReadDac.visibility = View.GONE
}
}
private fun handleGCommandResponse() {
testStatusCode = 1.7
sendHemoCubeCommand(HemoCubeCommands.LOAD_DAC_VALUES)
}
private fun handleECommandResponse() {
testStatusCode = 1.9
val message = if (isAdminUser()) {
resultData += "Calibration Completed\n"
resultData
} else {
"Calibration Completed\n"
}
autoDacViewModel.messages.postValue(message)
activity?.runOnUiThread {
showToast("Calibration completed")
binding.ivCheck.visibility = View.VISIBLE
}
}
private fun handleReadClickResponse() {
testStatusCode = 2.2
sendHemoCubeCommand(HemoCubeCommands.READ_DAC_COMMAND)
}
private fun handleCCommandResponse() {
testStatusCode = 1.5
sendHemoCubeCommand(HemoCubeCommands.SET_AUTO_DAC_TO_EPROM_COMMAND)
uploadAutoDacData()
}
private fun uploadAutoDacData() {
autoDacViewModel.addAutoDacDataToDb(
DiagnosticsData(
deviceId = sharedPreferences.getString(Constants.DEVICE_ID, "").toString(),
devicePassword = sharedPreferences.getString(Constants.DEVICE_PASSWORD_API, "").toString(),
deviceNatsToken = sharedPreferences.getString(Constants.NATS_TOKEN, "").toString(),
accessToken = sharedPreferences.getString(Constants.ACCESS_TOKEN, "").toString(),
deviceData = resultData,
runTime = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
.format(Calendar.getInstance().time)
)
)
}
private fun validateDacValues(): Boolean {
val pattern = Regex("(LED:\\d+)__DAC:(\\d+)__ADC:(\\d+)")
return pattern.findAll(resultData).none { match ->
val xValue = match.groupValues[2].toDouble()
val yValue = match.groupValues[3].toDouble()
xValue == 3200.0 && yValue < 500.0
}
}
private fun showToast(message: String) {

View File

@@ -45,7 +45,7 @@ class AutoDacViewModel @Inject constructor(
fun addAutoDacDataToDb(data: DiagnosticsData) {
viewModelScope.launch {
try {
when (val response = repository.addDiagnostics(data)) {
when (repository.addDiagnostics(data)) {
is Response.Success -> {
fireBaseUpload.postValue("Success")
}

View File

@@ -42,7 +42,7 @@ import java.util.UUID
import kotlin.math.log10
class HemoCubeBufferCheckFragment : Fragment() {
private val kitFailed = "Kit Failed"
private lateinit var binding: FragmentHemoCubeReferenceBinding
private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels()
private lateinit var sharedPreferences: SharedPreferences
@@ -178,6 +178,7 @@ class HemoCubeBufferCheckFragment : Fragment() {
}
override fun onUsbError(e: Exception?) {
//nothing
}
})
} catch (e: Exception) {
@@ -402,27 +403,27 @@ class HemoCubeBufferCheckFragment : Fragment() {
}
}
private fun findResult(calculatedRatio: Double?): String {
try {
hemoCubeViewModel.messages.postValue("result classification")
if (calculatedRatio != null) {
if (calculatedRatio < 0.05) return "Inconclusive. Very low Absorbance - Repeat test with Higher Blood Volume"
if (calculatedRatio in 0.05..0.155) return "Normal"
if (calculatedRatio in 0.155..0.175) return "Negative Borderline. Repeat Test"
if (calculatedRatio in 0.175..0.22) return "Sickle Cell Trait"
if (calculatedRatio in 0.22..0.25) return "Positive for Sickle Cell. HPLC for Confirmation"
if (calculatedRatio in 0.25..0.35) return "Sickle Cell Disease"
if (calculatedRatio > 0.35) return "Inconclusive. Repeat with test with lower volume of blood"
} else {
return "INVALID"
}
} catch (e: Exception) {
showToast(R.string.error_classification)
Firebase.crashlytics.recordException(e)
return "ERROR"
}
return "INVALID"
}
// private fun findResult(calculatedRatio: Double?): String {
// try {
// hemoCubeViewModel.messages.postValue("result classification")
// if (calculatedRatio != null) {
// if (calculatedRatio < 0.05) return "Inconclusive. Very low Absorbance - Repeat test with Higher Blood Volume"
// if (calculatedRatio in 0.05..0.155) return "Normal"
// if (calculatedRatio in 0.155..0.175) return "Negative Borderline. Repeat Test"
// if (calculatedRatio in 0.175..0.22) return "Sickle Cell Trait"
// if (calculatedRatio in 0.22..0.25) return "Positive for Sickle Cell. HPLC for Confirmation"
// if (calculatedRatio in 0.25..0.35) return "Sickle Cell Disease"
// if (calculatedRatio > 0.35) return "Inconclusive. Repeat with test with lower volume of blood"
// } else {
// return "INVALID"
// }
// } catch (e: Exception) {
// showToast(R.string.error_classification)
// Firebase.crashlytics.recordException(e)
// return "ERROR"
// }
// return "INVALID"
// }
private fun absorbanceBasedClassification(predictedDenovixRatio: Double?): String {
try {
@@ -430,9 +431,9 @@ class HemoCubeBufferCheckFragment : Fragment() {
if (predictedDenovixRatio != null) {
if (predictedDenovixRatio in 0.0..0.16) return "Kit Passed"
if (predictedDenovixRatio in 0.16..0.165) return "Kit Passed"
if (predictedDenovixRatio in 0.165..0.235) return "Kit Failed"
if (predictedDenovixRatio in 0.235..0.24) return "Kit Failed"
if (predictedDenovixRatio in 0.24..1.0) return "Kit Failed"
if (predictedDenovixRatio in 0.165..0.235) return kitFailed
if (predictedDenovixRatio in 0.235..0.24) return kitFailed
if (predictedDenovixRatio in 0.24..1.0) return kitFailed
} else {
return "INVALID"
}
@@ -460,9 +461,12 @@ class HemoCubeBufferCheckFragment : Fragment() {
(activity as HemocubeBufferCheckActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.START_BUFFER_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {}
override fun onUsbRead(data: ByteArray?) {
//nothing
}
override fun onUsbError(e: Exception?) {
//nothing
}
})
}
@@ -474,9 +478,12 @@ class HemoCubeBufferCheckFragment : Fragment() {
(activity as HemocubeBufferCheckActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.START_SAMPLE,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {}
override fun onUsbRead(data: ByteArray?) {
//nothing
}
override fun onUsbError(e: Exception?) {
//nothing
}
})
}
@@ -504,18 +511,21 @@ class HemoCubeBufferCheckFragment : Fragment() {
(activity as HemocubeBufferCheckActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.PRINT_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {}
override fun onUsbRead(data: ByteArray?) {
//nothing
}
override fun onUsbError(e: Exception?) {
//nothing
}
})
}
private fun calculateRatio(ratio: Double): Double {
val coefficient1 = currentDeviceData?.coefficients?.get(0) ?: 0.0
val coefficient2 = currentDeviceData?.coefficients?.get(1) ?: 1.0
return coefficient1 * ratio + coefficient2
}
//
// private fun calculateRatio(ratio: Double): Double {
// val coefficient1 = currentDeviceData?.coefficients?.get(0) ?: 0.0
// val coefficient2 = currentDeviceData?.coefficients?.get(1) ?: 1.0
// return coefficient1 * ratio + coefficient2
// }
private fun isSerialValid(s: String): Boolean {
if (s.length != 17) {

View File

@@ -75,9 +75,11 @@ class CalibrationFragment : Fragment() {
val etLed1Slope = binding.etLed1Slope
etLed1Slope.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
//nothing
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
//nothing
}
override fun afterTextChanged(s: Editable?) {
@@ -87,9 +89,11 @@ class CalibrationFragment : Fragment() {
val etLed1Intercept = binding.etLed1Intercept
etLed1Intercept.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
//nothing
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
//nothing
}
override fun afterTextChanged(s: Editable?) {
@@ -100,9 +104,11 @@ class CalibrationFragment : Fragment() {
val etLed2Slope = binding.etLed2Slope
etLed2Slope.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
//nothing
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
//nothing
}
override fun afterTextChanged(s: Editable?) {
@@ -112,9 +118,11 @@ class CalibrationFragment : Fragment() {
val etLed2Intercept = binding.etLed2Intercept
etLed2Intercept.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
//nothing
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
//nothing
}
override fun afterTextChanged(s: Editable?) {
@@ -125,9 +133,11 @@ class CalibrationFragment : Fragment() {
val etLed3Slope = binding.etLed3Slope
etLed3Slope.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
//nothing
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
//nothing
}
override fun afterTextChanged(s: Editable?) {
@@ -137,9 +147,11 @@ class CalibrationFragment : Fragment() {
val etLed3Intercept = binding.etLed3Intercept
etLed3Intercept.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
//nothing
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
//nothing
}
override fun afterTextChanged(s: Editable?) {
@@ -150,9 +162,11 @@ class CalibrationFragment : Fragment() {
val etLed4Slope = binding.etLed4Slope
etLed4Slope.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
//nothing
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
//nothing
}
override fun afterTextChanged(s: Editable?) {
@@ -162,9 +176,11 @@ class CalibrationFragment : Fragment() {
val etLed4Intercept = binding.etLed4Intercept
etLed4Intercept.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
//nothing
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
//nothing
}
override fun afterTextChanged(s: Editable?) {

View File

@@ -13,8 +13,6 @@
package com.example.hpostesting.presentation.dashboard
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@@ -34,13 +32,14 @@ class AboutFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// binding.linkClick.setOnClickListener {
// val url = "https://sminnovations.in/"
// val intent = Intent(Intent.ACTION_VIEW)
// intent.data = Uri.parse(url)
// startActivity(intent)
// }
}
}

View File

@@ -25,6 +25,10 @@ import androidx.fragment.app.activityViewModels
import com.example.hpostesting.presentation.adapter.OfflineUserListAdapter
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import `in`.sminnovations.hpostesting.databinding.FragmentActivitiesBinding
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import java.util.Locale
class ActivitiesFragment : Fragment() {
private lateinit var binding: FragmentActivitiesBinding
@@ -45,6 +49,12 @@ class ActivitiesFragment : Fragment() {
hemoCubeViewModel.allPendingUserToUpload.observe(viewLifecycleOwner) { userData ->
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.noDataText.visibility = View.GONE
val bm =
@@ -60,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

@@ -23,7 +23,6 @@ import android.os.Build
import android.os.Bundle
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.FileProvider
@@ -33,27 +32,28 @@ import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.navigateUp
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import com.example.hpostesting.util.Result
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.data.model.login.LoginRequest
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.jig.JigActivity
import com.example.hpostesting.presentation.utils.NatsManager
import com.google.android.material.navigation.NavigationView
import com.google.firebase.appdistribution.FirebaseAppDistribution
import com.google.firebase.appdistribution.FirebaseAppDistributionException
import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.google.firebase.ktx.Firebase
import com.google.firebase.remoteconfig.FirebaseRemoteConfig
import com.google.firebase.remoteconfig.ktx.remoteConfig
import com.google.firebase.remoteconfig.ktx.remoteConfigSettings
import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.BuildConfig
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityDashboardBinding
import java.io.File
import java.security.MessageDigest
import javax.inject.Inject
interface NatsMessageCallback {
fun interface NatsMessageCallback {
fun onMessageReceived(topic: String, message: String)
}
@@ -64,7 +64,9 @@ open interface IDataCollector: NatsMessageCallback {
@AndroidEntryPoint
class DashboardActivity : AppCompatActivity(), IDataCollector {
@Inject
lateinit var databaseRepository: DatabaseRepository
private val remoteConfig: FirebaseRemoteConfig = Firebase.remoteConfig
val TAG = "DashboardActivity"
private var isRegistered = false
private lateinit var appBarConfiguration: AppBarConfiguration
@@ -72,16 +74,17 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
lateinit var sharedPreferences: SharedPreferences
var responses: String = ""
lateinit var nats: NatsManager
private var downloadId: Long = 0
// TODO: Remove hemocube viewmodel
private val hemocubeViewModel: HemoCubeViewModel by viewModels()
private lateinit var sharedPreference: SharedPreferences
override fun attachBaseContext(newBase: Context?) {
val languageCode = LanguageManager.getSavedLanguage(newBase!!)
LanguageManager.setLocale(newBase, languageCode)
super.attachBaseContext(newBase)
}
override fun onMessageReceived(topic: String, message: String) {
// Handle incoming messages from NATS
@@ -91,16 +94,24 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
@SuppressLint("SetWorldReadable")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val firebaseManager = FirebaseManager(this)
binding = ActivityDashboardBinding.inflate(layoutInflater)
sharedPreferences = this.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
setContentView(binding.root)
setSupportActionBar(binding.appBarDashboard.toolbar)
nats = NatsManager(this)
val currentServer = firebaseManager.getLastSelectedServer().serverName
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
nats.connect()
}
val versionName = getAppVersion(this@DashboardActivity) + " [ " + getAppEnvironment(this@DashboardActivity) + " ]"
val savedKitSerial = sharedPreferences.getString(Constants.KIT_NUMBER, "")
Log.d("DashboardActivity", "Saved Kit Serial: $savedKitSerial")
// Toast.makeText(this, "Saved Kit Serial: $savedKitSerial", Toast.LENGTH_SHORT).show()
val versionName = getAppVersion(this@DashboardActivity) + " [ " + getAppEnvironment(this@DashboardActivity) +"->"+currentServer+"]"
binding.appBarDashboard.versionName.text = versionName
@@ -109,12 +120,99 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
nats.sub("server.hpos.${deviceId}.ping")
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) {
Log.d("DashboardLogs",it.toString())
var apk = it
val file = File(getExternalFilesDir("Downloads"), "update.apk")
file.setReadable(true, false)
val isReadable = file.setReadable(true, false)
if (!isReadable) {
Log.w(TAG, "Failed to set file readable")
}
// Write APK to file
apk.byteStream().use { input ->
@@ -122,8 +220,8 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
input.copyTo(output)
}
}
}
hemocubeViewModel.deviceUpdateheader.observe(this){
val apkFile = File(getExternalFilesDir("Downloads"), "update.apk")
val expectedChecksum = it.get("Checksum") // Provide your expected checksum here
@@ -158,6 +256,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 {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.dashboard, menu)
@@ -188,7 +292,7 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
return actualChecksum.equals(expectedChecksum, ignoreCase = true)
}
private fun installApk(file: File) {
val pInfo = baseContext.packageManager.getPackageInfo(baseContext.packageName, 0)
baseContext.packageManager.getPackageInfo(baseContext.packageName, 0)
val uri: Uri = FileProvider.getUriForFile(
this,
"${BuildConfig.APPLICATION_ID}.fileprovider",
@@ -223,41 +327,41 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
override fun onResume() {
super.onResume()
val firebaseAppDistribution = FirebaseAppDistribution.getInstance()
firebaseAppDistribution.updateIfNewReleaseAvailable()
.addOnProgressListener { updateProgress ->
if (updateProgress.apkBytesDownloaded > 0) {
Toast.makeText(
this,
"${updateProgress.updateStatus}. ${updateProgress.apkBytesDownloaded / 1048576} /${updateProgress.apkFileTotalBytes / 1048576} MB",
Toast.LENGTH_SHORT
).show()
}
}
.addOnFailureListener { e ->
// (Optional) Handle errors.
if (e is FirebaseAppDistributionException) {
when (e.errorCode) {
FirebaseAppDistributionException.Status.NOT_IMPLEMENTED -> {
// SDK did nothing. This is expected when building for Play.
}
else -> {
// Handle other errors.
Toast.makeText(
this,
"AppDistribution error, status: ${e.errorCode}",
Toast.LENGTH_SHORT
).show()
}
}
FirebaseCrashlytics.getInstance().recordException(e)
}
}
.addOnSuccessListener {
// Toast.makeText(this, "App Update: Success!", Toast.LENGTH_SHORT).show()
}
// val firebaseAppDistribution = FirebaseAppDistribution.getInstance()
// firebaseAppDistribution.updateIfNewReleaseAvailable()
// .addOnProgressListener { updateProgress ->
//
// if (updateProgress.apkBytesDownloaded > 0) {
// Toast.makeText(
// this,
// "${updateProgress.updateStatus}. ${updateProgress.apkBytesDownloaded / 1048576} /${updateProgress.apkFileTotalBytes / 1048576} MB",
// Toast.LENGTH_SHORT
// ).show()
// }
// }
// .addOnFailureListener { e ->
// // (Optional) Handle errors.
// if (e is FirebaseAppDistributionException) {
// when (e.errorCode) {
// FirebaseAppDistributionException.Status.NOT_IMPLEMENTED -> {
// // SDK did nothing. This is expected when building for Play.
// }
//
// else -> {
// // Handle other errors.
// Toast.makeText(
// this,
// "AppDistribution error, status: ${e.errorCode}",
// Toast.LENGTH_SHORT
// ).show()
// }
// }
// FirebaseCrashlytics.getInstance().recordException(e)
// }
// }
// .addOnSuccessListener {
//// Toast.makeText(this, "App Update: Success!", Toast.LENGTH_SHORT).show()
// }
}
override fun setConnect(connect: Boolean) {
@@ -274,15 +378,16 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
// }
}
private fun createDeviceUpdateRequestData(): DeviceUpdateRequest {
return DeviceUpdateRequest(
serial_no = sharedPreference.getString(Constants.DEVICE_ID, "")
)
}
// private fun createDeviceUpdateRequestData(): DeviceUpdateRequest {
// return DeviceUpdateRequest(
// serial_no = sharedPreferences.getString(Constants.DEVICE_ID, "")
// )
// }
private fun getAppVersion(context: Context): String {
return try {
val pInfo = context.packageManager.getPackageInfo(context.packageName, 0)
pInfo.versionName
} catch (e: PackageManager.NameNotFoundException) {
"N/A"
}

View File

@@ -28,6 +28,7 @@ import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.presentation.autodac.AutoDacActivity
import com.example.hpostesting.presentation.buffercheck.HemocubeBufferCheckActivity
import com.example.hpostesting.presentation.calibration.CalibrationActivity
import com.example.hpostesting.presentation.dashboard.ui.PasswordResetActivity
import com.example.hpostesting.presentation.deviceinfo.DeviceActivity
import com.example.hpostesting.presentation.deviceprovision.DeviceProvisionActivity
import com.example.hpostesting.presentation.diagnostics.DiagnosticsActivity
@@ -86,9 +87,12 @@ class GalleryFragment : Fragment() {
binding.btnUsbTerminal.visibility = View.VISIBLE
binding.btnSubmit.visibility = View.VISIBLE
binding.btnDeviceInfo.visibility = View.VISIBLE
binding.btnResetPassword.visibility = View.VISIBLE
binding.btnUpdateValues.visibility = View.VISIBLE
}else{
binding.btnResetPassword.visibility = View.GONE
binding.btnDeviceProvision.visibility = View.GONE
binding.btnAutoDac.visibility = View.GONE
binding.btnAutoDac.visibility = View.VISIBLE
binding.btnDeviceProvision.visibility = View.GONE
binding.btnDiagnostics.visibility = View.VISIBLE
binding.btnFiles.visibility = View.GONE
@@ -97,14 +101,22 @@ class GalleryFragment : Fragment() {
binding.btnUsbTerminal.visibility = View.GONE
binding.btnSubmit.visibility = View.GONE
binding.btnDeviceInfo.visibility = View.VISIBLE
binding.btnUpdateValues.visibility = View.GONE
}
binding.btnResetPassword.setOnClickListener{
startActivity(Intent(requireContext(), PasswordResetActivity::class.java))
}
binding.btnDeviceProvision.setOnClickListener {
startActivity(Intent(requireContext(), DeviceProvisionActivity::class.java))
}
binding.btnUpdateValues.setOnClickListener {
startActivity(Intent(requireContext(), UpdateValuesActivity::class.java))
}
binding.btnUsbTerminal.setOnClickListener {
startActivity(Intent(requireContext(), UsbTerminalActivity::class.java))
}
binding.btnSubmit.setOnClickListener {
startActivity(Intent(requireContext(), HemocubeBufferCheckActivity::class.java))
}

View File

@@ -13,6 +13,7 @@
package com.example.hpostesting.presentation.dashboard
import android.app.AlertDialog
import android.content.Context
import android.content.SharedPreferences
import android.content.pm.PackageManager
@@ -20,8 +21,10 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.preference.ListPreference
import androidx.preference.Preference
@@ -29,94 +32,231 @@ import androidx.preference.PreferenceFragmentCompat
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.data.model.TestState
import com.example.hpostesting.data.model.patient.toHemoCubeTestData
import com.example.hpostesting.data.repository.DatabaseRepository
import com.example.hpostesting.firebase.FirebaseConfig
import com.example.hpostesting.firebase.FirebaseManager
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentHemoCubeReferenceBinding
import `in`.sminnovations.hpostesting.databinding.FragmentSlideshowBinding
private var isLanguageChanged = false
class SlideshowFragment : Fragment(){
class SlideshowFragment : Fragment() {
private var selectedItem = "10mm"
private val values = arrayOf("10mm", "2mm")
private lateinit var binding: FragmentSlideshowBinding
private lateinit var sharedPreferences: SharedPreferences
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
): View {
binding = FragmentSlideshowBinding.inflate(inflater, container, false)
sharedPreferences =
requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
sharedPreferences = requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.nameEditText.setText(sharedPreferences.getString(Constants.LABNAME,""))
binding.nameEditText.setText(sharedPreferences.getString(Constants.LABNAME, ""))
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 {
var labname = binding.nameEditText.text.toString()
DataHolder.hemoCubeTestData?.apply {
this.labName = labname
}
with(sharedPreferences.edit()) {
putString(Constants.LABNAME, labname)
apply()
}
Toast.makeText(
requireContext(),
"Lab Name is Added successfully.",
Toast.LENGTH_SHORT
requireContext(), "Lab Name is Added successfully.", Toast.LENGTH_SHORT
).show()
}
childFragmentManager.beginTransaction().replace(binding.container.id,PrefsFragment()).commit()
val adapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, values)
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
val pos: Int
if (selectedItem == "10mm") {
pos = 0
} else {
pos = 1
}
binding.spinnerCuvette.adapter = adapter
binding.spinnerCuvette.onItemSelectedListener =
object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?, view: View?, position: Int, id: Long
) {
// Handle item selection here
selectedItem = values[position]
}
override fun onNothingSelected(parent: AdapterView<*>?) {
// Do nothing here
}
}
binding.spinnerCuvette.setSelection(pos)
binding.btnAddSize.setOnClickListener {
with(sharedPreferences.edit()) {
putString(Constants.CUVETTE_SIZE, selectedItem)
apply()
}
Toast.makeText(
requireContext(), "Selected cuvette size: $selectedItem", Toast.LENGTH_SHORT
).show()
}
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?) {
firebaseManager = FirebaseManager(requireContext())
databaseRepository = (activity as DashboardActivity).databaseRepository
tapManager = AppVersionTapManager()
val sharedPreference =
requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
val preferenceScreen = preferenceManager.createPreferenceScreen(requireContext())
val currentServer = firebaseManager.getLastSelectedServer().serverName
val languagePreference = ListPreference(requireContext())
languagePreference.key = "language_preference"
languagePreference.title = getString(R.string.app_language)
languagePreference.summary = getString(R.string.select_language)
languagePreference.entries = arrayOf("English", "Kannada", "Hindi")
languagePreference.entryValues = arrayOf("en", "kn", "hi")
languagePreference.setDefaultValue("en")
// Language Preference
val languagePreference = ListPreference(requireContext()).apply {
key = "language_preference"
title = getString(R.string.app_language)
summary = getString(R.string.select_language)
entries = arrayOf("English", "Kannada", "Hindi")
entryValues = arrayOf("en", "kn", "hi")
setDefaultValue("en")
icon = ContextCompat.getDrawable(requireContext(), R.drawable.baseline_translate_24)
languagePreference.onPreferenceChangeListener =
Preference.OnPreferenceChangeListener { _, newValue ->
onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->
val languageCode = newValue as String
updateLanguage(requireContext(), languageCode)
true
}
}
preferenceScreen.addPreference(languagePreference)
setPreferenceScreen(preferenceScreen)
// App Version Preference
val appVersionPreference = Preference(requireContext())
appVersionPreference.title = "App Version"
appVersionPreference.summary =
getAppVersion(requireContext()) + " [ " + getAppEnvironment(requireContext()) + " ]"
val appVersionPreference = Preference(requireContext()).apply {
title = "App Version"
summary =
getAppVersion(requireContext()) + " [ " + getAppEnvironment(requireContext()) +"->"+currentServer+"]"
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 {
//nothing
}
true
}
}
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)
if (isLanguageChanged) {
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) {
LanguageManager.persistLanguagePreference(context, languageCode)
LanguageManager.setLocale(context, languageCode)
requireActivity().recreate() // Recreate activity to apply language changes
requireActivity().recreate()
isLanguageChanged = true
}
private fun getAppVersion(context: Context): String {
return try {
val pInfo = context.packageManager.getPackageInfo(context.packageName, 0)
@@ -134,4 +274,6 @@ class PrefsFragment: PreferenceFragmentCompat(){
"N/A"
}
}
}
}

View File

@@ -0,0 +1,50 @@
/*
* // 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.dashboard
import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.example.hpostesting.data.constant.Constants
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityDashboardBinding
import `in`.sminnovations.hpostesting.databinding.ActivityUpdateValuesBinding
class UpdateValuesActivity : AppCompatActivity() {
private lateinit var binding: ActivityUpdateValuesBinding
lateinit var sharedPreferences: SharedPreferences
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityUpdateValuesBinding.inflate(layoutInflater)
sharedPreferences = this.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
setContentView(binding.root)
binding.btnSubmit.setOnClickListener {
saveStringToPreferences(Constants.ABS2LED1MMLL, binding.et2mmled1Ll.text.toString())
saveStringToPreferences(Constants.ABS2LED1MMUL, binding.et2mmled1Ul.text.toString())
saveStringToPreferences(Constants.ABS2LED2MMLL, binding.et2mmled2Ll.text.toString())
saveStringToPreferences(Constants.ABS2LED2MMUL, binding.et2mmled2Ul.text.toString())
saveStringToPreferences(Constants.ABS10LED1MMLL, binding.et10mmled1Ll.text.toString())
saveStringToPreferences(Constants.ABS10LED1MMUL, binding.et10mmled1Ul.text.toString())
saveStringToPreferences(Constants.ABS10LED2MMLL, binding.et10mmled2Ll.text.toString())
saveStringToPreferences(Constants.ABS10LED2MMUL, binding.et10mmled2Ul.text.toString())
}
}
private fun saveStringToPreferences(key: String, value: String) {
sharedPreferences.edit().putString(key, value).apply()
}
}

View File

@@ -13,46 +13,38 @@
package com.example.hpostesting.presentation.dashboard.ui
import android.annotation.SuppressLint
import android.accounts.Account
import android.accounts.AccountManager
import android.content.Context
import android.content.SharedPreferences
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.model.login.LoginRequest
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.example.hpostesting.util.AppInitializer
import com.example.hpostesting.util.SecureStorage
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentLoginBinding
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.net.HttpURLConnection
import java.net.URL
import java.util.Scanner
class LoginFragment : Fragment() {
private val LOCATION_PERMISSION_REQUEST_CODE = 1001
// private lateinit var locationManager: LocationManager
// var latitude = 0.0
// var longitude = 0.0
var latitude = 0.0
var longitude = 0.0
private lateinit var accountManager: AccountManager
private lateinit var secureStorage: SecureStorage
var TAG = "LoginFragmentCheck"
private var _binding: FragmentLoginBinding? = null
private val binding get() = _binding!!
private lateinit var sharedPreference: SharedPreferences
private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?,
@@ -60,6 +52,11 @@ class LoginFragment : Fragment() {
_binding = FragmentLoginBinding.inflate(inflater, container, false)
sharedPreference =
requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
accountManager = AccountManager.get(requireActivity())
secureStorage = SecureStorage(requireActivity())
// Initialize user roles and credentials if not already done
AppInitializer.initialize(requireActivity())
return binding.root
}
@@ -67,107 +64,132 @@ class LoginFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
init()
if(isInternetAvailable()){
getPublicIpAddr { ipAddress ->
DataHolder.ipAddress = ipAddress
}
Log.d("ipaddress",DataHolder.ipAddress)
}
// getPublicIpAddr { ipAddress ->
// DataHolder.ipAddress = ipAddress
// }
// locationManager = requireActivity().getSystemService(Context.LOCATION_SERVICE) as LocationManager
// // Check for location permission
// if (ContextCompat.checkSelfPermission(requireContext(),
// Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(requireContext(),
// Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// // Permission is not granted, request it
// ActivityCompat.requestPermissions(requireActivity(),
// arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION,Manifest.permission.ACCESS_FINE_LOCATION),
// LOCATION_PERMISSION_REQUEST_CODE)
// } else {
// // Permission is granted, fetch location
// checkLocation()
// }
//
// if (isNetworkProviderAvailable()) {
// Toast.makeText(requireContext(), "Network provider is available", Toast.LENGTH_SHORT).show()
// } else {
// Toast.makeText(requireContext(), "Network provider is not available", Toast.LENGTH_SHORT).show()
// if(isInternetAvailable()){
// getPublicIpAddr { ipAddress ->
// DataHolder.ipAddress = ipAddress
// }
// Log.d("ipaddress",DataHolder.ipAddress)
// }
setupAutoCompleteTextView()
//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)
// private fun isNetworkProviderAvailable(): Boolean {
//
// return locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
// }
// 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() {
if (isUserLoggedIn()) {
navigateToHomeFragment()
return
}
binding.btnLogin.setOnClickListener {
// Toast.makeText(requireContext(), "$latitude/$longitude",Toast.LENGTH_SHORT).show()
val loginId = binding.loginId.text.toString()
val password = binding.password.text.toString()
val loginId = binding.loginId.text.toString().trim()
val password = binding.password.text.toString().trim()
if (loginId.isNotBlank() && password.isNotBlank()) {
performLogin(loginId, password)
var Password = sharedPreference.getString(Constants.DEVICE_PASSWORD_API, "").toString()
var UserID = sharedPreference.getString(Constants.DEVICE_ID_API, "").toString()
hemoCubeViewModel.login(createLoginRequestData(UserID, Password))
} else {
if (loginId.isBlank()) {
binding.loginId.error = R.string.enter_proper_login_id.toString()
Log.d("LoginFragment","enter proper login id")
}
if (password.isBlank()) {
binding.password.error = R.string.enter_proper_password.toString()
Log.d("LoginFragment","enter proper password")
}
}
}
}
private fun createLoginRequestData(userID: String, password: String): LoginRequest {
val pInfo = requireActivity().packageManager.getPackageInfo(
requireActivity().packageName, 0
)
val version = pInfo.versionName
var labname = sharedPreference.getString(Constants.LABNAME,"")
return LoginRequest(
password = password, serialNumber = userID, username = userID, version = version, lab = labname,location = DataHolder.ipAddress.toString()
)
}
private fun isUserLoggedIn(): Boolean {
return sharedPreference.getString(Constants.USER_ID, "")?.isNotBlank() == true
}
private fun navigateToHomeFragment() {
Log.d("LoginFragment","Login Successful")
findNavController().navigate(R.id.action_loginFragment_to_homeFragment)
}
private fun performLogin(loginId: String, password: String) {
val matchingId = Constants.STATICID.firstOrNull { it == loginId }
if (matchingId != null) {
if (password == Constants.password) {
saveUserId(loginId)
navigateToHomeFragment()
return
} else {
Toast.makeText(requireContext(), R.string.wrong_password, Toast.LENGTH_SHORT).show()
}
if (validateCredentials(loginId, password)) {
addAccount(loginId, password)
val role = getRoleForUser(loginId)
saveUserId(role)
navigateToHomeFragment()
return
} else {
Toast.makeText(requireActivity(), "Invalid credentials", Toast.LENGTH_SHORT).show()
}
Toast.makeText(requireContext(), R.string.wrong_user_id, Toast.LENGTH_SHORT).show()
// val matchingId = Constants.STATICID.firstOrNull { it == loginId }
// if (matchingId != null) {
// if (password == Constants.password) {
// saveUserId(loginId)
// navigateToHomeFragment()
// return
// } else {
// Log.d("LoginFragment","wrong password")
// Toast.makeText(requireContext(), R.string.wrong_password, Toast.LENGTH_SHORT).show()
// }
// }
// Log.d("LoginFragment","wrong password")
// Toast.makeText(requireContext(), R.string.wrong_user_id, Toast.LENGTH_SHORT).show()
}
private fun getRoleForUser(username: String): String {
// Replace this with your actual logic to determine the role for the user
return when (username) {
"FACTORY" -> "FACTORY"
"ADMIN" -> "ADMIN"
"PQUSER" -> "PQUSER"
"QCUSER" -> "QCUSER"
else -> "HPOSUSER"
}
}
private fun validateCredentials(username: String, password: String): Boolean {
var storedPassword = secureStorage.getPassword()
// if (!checkUserName(binding.etName.text.toString())) {
// binding.etName.error = "Name field can't be empty or less than 3 characters"
// return false
// }
if (!checkCenterName(binding.centerName.text.toString())) {
binding.centerName.error = "Center name can't be empty or less than 3 characters"
return false
}
if(username == "ADMIN"){
storedPassword = secureStorage.getAdminPassword()
}
return storedPassword != null &&
password == storedPassword &&
(username == "HPOSUSER" || username == "ADMIN" || username == "FACTORY" || username == "PQUSER" || username == "QCUSER")
}
private fun addAccount(username: String, password: String) {
val account = Account(username, "com.example.account")
accountManager.addAccountExplicitly(account, password, null)
}
private fun saveUserId(userId: String) {
with(sharedPreference.edit()) {
putString(Constants.USER_ID, userId)
apply()
}
DataHolder.centerName = binding.centerName.text.toString()
DataHolder.district = binding.etDistrict.text.toString()
with(sharedPreference.edit()) {
putString(Constants.CENTER_NAME, binding.centerName.text.toString().lowercase().trim())
putString(Constants.DISTRICT, binding.etDistrict.text.toString())
apply()
}
}
override fun onDestroyView() {
@@ -176,54 +198,53 @@ class LoginFragment : Fragment() {
}
/** Check if we can get our location */
// @SuppressLint("MissingPermission")
// @SuppressLint("MissingPermission")
// fun checkLocation() {
//
// // Get the location manager
// val locationManager = requireActivity().getSystemService(Context.LOCATION_SERVICE) as LocationManager
// val locationProviderWifi = LocationManager.NETWORK_PROVIDER
// val locationProviderGPS = LocationManager.FUSED_PROVIDER
// val locationProviderGPS = LocationManager.GPS_PROVIDER
// val locationListenerNetwork: LocationListener
// val locationListenerGPS: LocationListener
// var gps_enabled = false
// var network_enabled = false
// Log.d(TAG,"PRoveider"+locationManager.allProviders.toString())
// //check wifi
//
// //check wifi
// val connectivityManager = requireActivity().getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
// val mWifi = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI)
//
// if (mWifi!!.isConnected) {
// Log.d(TAG, "Wifi connected")
// }
//
// //check gps and wifi availability
//
// //check gps and wifi availability
// try {
// gps_enabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
// } catch (ex: java.lang.Exception) {
// } catch (ex: Exception) {
// //nothing
// }
//
// try {
// network_enabled =
// locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
// } catch (ex: java.lang.Exception) {
// network_enabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
// } catch (ex: Exception) {
// //nothing
// }
//
// if (!gps_enabled) {
// Log.d(TAG, "GPS: Missing")
// }else{
//// getPublicIpAddr { ipAddress ->
//// // Do something with the ipAddress
//// Log.d(TAG, "GPS: PRESENT"+ipAddress)
//// }
// }
// if (!network_enabled) {
// Log.d(TAG, "Network: Missing")
// }
//
// /* Location change listeners */
//
// /* Location change listeners */try {
// Log.d(TAG, "GPS: PRESENT TRy")
// // Define a listener that responds to gps location updates
// locationListenerGPS = object : LocationListener {
// override fun onLocationChanged(location: Location) {
// Log.d(TAG, "GPS: PRESENT loc")
// Log.d(
// TAG,
// "GPS: Latitude: " + location.latitude + ", Longitude = " + location.longitude
@@ -231,27 +252,22 @@ class LoginFragment : Fragment() {
// }
//
// override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {
// Log.d(TAG, "GPS location found 1")
// Log.d(TAG, "GP location found 1")
// }
//
// override fun onProviderEnabled(provider: String) {
// Log.d(TAG, "GPS location found 2")
// Log.d(TAG, "GP location found 2")
// }
//
// override fun onProviderDisabled(provider: String) {
// Log.d(TAG, "GPS location found 3")
// Log.d(TAG, "GP location found 3")
// }
// }
// locationManager.requestLocationUpdates(
// locationProviderGPS,
// 0,
// 0f,
// locationListenerGPS
// )
// } catch (e: java.lang.Exception) {
// Log.e(TAG, "Location Exception GPS: " + e.message)
// locationManager.requestLocationUpdates(locationProviderGPS, 0, 0f, locationListenerGPS)
// Log.d(TAG, "GPS: PRESENT Req")
// } catch (e: Exception) {
// Log.e(TAG, "Location Exception: " + e.message)
// }
//
// try {
// // Define a listener that responds to wifi location updates
// locationListenerNetwork = object : LocationListener {
@@ -280,52 +296,66 @@ class LoginFragment : Fragment() {
// 0f,
// locationListenerNetwork
// )
// } catch (e: java.lang.Exception) {
// Log.e(TAG, "Location Exception: " + e.message)
// } catch (e: Exception) {
// Log.e(TAG, "NW Location Exception: " + e.message)
// }
//
// }
// override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
// super.onRequestPermissionsResult(requestCode, permissions, grantResults)
// if (requestCode == LOCATION_PERMISSION_REQUEST_CODE) {
// if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// // Permission granted, fetch location
// checkLocation()
// } else {
// // Permission denied
// Toast.makeText(requireContext(), "Location permission denied", Toast.LENGTH_SHORT).show()
// fun getPublicIpAddr(callback: (String) -> Unit) {
// 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()
// callback(ipAddress)
// }
// }
// } finally {
// conn.disconnect()
// }
// }
// }
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()
callback(ipAddress)
}
}
} finally {
conn.disconnect()
}
}
}catch (e: Exception){
Log.e(TAG,e.toString())
}
}
@SuppressLint("NewApi")
private fun isInternetAvailable(): Boolean {
val connectivityManager = requireActivity().getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val network = connectivityManager.activeNetwork ?: return false
val networkCapabilities = connectivityManager.getNetworkCapabilities(network) ?: return false
return networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
//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()
// callback(ipAddress)
// }
// }
// } finally {
// conn.disconnect()
// }
// }
// }catch (e: Exception){
// Log.e(TAG,e.toString())
// }
//}
// @SuppressLint("NewApi")
// private fun isInternetAvailable(): Boolean {
// val connectivityManager = requireActivity().getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
// val network = connectivityManager.activeNetwork ?: return false
// val networkCapabilities = connectivityManager.getNetworkCapabilities(network) ?: return false
// return networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
// }
//
// private fun checkUserName(userName: String): Boolean {
// return userName.isNotEmpty() && userName.length >= 3
//}
private fun checkCenterName(centerName: String): Boolean {
return centerName.isNotEmpty() && centerName.length >= 3
}
}

View File

@@ -0,0 +1,42 @@
package com.example.hpostesting.presentation.dashboard.ui
import com.example.hpostesting.util.SecureStorage
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import `in`.sminnovations.hpostesting.R
class PasswordResetActivity : AppCompatActivity() {
private lateinit var editTextNewPassword: EditText
private lateinit var buttonResetPassword: Button
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_password_reset)
editTextNewPassword = findViewById(R.id.editTextNewPassword)
buttonResetPassword = findViewById(R.id.buttonResetPassword)
buttonResetPassword.setOnClickListener {
val newPassword = editTextNewPassword.text.toString().trim()
if (newPassword.isNotEmpty()) {
resetPassword(newPassword)
} else {
Toast.makeText(this, "Please enter a new password", Toast.LENGTH_SHORT).show()
}
}
}
private fun resetPassword(newPassword: String) {
// Implement password reset logic here
// For example, you can store the new password securely
// and update it in the authentication system
val secureStorage = SecureStorage(this)
secureStorage.storePassword(newPassword)
Toast.makeText(this, "Password reset successfully", Toast.LENGTH_SHORT).show()
finish()
}
}

View File

@@ -34,8 +34,8 @@ 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.DataHolder
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.constant.LanguageManager
import com.example.hpostesting.presentation.utils.DeviceCommunicationHandler
@@ -105,8 +105,7 @@ class DeviceActivity : AppCompatActivity(), DeviceCommunicationHandler {
super.onCreate(savedInstanceState)
binding = ActivityDeviceBinding.inflate(layoutInflater)
setContentView(binding.root)
// setSupportActionBar(binding.myToolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
binding.myToolbar.title = "Device Information"
setupListener()
connectUsb(false)
}

View File

@@ -89,6 +89,7 @@ class DeviceFragment : Fragment() {
object : UsbServiceListener {
@SuppressLint("SetTextI18n")
override fun onUsbRead(data: ByteArray?) {
//nothing
}
override fun onUsbError(e: Exception?) {
@@ -141,7 +142,8 @@ class DeviceFragment : Fragment() {
val lines = resultData.split("\n")
var temp = lines[2]
val temp1 = resultData.substringAfter("#AS").substringBefore("#AC")
binding.tvSubtitleNew.text = "Device ID : "+hardwareId+"\nTemperature : $temp\n"+temp1
binding.tvSubtitleNew.text =
"Device ID : $hardwareId\nTemperature : $temp\n$temp1"
}
}

View File

@@ -17,7 +17,6 @@ import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.os.Bundle
import android.os.Environment
import android.provider.Settings
import android.util.Log
import android.view.LayoutInflater
@@ -27,20 +26,18 @@ import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.MutableLiveData
import com.example.hpostesting.util.Result
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionRequest
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.encryption.Encryption
import com.example.hpostesting.presentation.utils.UsbServiceListener
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.google.android.gms.ads.identifier.AdvertisingIdClient
import com.example.hpostesting.presentation.utils.UsbServiceListener
import com.example.hpostesting.util.Result
import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.ktx.Firebase
import `in`.sminnovations.hpostesting.databinding.FragmentDeviceProvisionBinding
import java.io.File
import java.io.FileOutputStream
class DeviceProvisionFragment : Fragment() {
private var resultData: String = ""
@@ -118,12 +115,7 @@ class DeviceProvisionFragment : Fragment() {
)
apply()
}
startActivity(
Intent(
requireContext(),
DashboardActivity::class.java
)
)
Toast.makeText(
activity, "Device registered successfully", Toast.LENGTH_LONG
).show()
@@ -148,7 +140,13 @@ class DeviceProvisionFragment : Fragment() {
// viewModel.addDeviceId(DeviceData(deviceId = sharedPreferences.getString(Constants.DEVICE_ID, "").toString()))
Log.e("idpass", response.toString())
Log.e("idpass", response.data.data?.credentials?.username.toString())
Log.e("idpass", deviceProvisionResponse)
// Log.e("idpass", deviceProvisionResponse)
startActivity(
Intent(
requireContext(),
DashboardActivity::class.java
)
)
} else {
Toast.makeText(
activity,
@@ -161,11 +159,10 @@ class DeviceProvisionFragment : Fragment() {
}
is Result.Error -> {
Log.d("deviceProvisionResponse", response.exception.toString())
response.exception.let { message ->
Toast.makeText(
activity,
"An error occurred in device provision: ${message.message}",
"An error occurred in device provision: $message",
Toast.LENGTH_LONG
).show()
}
@@ -175,7 +172,9 @@ class DeviceProvisionFragment : Fragment() {
binding.btnSubmit.visibility = View.GONE
}
else -> {}
else -> {
//Nothing
}
}
}
viewModel.fireBaseUpload.observe(viewLifecycleOwner) { result ->
@@ -193,8 +192,12 @@ class DeviceProvisionFragment : Fragment() {
(activity as DeviceProvisionActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.DEVICE_CONFIGURATION_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {}
override fun onUsbError(e: Exception?) {}
override fun onUsbRead(data: ByteArray?) {
//nothing
}
override fun onUsbError(e: Exception?) {
//nothing
}
})
}
@@ -214,7 +217,9 @@ class DeviceProvisionFragment : Fragment() {
}
}
override fun onUsbError(e: Exception?) {}
override fun onUsbError(e: Exception?) {
//nothing
}
})
} catch (e: Exception) {
Firebase.crashlytics.recordException(e)
@@ -248,11 +253,15 @@ class DeviceProvisionFragment : Fragment() {
private fun encryptAndSaveToFile(username: String, password: String) {
val messageToEncrypt = "$username\n$password"
val encryptionKey =
Settings.Secure.getString(context?.contentResolver, Settings.Secure.ANDROID_ID)
val encryptionKey = Settings.Secure.getString(requireContext().contentResolver, Settings.Secure.ANDROID_ID)
val encryptedString = Encryption.encrypt(messageToEncrypt, 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")
if (!file.exists()) {

View File

@@ -59,7 +59,7 @@ class DeviceProvisionViewModel @Inject constructor(
fun addDeviceProvisionDataToDb(data: DeviceData) {
viewModelScope.launch {
try {
when (val response = repository.getDeviceResponse(data)) {
when (repository.getDeviceResponse(data)) {
is Response.Success -> {
// Log.i("Testdb", "Data uploaded to Firestore successfully")
fireBaseUpload.postValue("Successfully device response uploaded to firebase")
@@ -70,7 +70,9 @@ class DeviceProvisionViewModel @Inject constructor(
fireBaseUpload.postValue("Error")
}
else -> {}
else -> {
//nothing
}
}
} catch (e: Exception) {
// Log.e("Testdb", "Exception during data upload: ${e.message}")

View File

@@ -30,13 +30,10 @@ import androidx.fragment.app.activityViewModels
import androidx.lifecycle.MutableLiveData
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.constant.TestStatus
import com.example.hpostesting.data.model.devicediagnostics.AdditionalDetails
import com.example.hpostesting.data.model.devicediagnostics.DeviceDiagnosticsRequest
import com.example.hpostesting.data.model.diagnostics.DiagnosticsData
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.presentation.autodac.AutoDacActivity
import com.example.hpostesting.presentation.hemocube.HemocubeActivity
import com.example.hpostesting.presentation.utils.UsbServiceListener
import com.example.hpostesting.util.Result
import com.example.hpostesting.util.Result.Success
@@ -51,10 +48,10 @@ import java.util.Locale
class DiagnosticsFragment : Fragment() {
// Initialize variables to store LED DAC values
var led1Dac: Int? = null
var led2Dac: Int? = null
var led3Dac: Int? = null
var led4Dac: Int? = null
var led1Dac: Double? = null
var led2Dac: Double? = null
var led3Dac: Double? = null
var led4Dac: Double? = null
private var currentProgress = 0
private val targetProgress = 95 // Target progress value
private val delayBetweenIncrements = 1500
@@ -106,10 +103,10 @@ class DiagnosticsFragment : Fragment() {
val additionalDetails = AdditionalDetails(
batteryLevel = batteryLevel,
batteryCapacity = batteryCapacity!!,
batteryMaxCapacity = batteryMaxCapacity!!,
batteryCapacity = batteryCapacity,
batteryMaxCapacity = batteryMaxCapacity,
batteryTemperature = batteryTemperature,
batteryVoltage = batteryVoltage!!
batteryVoltage = batteryVoltage
)
if(Constants.MOLBIO_INTEGRATION){
diagnosticsViewModel.deviceDiagnostics(
@@ -152,7 +149,7 @@ class DiagnosticsFragment : Fragment() {
response.data.data?.let { diagnosticsData ->
val batteryLevel = diagnosticsData.additionalDetails?.batteryLevel
diagnosticsData.additionalDetails?.batteryLevel
}
} else {
@@ -172,9 +169,12 @@ class DiagnosticsFragment : Fragment() {
).show()
}
is Result.Loading -> {
//nothing
}
else -> {}
else -> {
// nothing
}
}
}
@@ -190,8 +190,8 @@ class DiagnosticsFragment : Fragment() {
// data?.let {
// val stringData = String(it)
// diagnosticsViewModel.messages.postValue(stringData)
// binding.tvSubtitle4.text = stringData
// }
// binding.tvSubtitle4.text = stringData
// }
}
override fun onUsbError(e: Exception?) {
@@ -206,6 +206,7 @@ class DiagnosticsFragment : Fragment() {
HemoCubeCommands.DIAGNOSTICS_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
//nothing
}
override fun onUsbError(e: Exception?) {
@@ -219,6 +220,7 @@ class DiagnosticsFragment : Fragment() {
HemoCubeCommands.READ_DAC_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
//nothing
}
override fun onUsbError(e: Exception?) {
@@ -232,6 +234,7 @@ class DiagnosticsFragment : Fragment() {
HemoCubeCommands.LOAD_DAC_VALUES,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
//nothing
}
override fun onUsbError(e: Exception?) {
@@ -240,7 +243,7 @@ class DiagnosticsFragment : Fragment() {
})
}
private fun listenToHemoCube() {
private fun listenToHemoCube() {
diagnosticsViewModel.messages.postValue("Place cuvette filled with buffer\n and click on start")
val fullReadOutput = StringBuilder()
startListening.postValue(true)
@@ -254,7 +257,7 @@ class DiagnosticsFragment : Fragment() {
fullReadOutput.append(stringData)
handleUsbData(stringData)
// binding.tvSubtitle4.text = resultData
// binding.tvSubtitle4.text = resultData
// if (stringData.contains("SN")) {
// val slData = stringData.split(" ")
@@ -319,7 +322,7 @@ class DiagnosticsFragment : Fragment() {
private fun handleUsbData(stringData: String) {
resultData += stringData
if (sharedPreferences.getString(Constants.USER_ID, "").toString() == "ADMIN") {
currentResultData += stringData
currentResultData += stringData
}
when {
@@ -354,7 +357,7 @@ class DiagnosticsFragment : Fragment() {
(resultData.contains("#RC") && this.testStatusCode < 1.8) -> {
this.testStatusCode = 1.9
activity?.runOnUiThread {
finalCalculation()
finalCalculation()
setProgress(100)
binding.progressBarHor.visibility = View.GONE
currentResultData += "\nIf you are facing any issues while using the device \n Contact us for help at support@sminnovations.in"
@@ -383,11 +386,36 @@ class DiagnosticsFragment : Fragment() {
if (!ledDataMap.containsKey(ledName)) {
ledDataMap[ledName] = mutableListOf()
}
if ((ledDataMap[ledName]?.size ?: 0) < 6) {
if ((ledDataMap[ledName]?.size ?: 0) < 7 && xValue != 0.0) {
ledDataMap[ledName]?.add(xValue to yValue)
}
// ledDataMap[ledName]?.add(xValue to yValue)
}
// var valuesAdded = 0 // Track the number of values added
//
// for (match in matches) {
// val ledName = match.groupValues[1]
// val xValue = match.groupValues[2].toDouble()
// val yValue = match.groupValues[3].toDouble()
//
// // Add x and y values to the corresponding lists based on the LED name
// if (!ledDataMap.containsKey(ledName)) {
// ledDataMap[ledName] = mutableListOf()
// }
//
// // Check if we have already added one value, then add the next six
// if (valuesAdded > 0 && (ledDataMap[ledName]?.size ?: 0) < 6) {
// ledDataMap[ledName]?.add(xValue to yValue)
// }
//
// // Increase the count of values added
// valuesAdded++
//
// // Break the loop if we have added 6 values
// if (valuesAdded >= 7) {
// break
// }
// }
// String array to store pass or fail messages for each LED
val results = mutableListOf<String>()
@@ -401,7 +429,7 @@ class DiagnosticsFragment : Fragment() {
// Find LED DAC values using regex
regex.findAll(resultData).forEach {
val (led, dac) = it.destructured
val dacValue = dac.toInt()
val dacValue = dac.toDouble()
when (led.toInt()) {
1 -> led1Dac = dacValue
@@ -446,12 +474,20 @@ class DiagnosticsFragment : Fragment() {
// Calculation for ADC value
val adcValue = when (ledName) {
"LED:1" -> 22000.0
"LED:2", "LED:3" -> 18000.0
"LED:2"-> 18000.0
"LED:3" -> 18000.0
"LED:4" -> 22000.0
else -> 0.0
}
val ledValue = when (ledName) {
"LED:1" -> led1Dac
"LED:2" -> led2Dac
"LED:3" -> led3Dac
"LED:4" -> led4Dac
else -> 0.0
}
val dacValue = calculateDAC(adcValue, slope, constant)
val resultDAC = dacValue - led1Dac!!
val resultDAC = dacValue - ledValue!!
if(resultDAC < 200){
currentResultData += "$ledName DAC LEVEL PASS (✓)\n"
println("$ledName DAC LEVEL PASS")
@@ -464,7 +500,7 @@ class DiagnosticsFragment : Fragment() {
return message
}
fun calculateDAC(adc: Double, slope: Double, constant: Double): Double {
private fun calculateDAC(adc: Double, slope: Double, constant: Double): Double {
return (adc - constant) / slope
}

View File

@@ -13,10 +13,6 @@
package com.example.hpostesting.presentation.diagnostics
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.BatteryManager
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
@@ -34,7 +30,7 @@ import javax.inject.Inject
@HiltViewModel
class DiagnosticsViewModel @Inject constructor(
private val repository: Repository,
context: Context,
// context: Context,
) : ViewModel() {
var isServiceConnected = false
val progressBar = MutableLiveData(false)
@@ -43,14 +39,14 @@ class DiagnosticsViewModel @Inject constructor(
val deviceData = MutableLiveData<DeviceData?>()
val fireBaseUpload = MutableLiveData<String>()
val deviceDiagnosticsResponse = MutableLiveData<Result<DeviceDiagnosticsResponse>>()
private val batteryStatus: Intent? =
IntentFilter(Intent.ACTION_BATTERY_CHANGED).let { ifilter ->
context.registerReceiver(null, ifilter)
}
// private val batteryStatus: Intent? =
// IntentFilter(Intent.ACTION_BATTERY_CHANGED).let { ifilter ->
// context.registerReceiver(null, ifilter)
// }
fun addDiagnosticsDataToDb(data: DiagnosticsData) {
viewModelScope.launch {
try {
when (val response = repository.addDiagnostics(data)) {
when (repository.addDiagnostics(data)) {
is Response.Success -> {
// Log.i("Testdb", "Data uploaded to Firestore successfully")
fireBaseUpload.postValue("Success")
@@ -61,7 +57,9 @@ class DiagnosticsViewModel @Inject constructor(
fireBaseUpload.postValue("Error")
}
else -> {}
else -> {
//nothing
}
}
} catch (e: Exception) {
// Log.e("Testdb", "Exception during data upload: ${e.message}")
@@ -79,71 +77,71 @@ class DiagnosticsViewModel @Inject constructor(
}
fun getBatteryLevel(): Float? {
val batteryPct: Float? = batteryStatus?.let { intent ->
val level: Int =
intent.getIntExtra(
BatteryManager.EXTRA_LEVEL,
-1
)
val scale: Int =
intent.getIntExtra(
BatteryManager.EXTRA_SCALE,
-1
)
level * 100 / scale.toFloat()
}
return batteryPct
}
fun getBatteryTemperature(): Float? {
val batteryTemp: Float? = batteryStatus?.let { intent ->
val temperature = intent.getIntExtra(
BatteryManager.EXTRA_TEMPERATURE,
0
)
temperature.toFloat() / 10
}
return batteryTemp
}
fun getBatteryVoltage(context: Context): Float {
val batteryIntent =
context.registerReceiver(
null,
IntentFilter(Intent.ACTION_BATTERY_CHANGED)
)
val voltage = batteryIntent?.getIntExtra(
BatteryManager.EXTRA_VOLTAGE,
0
) ?: 0
// milli-volts to volts
return voltage.toFloat() / 1000
}
fun getBatteryCapacity(context: Context): Int {
val batteryManager =
context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
val currentCapacity =
batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER)
return currentCapacity
}
fun getBatteryMaxCapacity(context: Context): Float {
val batteryManager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
val designCapacity =
batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
val currentCapacity =
batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER)
// Calculate the estimated maximum battery capacity in mAh
val maxCapacity = currentCapacity.toFloat() / designCapacity.toFloat() * 100
return maxCapacity
}
// fun getBatteryLevel(): Float? {
// val batteryPct: Float? = batteryStatus?.let { intent ->
// val level: Int =
// intent.getIntExtra(
// BatteryManager.EXTRA_LEVEL,
// -1
// )
// val scale: Int =
// intent.getIntExtra(
// BatteryManager.EXTRA_SCALE,
// -1
// )
// level * 100 / scale.toFloat()
// }
//
// return batteryPct
// }
//
// fun getBatteryTemperature(): Float? {
// val batteryTemp: Float? = batteryStatus?.let { intent ->
// val temperature = intent.getIntExtra(
// BatteryManager.EXTRA_TEMPERATURE,
// 0
// )
// temperature.toFloat() / 10
// }
//
// return batteryTemp
// }
//
// fun getBatteryVoltage(context: Context): Float {
// val batteryIntent =
// context.registerReceiver(
// null,
// IntentFilter(Intent.ACTION_BATTERY_CHANGED)
// )
// val voltage = batteryIntent?.getIntExtra(
// BatteryManager.EXTRA_VOLTAGE,
// 0
// ) ?: 0
//
// // milli-volts to volts
// return voltage.toFloat() / 1000
// }
//
//
// fun getBatteryCapacity(context: Context): Int {
// val batteryManager =
// context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
// val currentCapacity =
// batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER)
//
// return currentCapacity
// }
//
// fun getBatteryMaxCapacity(context: Context): Float {
// val batteryManager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
// val designCapacity =
// batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
// val currentCapacity =
// batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER)
//
// // Calculate the estimated maximum battery capacity in mAh
// val maxCapacity = currentCapacity.toFloat() / designCapacity.toFloat() * 100
//
// return maxCapacity
// }
}

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,400 @@
/*
* // 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.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.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?) {
//nothing
}
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?) {
//nothing
}
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?) {
//nothing
}
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,89 @@
/*
* // 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 -> {
//nothing
}
}
} catch (e: Exception) {
fireBaseUpload.postValue("Error")
}
}
}
fun addAutoDacDataToDb(data: DiagnosticsData) {
viewModelScope.launch {
try {
when (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
}
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", "State: ${testDetails?.state}")
Log.d("DigitalCardFragment", "ABHA ID: ${testDetails?.abhaId}")
@@ -67,7 +67,7 @@ class DigitalCardFragment : Fragment() {
activity?.runOnUiThread {
binding.progressBar.visibility = View.GONE
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.State.text = "State: ${testDetails?.state}"
binding.abhaid.text = "ABHA ID: ${testDetails?.abhaId}"

View File

@@ -25,11 +25,8 @@ import androidx.lifecycle.viewModelScope
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import com.example.hpostesting.util.CsvWriter
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.util.NetworkStatusLiveData
import com.example.hpostesting.util.Result
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.dao.HemoCubeBufferDao
import com.example.hpostesting.data.dao.HemoCubeDao
import com.example.hpostesting.data.datasource.LocalFileDataSource
@@ -43,7 +40,6 @@ import com.example.hpostesting.data.model.molbioresult.MolbioV2ResultResponse
import com.example.hpostesting.data.model.patient.BufferCheckData
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.MolbioHemocubeData
import com.example.hpostesting.data.model.patient.toHemoCubeTestData
import com.example.hpostesting.data.model.updates.CheckUpdateRequest
import com.example.hpostesting.data.model.updates.CheckUpdateResponse
@@ -51,8 +47,11 @@ import com.example.hpostesting.data.model.updates.DeviceUpdateRequest
import com.example.hpostesting.data.repository.Repository
import com.example.hpostesting.domain.CheckUpdateWorker
import com.example.hpostesting.domain.LogFileManager
import com.example.hpostesting.util.CsvWriter
import com.example.hpostesting.util.NetworkStatusLiveData
import com.example.hpostesting.util.Result
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.CoroutineExceptionHandler
import `in`.sminnovations.hpostesting.R
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import okhttp3.Headers
@@ -69,22 +68,23 @@ import javax.inject.Inject
@Suppress("MemberVisibilityCanBePrivate")
@HiltViewModel
class HemoCubeViewModel @Inject constructor(
private val hemoCubeDao: HemoCubeDao,
val hemoCubeDao: HemoCubeDao,
private val hemoCubeBufferDao: HemoCubeBufferDao,
private val repository: Repository,
private val logFileManager: LogFileManager,
private val localFileDataSource: LocalFileDataSource,
context: Context,
private val contextV: Context
) : ViewModel() {
private val successMsg = "Data uploaded to Firestore successfully"
private var testUpload: Boolean = false
var isServiceConnected = false
val progressBar = MutableLiveData(false)
private val testDetails = DataHolder.selectedTest?.toHemoCubeTestData()
private val testDetailsmolbio = DataHolder.hemoCubeTestData?.MolbioHemocubeData()
val messages = MutableLiveData<String>()
private val sharedPreference =
context.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
contextV.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
private val workManager = WorkManager.getInstance(context)
private val workManager = WorkManager.getInstance(contextV)
// init {
// startPeriodicCheckUpdate()
@@ -105,7 +105,7 @@ class HemoCubeViewModel @Inject constructor(
// Get the device ID of the device you want to retrieve data for (e.g., the first device in the list)
private val _networkStatusLiveData = NetworkStatusLiveData(context)
private val _networkStatusLiveData = NetworkStatusLiveData(contextV)
val allUserData = hemoCubeDao.getAll()
val allLocalData = hemoCubeDao.getAll()
val allPendingUserToUpload = hemoCubeDao.getPendingUser()
@@ -121,11 +121,11 @@ class HemoCubeViewModel @Inject constructor(
private val batteryStatus: Intent? =
IntentFilter(Intent.ACTION_BATTERY_CHANGED).let { ifilter ->
context.registerReceiver(null, ifilter)
contextV.registerReceiver(null, ifilter)
}
fun uploadHemoCubeResultToDatabase(
isOnline: Boolean, testStatus: Boolean, kitSerial: String?,
isOnline: Boolean, testStatus: Boolean, kitSerial: String?,quickCapture:Boolean
) = viewModelScope.launch {
if (kitSerial != null) {
testDetails?.kitSerial = kitSerial
@@ -135,19 +135,84 @@ class HemoCubeViewModel @Inject constructor(
try {
if (isOnline) {
parseData()
addResultTestToDb()
//addResultTestToDb(quickCapture)
if(Constants.FIREBASE_INTEGRATION){
addResultTestToDb(quickCapture)
}else{
uploadToMolbio()
}
} else {
parseData()
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(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
contextV.resources.getString(R.string.DateTimeFormat), Locale.getDefault()
).format(Calendar.getInstance().time)
testDetails?.localFlag = false
hemoCubeDao.updateTest(testDetails!!)
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) {
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(
contextV.resources.getString(R.string.DateTimeFormat), 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 {
loginResponse.postValue(Result.Loading())
@@ -172,7 +237,7 @@ class HemoCubeViewModel @Inject constructor(
}
fun sendDataToMolbio() = viewModelScope.launch(Dispatchers.IO + coroutineExceptionHandler) {
fun sendDataToMolbio() = viewModelScope.launch(Dispatchers.IO) {
Log.d("molbio","getting in sendMolbio")
val resultList = MolbioV2ResultRequest(mutableListOf())
@@ -189,7 +254,7 @@ class HemoCubeViewModel @Inject constructor(
?: "defaultThreshold" // Handle possible nulls safely
resultList.results?.add(
MolbioV2Result(
rawData = userData.MolbioHemocubeData(),
rawData = userData,
analysisId = userData._id,
analysisDate = currentTimeFormatted,
analysisStatus = userData.classificationResult
@@ -223,34 +288,40 @@ class HemoCubeViewModel @Inject constructor(
is Result.Success -> {
it.data.data?.forEach { id ->
id.rawData?.let { it1 ->
updateLocalFlag(it1._id)
updateMolbioFlag(
it1._id
)
}
}
fireBaseBulkUpload.postValue("Success")
}
is Result.Error -> {
fireBaseBulkUpload.postValue("Error")
Log.d("result","result upload error")
}
else -> {
fireBaseBulkUpload.postValue("Error")
Log.d("result","result upload else")
}
}
}
}
fun sendDataToFirebase() = viewModelScope.launch ( Dispatchers.IO + coroutineExceptionHandler ) {
fun sendDataToFirebase() = viewModelScope.launch (Dispatchers.IO) {
val pendingData = hemoCubeDao.getFirebasePending()
pendingData.forEach{
userData ->
if (userData != null) {
if (!userData.localFlag && userData.testStatus == true) {
bulkAddResultTestToDb(userData)
}
if (!userData.localFlag && userData.testStatus == true) {
bulkAddResultTestToDb(userData)
}
}
if(testUpload){
fireBaseBulkUpload.postValue("Success")
}
// else{
// fireBaseBulkUpload.postValue("Error")
// }
}
@@ -267,7 +338,6 @@ class HemoCubeViewModel @Inject constructor(
repository.deviceUpdate(deviceUpdateRequest).let {
deviceUpdate.postValue(it.body())
deviceUpdateheader.postValue(it.headers())
}
}
@@ -290,7 +360,7 @@ class HemoCubeViewModel @Inject constructor(
fun uploadLogs() = viewModelScope.launch {
uploadLogs.postValue(Result.Loading())
val logFile = logFileManager.createLogFile().let { file ->
logFileManager.createLogFile().let { file ->
val requestBody = file?.asRequestBody("multipart/form-data".toMediaTypeOrNull())
val multipartFile =
requestBody?.let { MultipartBody.Part.createFormData("logFile", file?.name, it) }
@@ -315,7 +385,7 @@ class HemoCubeViewModel @Inject constructor(
when (val response =
repository.addTestToDatabaseforBufferCheck(bufferCheckData)) {
is Response.Success -> {
Log.i("Testdb", "Data uploaded to Firestore successfully")
Log.i("Testdb", successMsg)
fireBaseUpload.postValue("Success")
bufferCheckData.localFlag = true
hemoCubeBufferDao.insertAll(bufferCheckData)
@@ -327,8 +397,6 @@ class HemoCubeViewModel @Inject constructor(
bufferCheckData.localFlag = true
hemoCubeBufferDao.insertAll(bufferCheckData)
}
else -> {}
}
} catch (e: Exception) {
Log.e("Testdb", "Exception during data upload: ${e.message}")
@@ -343,7 +411,7 @@ class HemoCubeViewModel @Inject constructor(
fun bulkAddResultKitTestToDb(bufferCheckData: BufferCheckData) {
viewModelScope.launch {
bufferCheckData.reportUploadTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
contextV.resources.getString(R.string.DateTimeFormat), Locale.getDefault()
).format(Calendar.getInstance().time)
when (repository.addTestToDatabaseforBufferCheck(bufferCheckData)) {
is Response.Success -> {
@@ -372,7 +440,7 @@ class HemoCubeViewModel @Inject constructor(
testDetails?.resultData = DataHolder.hemoCubeTestData?.resultData.toString()
testDetails?.location = DataHolder.location
testDetails?.testTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
contextV.resources.getString(R.string.DateTimeFormat), Locale.getDefault()
).format(Calendar.getInstance().time)
testDetails?.appVersion = DataHolder.hemoCubeTestData?.appVersion
testDetails?.deviceId = DataHolder.hemoCubeTestData?.deviceId
@@ -402,7 +470,7 @@ class HemoCubeViewModel @Inject constructor(
testDetails?.coefficients = DataHolder.hemoCubeTestData?.coefficients
testDetails?.incubationTime = DataHolder.hemoCubeTestData?.incubationTime.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?.classificationResult = DataHolder.hemoCubeTestData?.classificationResult!!
testDetails?.prdClassification = DataHolder.hemoCubeTestData?.prdClassification.toString()
@@ -421,73 +489,96 @@ class HemoCubeViewModel @Inject constructor(
testDetails?.volume = DataHolder.hemoCubeTestData?.volume
testDetails?.filter = DataHolder.hemoCubeTestData?.filter
testDetails?.labName = DataHolder.hemoCubeTestData?.labName
testDetails?.cuvetteSize = sharedPreference.getString(Constants.CUVETTE_SIZE, "").toString()
testDetails?.centerName = sharedPreference.getString(Constants.CENTER_NAME, "").toString()
testDetails?.district = sharedPreference.getString(Constants.DISTRICT, "").toString()
testDetails?.ipAddress = sharedPreference.getString(Constants.IP_ADDRESS, "").toString()
testDetails?.configUpdatedRecent = sharedPreference.getString(Constants.LAST_UPDATED, "NA").toString()
}
private fun addResultTestToDb() {
private fun addResultTestToDb(quickCapture: Boolean) {
viewModelScope.launch {
try {
testDetails!!.reportUploadTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
testDetails!!.quickCapture = quickCapture
testDetails.testStatus = true
testDetails.reportUploadTime = SimpleDateFormat(
contextV.resources.getString(R.string.DateTimeFormat), Locale.getDefault()
).format(Calendar.getInstance().time)
val currentTimeFormatted = SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ssZZZZZ",
contextV.resources.getString(R.string.DateTimeFormat),
Locale.getDefault()
).format(Calendar.getInstance().time)
if(Constants.FIREBASE_INTEGRATION) {
when (val response = repository.addTestToDatabase(testDetails)) {
is Response.Success -> {
val kitCount = sharedPreference.getInt(Constants.KIT_COUNT, 0)
with(sharedPreference.edit()) {
putInt(Constants.KIT_COUNT, kitCount.plus(1))
apply()
if(quickCapture){
when (val response = repository.addQcTestToDatabase(testDetails)) {
is Response.Success -> {
val kitCount = sharedPreference.getInt(Constants.KIT_COUNT, 0)
with(sharedPreference.edit()) {
putInt(Constants.KIT_COUNT, kitCount.plus(1))
apply()
}
Log.i("Testdb", successMsg)
fireBaseUpload.postValue("Success")
testDetails.localFlag = true
hemoCubeDao.updateTest(testDetails)
}
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 -> {
//nothing
}
}
}else{
when (val response = repository.addTestToDatabase(testDetails)) {
is Response.Success -> {
testDetails.localFlag = true
val kitCount = sharedPreference.getInt(Constants.KIT_COUNT, 0)
with(sharedPreference.edit()) {
putInt(Constants.KIT_COUNT, kitCount.plus(1))
apply()
}
Log.i("Testdb", successMsg)
fireBaseUpload.postValue("Success")
is Response.Error -> {
Log.e("Testdb", "Error uploading data to Firestore: $response")
fireBaseUpload.postValue("Error")
hemoCubeDao.updateTest(testDetails)
}
if (Constants.MOLBIO_INTEGRATION) {
// Sanitize testDetails before using it in the API call
val sanitizedTestDetails = sanitizeDoubleValues(testDetails)
else -> {}
}
}
if (Constants.MOLBIO_INTEGRATION) {
val kitCount = sharedPreference.getInt(Constants.KIT_COUNT, 0)
with(sharedPreference.edit()) {
putInt(Constants.KIT_COUNT, kitCount.plus(1))
apply()
}
// Sanitize testDetails before using it in the API call
val sanitizedTestDetails = testDetailsmolbio?.let { sanitizeDoubleValues(it) }
// 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,
// 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,
)
)
)
)
)
)
)
hemoCubeDao.updateTest(testDetails)
}
hemoCubeDao.updateTest(testDetails)
}
is Response.Error -> {
Log.e("Testdb", "Error uploading data to Firestore: $response")
fireBaseUpload.postValue("Error")
hemoCubeDao.updateTest(testDetails)
}
}
}
} catch (e: Exception) {
Log.e("Testdb", "Exception during data upload: ${e.message}")
fireBaseUpload.postValue("Error")
@@ -502,28 +593,29 @@ class HemoCubeViewModel @Inject constructor(
).format(Calendar.getInstance().time)
when (repository.addTestToDatabase(userData)) {
is Response.Success -> {
fireBaseBulkUpload.postValue("Success")
testUpload = true
userData.localFlag = true
updateLocalFlag(userData._id)
}
else -> {
fireBaseBulkUpload.postValue("Error")
testUpload = false
}
}
}
}
fun sanitizeDoubleValues(molbiohemocubeData: MolbioHemocubeData): MolbioHemocubeData {
molbiohemocubeData::class.java.declaredFields.forEach { field ->
fun sanitizeDoubleValues(hemoCubeTestData: HemoCubeTestData): HemoCubeTestData {
hemoCubeTestData::class.java.declaredFields.forEach { field ->
if (field.type == Double::class.javaObjectType || field.type == Double::class.javaPrimitiveType) {
field.isAccessible = true
val value = field.get(molbiohemocubeData) as Double?
val value = field.get(hemoCubeTestData) as Double?
if (value != null && (value.isInfinite() || value.isNaN())) {
field.set(molbiohemocubeData, 0.0) // Replace with a suitable default value
field.set(hemoCubeTestData, 0.0) // Replace with a suitable default value
}
}
}
return molbiohemocubeData
return hemoCubeTestData
}
private fun updateLocalFlag(userId: String) = viewModelScope.launch {
@@ -538,7 +630,6 @@ class HemoCubeViewModel @Inject constructor(
hemoCubeDao.insertAll(userData)
}
fun deleteById(userId: String) = viewModelScope.launch {
hemoCubeDao.deleteById(id = userId)
}
@@ -551,7 +642,7 @@ class HemoCubeViewModel @Inject constructor(
when (val response =
repository.addTestToDatabaseforBufferCheck(bufferCheckData)) {
is Response.Success -> {
Log.i("Testdb", "Data uploaded to Firestore successfully")
Log.i("Testdb", successMsg)
fireBaseUpload.postValue("Success")
}
@@ -559,8 +650,6 @@ class HemoCubeViewModel @Inject constructor(
Log.e("Testdb", "Error uploading data to Firestore: $response")
fireBaseUpload.postValue("Error")
}
else -> {}
}
} catch (e: Exception) {
Log.e("Testdb", "Exception during data upload: ${e.message}")
@@ -573,6 +662,10 @@ class HemoCubeViewModel @Inject constructor(
viewModelScope.launch {
hemoCubeBufferDao.updateFieldById(id = bufferId, true)
}
fun deleteByStatus() = viewModelScope.launch {
hemoCubeDao.deleteByStatus()
}
fun getLocalUserDataForCsv(context: Context): Boolean {
val localUserDataLiveData: LiveData<List<HemoCubeTestData>> = hemoCubeDao.getAll()
@@ -588,7 +681,7 @@ class HemoCubeViewModel @Inject constructor(
userData._id,
userData.name,
userData.bloodGroup,
userData.birthYear,
userData.age,
userData.classificationResult,
userData.testTime.toString(),
userData.userImageURL
@@ -694,7 +787,4 @@ class HemoCubeViewModel @Inject constructor(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
}
val coroutineExceptionHandler = CoroutineExceptionHandler{_, throwable ->
throwable.printStackTrace()
}
}

View File

@@ -21,9 +21,11 @@ import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.ServiceConnection
import android.content.SharedPreferences
import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbDeviceConnection
import android.hardware.usb.UsbManager
import android.icu.text.SimpleDateFormat
import android.os.Build
import android.os.Bundle
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.LanguageManager
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.UsbSerialProber
import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityHemocubeBinding
import java.util.Calendar
import java.util.Locale
@AndroidEntryPoint
open class HemocubeActivity : AppCompatActivity() {
private val remoteConfig: FirebaseRemoteConfig = Firebase.remoteConfig
private lateinit var binding: ActivityHemocubeBinding
private val viewModel by viewModels<HemoCubeViewModel>()
private var myMenu: Menu? = null
lateinit var sharedPreferences: SharedPreferences
private lateinit var mDriver: UsbSerialDriver
private var mConnection: UsbDeviceConnection? = null
lateinit var mService: UsbService
@@ -70,6 +79,7 @@ open class HemocubeActivity : AppCompatActivity() {
DataHolder.usbConnected.postValue(true)
}
} else {
Log.d("HemoCubeActivity", "permission denied for device")
onErrorReported("permission denied for device")
DataHolder.usbConnected.postValue(true)
}
@@ -107,6 +117,95 @@ open class HemocubeActivity : AppCompatActivity() {
supportActionBar?.setDisplayHomeAsUpEnabled(true)
setupListener()
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() {
@@ -115,10 +214,12 @@ open class HemocubeActivity : AppCompatActivity() {
if (it) {
myMenu?.get(0)?.icon =
ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_24)
Log.d("HemoCubeActivity", "Device is Connected")
} 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()
Log.d("HemoCubeActivity", "Device is Disconnected")
}
}
}
@@ -130,8 +231,10 @@ open class HemocubeActivity : AppCompatActivity() {
val availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager)
if (availableDrivers.isEmpty()) {
Log.d("HemoCubeActivity", "No Device is Connected")
onErrorReported("No Device is Connected")
} else {
Log.d("HemoCubeActivity", "Device available")
mDriver = availableDrivers[0]
mConnection = manager.openDevice(mDriver.device)
@@ -191,14 +294,23 @@ open class HemocubeActivity : AppCompatActivity() {
}
override fun onBackPressed() {
val fragment = supportFragmentManager.findFragmentById(R.id.fghemocube)
if (fragment is HemoCubeFragment) {
fragment.handleBackButtonPress()
} else {
super.onBackPressed()
}
// override fun onBackPressed() {
// val fragment = supportFragmentManager.findFragmentById(R.id.fghemocube)
// if (fragment is HemoCubeFragment) {
// fragment.handleBackButtonPress()
// } else {
// super.onBackPressed()
// }
// }
override fun onBackPressed() {
val fragment = supportFragmentManager.findFragmentById(R.id.fghemocube)
if (fragment is HemoCubeFragment && fragment.handleBackButtonPress()) {
// If the fragment handled the back press, return to avoid calling super.onBackPressed
return
}
// If the fragment did not handle the back press, call the superclass method
super.onBackPressed()
}
fun onErrorReported(msg: String) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()

View File

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

View File

@@ -485,7 +485,7 @@ class TestRightViewModel @Inject constructor(
val csvUri = csvUploadTask.storage.downloadUrl.await().toString()
val logUri = logUploadTask.storage.downloadUrl.await().toString()
val serialNumber = Constants.STATICID.firstOrNull { it == deviceSerialNumber }
// val serialNumber = Constants.STATICID.firstOrNull { it == deviceSerialNumber }
testDetails?.csvPath = csvUri
testDetails?.reportPath = logUri

View File

@@ -43,7 +43,6 @@ import com.example.hpostesting.data.model.molbioresult.MolbioV2ResultResponse
import com.example.hpostesting.data.model.patient.BufferCheckData
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.MolbioHemocubeData
import com.example.hpostesting.data.model.patient.toHemoCubeTestData
import com.example.hpostesting.data.model.updates.CheckUpdateRequest
import com.example.hpostesting.data.model.updates.CheckUpdateResponse
@@ -76,7 +75,6 @@ class TrueHemeViewModel @Inject constructor(
var isServiceConnected = false
val progressBar = MutableLiveData(false)
private val testDetails = DataHolder.selectedTest?.toHemoCubeTestData()
private val testDetailsmolbio = DataHolder.hemoCubeTestData?.MolbioHemocubeData()
val messages = MutableLiveData<String>()
private val sharedPreference =
context.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
@@ -161,12 +159,12 @@ class TrueHemeViewModel @Inject constructor(
}
}
fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest) = viewModelScope.launch {
deviceUpdate.postValue(Result.Loading())
repository.deviceUpdate(deviceUpdateRequest).let {
// fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest) = viewModelScope.launch {
// deviceUpdate.postValue(Result.Loading())
// repository.deviceUpdate(deviceUpdateRequest).let {
// deviceUpdate.postValue(it)
}
}
// }
// }
fun startPeriodicCheckUpdate() {
val periodicRequest = PeriodicWorkRequestBuilder<CheckUpdateWorker>(
@@ -289,7 +287,7 @@ class TrueHemeViewModel @Inject constructor(
testDetails?.coefficients = DataHolder.hemoCubeTestData?.coefficients
testDetails?.incubationTime = DataHolder.hemoCubeTestData?.incubationTime.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?.classificationResult = DataHolder.hemoCubeTestData?.classificationResult!!
testDetails?.prdClassification = DataHolder.hemoCubeTestData?.prdClassification.toString()
@@ -323,12 +321,12 @@ class TrueHemeViewModel @Inject constructor(
}
Log.i("Testdb", "Data uploaded to Firestore successfully")
fireBaseUpload.postValue("Success")
testDetailsmolbio!!.localFlag = true
testDetails.localFlag = true
uploadResult(
MolbioV2ResultRequest(
mutableListOf(
MolbioV2Result(
rawData = testDetailsmolbio,
rawData = testDetails,
analysisId = testDetails._id,
analysisDate = testDetails.testTime,
analysisStatus = testDetails.classificationResult,
@@ -436,7 +434,7 @@ class TrueHemeViewModel @Inject constructor(
userData._id,
userData.name,
userData.bloodGroup,
userData.birthYear,
userData.age,
userData.classificationResult,
userData.testTime.toString(),
userData.userImageURL

View File

@@ -36,11 +36,7 @@ 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.HemoCubeCommands
import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.presentation.deviceinfo.DeviceFragment
import com.example.hpostesting.presentation.utils.DeviceCommunicationHandler
import com.example.hpostesting.presentation.utils.UsbServiceListener
import com.example.hpostesting.util.UsbService
import com.hoho.android.usbserial.driver.UsbSerialDriver
import com.hoho.android.usbserial.driver.UsbSerialProber
@@ -59,25 +55,37 @@ class UsbTerminalActivity : AppCompatActivity() {
private var mConnection: UsbDeviceConnection? = null
lateinit var mService: UsbService
private var deviceId = ""
private var executedCommands: MutableList<String> = mutableListOf()
private var isResuming = false
private val TAG = "Calibration"
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 {
if (UsbManager.ACTION_USB_DEVICE_DETACHED == intent.action) {
// Handle USB disconnection
Log.d(TAG, "USB device detached")
cleanupUsb()
DataHolder.usbConnected.postValue(false)
}
if (UsbManager.ACTION_USB_DEVICE_ATTACHED == intent.action) {
// Handle USB reconnection
Log.d(TAG, "USB device attached")
connectUsb(false) // Attempt reconnection
} else if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
// Handle USB permission granted
device?.let {
connectUsb(true)
DataHolder.usbConnected.postValue(true)
}
} else {
onErrorReported("permission denied for device")
DataHolder.usbConnected.postValue(true)
Log.e(TAG, "USB permission denied")
DataHolder.usbConnected.postValue(false)
}
}
}
}
@@ -96,6 +104,15 @@ class UsbTerminalActivity : AppCompatActivity() {
}
}
fun getExecutedCommands(): List<String> {
return executedCommands
}
fun addExecutedCommand(command: String) {
if (!executedCommands.contains(command)) {
executedCommands.add(command)
}
}
override fun attachBaseContext(newBase: Context?) {
val languageCode = LanguageManager.getSavedLanguage(newBase!!)
LanguageManager.setLocale(newBase, languageCode)
@@ -106,18 +123,28 @@ class UsbTerminalActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
binding = ActivityUsbTerminalBinding.inflate(layoutInflater)
setContentView(binding.root)
// setSupportActionBar(binding.myToolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
val filter = IntentFilter()
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED)
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED)
registerReceiver(broadcastReceiver, filter)
doBoth()
}
fun doBoth(){
setupListener()
connectUsb(false)
}
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)
@@ -128,11 +155,14 @@ class UsbTerminalActivity : AppCompatActivity() {
open fun connectUsb(permissionGranted: Boolean) {
Log.d(TAG, "connectUsb() called, permission variable = $permissionGranted")
cleanupUsb() // Clean up before reinitializing
val manager = getSystemService(Context.USB_SERVICE) as UsbManager
val availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager)
if (availableDrivers.isEmpty()) {
onErrorReported("No Device is Connected")
onErrorReported("No Device Connected")
DataHolder.usbConnected.postValue(false)
} else {
mDriver = availableDrivers[0]
mConnection = manager.openDevice(mDriver.device)
@@ -140,13 +170,13 @@ class UsbTerminalActivity : AppCompatActivity() {
requestUserPermission(manager, mDriver.device)
} else {
setupService()
DataHolder.usbConnected.postValue(true)
}
}
}
fun onErrorReported(msg: String) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
if (!isFinishing) onBackPressed()
}
private fun moveToNext() {
@@ -156,6 +186,9 @@ class UsbTerminalActivity : AppCompatActivity() {
.commit()
}
@SuppressLint("MutableImplicitPendingIntent")
private fun requestUserPermission(manager: UsbManager, device: UsbDevice) {
val mPendingIntent: PendingIntent
@@ -187,12 +220,29 @@ class UsbTerminalActivity : AppCompatActivity() {
return true
}
override fun onDestroy() {
super.onDestroy()
unregisterReceiver(broadcastReceiver)
if (usbTerminalViewModel.isServiceConnected) {
mService.disconnect()
unbindService(connection)
usbTerminalViewModel.isServiceConnected = false
}
cleanupUsb()
}
private fun cleanupUsb() {
try {
mService.disconnect()
unbindService(connection)
} catch (e: Exception) {
Log.e(TAG, "Error during USB cleanup: ${e.message}")
}
mConnection?.close()
mConnection = null
}
}

View File

@@ -13,6 +13,8 @@
package com.example.hpostesting.presentation.usb_teminal
// Fragment Class
import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
@@ -23,62 +25,150 @@ import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.MutableLiveData
import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.presentation.utils.UsbServiceListener
import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.ktx.Firebase
import `in`.sminnovations.hpostesting.databinding.FragmentUsbTerminalBinding
class UsbTerminalFragment : Fragment() {
private lateinit var binding: FragmentUsbTerminalBinding
private val usbTerminalViewModel: UsbTerminalViewModel by activityViewModels()
private lateinit var sharedPreferences: SharedPreferences
private var startListening = MutableLiveData(false)
private var resultData: String = ""
private var resultData = StringBuilder()
private var commandQueue: MutableList<String> = mutableListOf()
private var currentCommand: String? = null
var executedCommands: MutableList<String> = mutableListOf()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
): View {
binding = FragmentUsbTerminalBinding.inflate(inflater, container, false)
sharedPreferences =
requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
binding.clearQueueButton.setOnClickListener {
clearQueue()
}
sharedPreferences = requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val pastCommands = (activity as? UsbTerminalActivity)?.getExecutedCommands() ?: emptyList()
if (pastCommands.isNotEmpty()) {
resumeCommands(pastCommands)
}
initViews()
}
private fun initViews() {
binding.messageCommand.movementMethod = ScrollingMovementMethod()
usbTerminalViewModel.messages.observe(viewLifecycleOwner) {
binding.messageCommand.text = it
// Observe messages with proper formatting
usbTerminalViewModel.messages.observe(viewLifecycleOwner) { message ->
binding.messageCommand.text = message
scrollToBottom()
}
binding.sendCommand.setOnClickListener {
callCommand(binding.etCommands.text.trim().toString())
val commands = binding.etCommands.text.toString().trim()
if (commands.isNotEmpty()) {
// Process entire command string
addToQueue(listOf(commands))
binding.etCommands.text.clear()
}
}
listenToHemoCube()
callCommand("I")
}
private fun callCommand(command: String) {
usbTerminalViewModel.progressBar.postValue(true)
(activity as UsbTerminalActivity).mService.sendAndListenToHemoCubeTxt(
command,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
}
private fun scrollToBottom() {
binding.messageCommand.post {
val scrollAmount = binding.messageCommand.layout.getLineTop(binding.messageCommand.lineCount) -
binding.messageCommand.height
if (scrollAmount > 0) {
binding.messageCommand.scrollTo(0, scrollAmount)
}
}
}
override fun onUsbError(e: Exception?) {
usbTerminalViewModel.progressBar.postValue(false)
private fun addToQueue(commands: List<String>) {
// Append new commands to the queue instead of replacing it
commandQueue.addAll(commands)
// Track commands in the activity
(activity as? UsbTerminalActivity)?.let { activity ->
commands.forEach { command ->
activity.addExecutedCommand(command)
}
}
appendFormattedMessage("\nAdded commands to queue: ${commands.joinToString(" ")}")
processNextCommand() // Start processing if not already in progress
}
fun clearQueue() {
commandQueue.clear()
currentCommand = null
appendFormattedMessage("\nCommand queue cleared")
}
private fun appendFormattedMessage(message: String) {
resultData.append("\n").append(message)
usbTerminalViewModel.messages.postValue(resultData.toString())
scrollToBottom()
}
private fun processNextCommand() {
if (currentCommand == null && commandQueue.isNotEmpty()) {
currentCommand = commandQueue.removeAt(0)
callCommand(currentCommand!!)
}
}
private fun callCommand(command: String) {
// Don't process if command was cleared
if (currentCommand == null) {
return
}
usbTerminalViewModel.progressBar.postValue(true)
appendFormattedMessage("Sending command: $command \n")
try {
(activity as UsbTerminalActivity).mService.sendAndListenToHemoCubeTxt(
command,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
// Keep empty as per original code
}
override fun onUsbError(e: Exception?) {
activity?.runOnUiThread {
appendFormattedMessage("Error sending command $command: ${e?.message ?: "Unknown error"}")
usbTerminalViewModel.progressBar.postValue(false)
currentCommand = null
processNextCommand()
}
}
}
})
)
} catch (e: Exception) {
appendFormattedMessage("Error: ${e.localizedMessage}")
usbTerminalViewModel.progressBar.postValue(false)
currentCommand = null
processNextCommand()
}
}
private fun listenToHemoCube() {
val fullReadOutput = StringBuilder()
startListening.postValue(true)
try {
@@ -86,20 +176,58 @@ class UsbTerminalFragment : Fragment() {
override fun onUsbRead(data: ByteArray?) {
data?.let {
val stringData = String(it)
fullReadOutput.append(stringData)
resultData += stringData
usbTerminalViewModel.messages.postValue(resultData)
resultData.append(stringData)
activity?.runOnUiThread {
usbTerminalViewModel.messages.postValue(resultData.toString())
scrollToBottom()
// Check for command completion
if (currentCommand != null && stringData.contains("${currentCommand}C")) {
currentCommand = null
usbTerminalViewModel.progressBar.postValue(false)
// If there are no more commands in queue, clear completion flags
if (commandQueue.isEmpty()) {
appendFormattedMessage("\nAll commands completed")
} else {
processNextCommand()
}
}
}
}
}
override fun onUsbError(e: Exception?) {
usbTerminalViewModel.messages.postValue(e!!.localizedMessage)
usbTerminalViewModel.progressBar.postValue(false)
activity?.runOnUiThread {
appendFormattedMessage("Error: ${e?.localizedMessage ?: "Unknown error"}")
usbTerminalViewModel.progressBar.postValue(false)
currentCommand = null
processNextCommand()
}
}
})
} catch (e: Exception) {
usbTerminalViewModel.messages.postValue(e.localizedMessage)
Firebase.crashlytics.recordException(e)
appendFormattedMessage("Error: ${e.localizedMessage}")
}
}
}
fun resumeCommands(pastCommands: List<String>) {
appendFormattedMessage("Resuming execution...")
pastCommands.forEach { command ->
if (!commandQueue.contains(command)) {
commandQueue.add(command)
}
}
processNextCommand()
}
override fun onDestroyView() {
super.onDestroyView()
startListening.value = false
resultData.clear()
commandQueue.clear()
currentCommand = null
}
}

View File

@@ -23,8 +23,6 @@ import javax.inject.Inject
@HiltViewModel
class UsbTerminalViewModel @Inject constructor(
private val hemoCubeDao: HemoCubeDao,
private val repository: Repository,
) : ViewModel() {
var isServiceConnected = false
val progressBar = MutableLiveData(false)

View File

@@ -15,6 +15,6 @@ package com.example.hpostesting.presentation.utils
import com.example.hpostesting.data.constant.HemoCubeCommands
interface DeviceCommunicationHandler {
fun interface DeviceCommunicationHandler {
fun sendAndListenToDevice(command: HemoCubeCommands, listener: UsbServiceListener)
}

View File

@@ -26,16 +26,9 @@ import io.nats.client.NKey
import io.nats.client.Nats
import io.nats.client.Options
import io.nats.client.support.SSLUtils
import java.io.FileInputStream
import java.io.IOException
import java.nio.charset.StandardCharsets
import java.security.GeneralSecurityException
import java.security.KeyStore
import java.security.SecureRandom
import java.security.cert.CertificateFactory
import javax.net.ssl.KeyManagerFactory
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManagerFactory
class NatsManager(datacollector: DashboardActivity) {
@@ -46,41 +39,41 @@ class NatsManager(datacollector: DashboardActivity) {
var connect = false
var sharedPreferences = datacollector.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
private fun createSSLContext(): SSLContext {
val keyStorePassword = "prime24".toCharArray() // Change as necessary
val clientCertPath = "/storage/sdcard0/Download/client.p12"
// Load client certificate and key
val keyStore = KeyStore.getInstance("PKCS12")
FileInputStream(clientCertPath).use { keyStoreInputStream ->
keyStore.load(keyStoreInputStream, keyStorePassword)
}
val caCertPath =
"/storage/sdcard0/Android/data/in.sminnovations.hpostesting.quality/files/NATS/clientCertificate/client-cert.pem"
val caCert = FileInputStream(caCertPath).use { inputStream ->
val certificateFactory = CertificateFactory.getInstance("X.509")
certificateFactory.generateCertificate(inputStream)
}
val trustStore = KeyStore.getInstance(KeyStore.getDefaultType()).apply {
load(null, null) // Initialize the keystore
setCertificateEntry("caCert", caCert) // Add the CA certificate
}
// Initialize key manager factory
val kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm())
kmf.init(keyStore, keyStorePassword)
// Initialize trust manager factory
val tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
tmf.init(trustStore)
// Initialize SSLContext
val sslContext = SSLContext.getInstance("TLS")
sslContext.init(kmf.keyManagers, tmf.trustManagers, SecureRandom())
return sslContext
}
// private fun createSSLContext(): SSLContext {
// val keyStorePassword = "prime24".toCharArray() // Change as necessary
// val clientCertPath = "/storage/sdcard0/Download/client.p12"
//
// // Load client certificate and key
// val keyStore = KeyStore.getInstance("PKCS12")
// FileInputStream(clientCertPath).use { keyStoreInputStream ->
// keyStore.load(keyStoreInputStream, keyStorePassword)
// }
// val caCertPath =
// "/storage/sdcard0/Android/data/in.sminnovations.hpostesting.quality/files/NATS/clientCertificate/client-cert.pem"
// val caCert = FileInputStream(caCertPath).use { inputStream ->
// val certificateFactory = CertificateFactory.getInstance("X.509")
// certificateFactory.generateCertificate(inputStream)
// }
//
// val trustStore = KeyStore.getInstance(KeyStore.getDefaultType()).apply {
// load(null, null) // Initialize the keystore
// setCertificateEntry("caCert", caCert) // Add the CA certificate
// }
//
// // Initialize key manager factory
// val kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm())
// kmf.init(keyStore, keyStorePassword)
//
// // Initialize trust manager factory
// val tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
// tmf.init(trustStore)
//
// // Initialize SSLContext
// val sslContext = SSLContext.getInstance("TLS")
// sslContext.init(kmf.keyManagers, tmf.trustManagers, SecureRandom())
//
// return sslContext
// }
@RequiresApi(Build.VERSION_CODES.O)
fun connect() {
@@ -139,7 +132,7 @@ class NatsManager(datacollector: DashboardActivity) {
if (nc?.status == Connection.Status.CONNECTED) {
Log.d("NATSCONNECTION", "NATS is successfully connected.")
nc?.subscribe("device.hpos.${deviceId}.ping")
// Log.d(TAG, "Nats subscribed with ping-"+d)
// Log.d(TAG, "Nats subscribed with ping-"+d)
nc?.publish(
"server.hpos.${deviceId}.ping",
"ALIVE".toByteArray(StandardCharsets.UTF_8)

View File

@@ -0,0 +1,14 @@
package com.example.hpostesting.util
import android.content.Context
object AppInitializer {
fun initialize(context: Context) {
val secureStorage = SecureStorage(context)
if (secureStorage.getPassword() == null || secureStorage.getAdminPassword() == null) {
// Store the shared password securely
secureStorage.storePassword("SMI@12345")
secureStorage.storeAdminPassword("SMI@Admin$")
}
}
}

View File

@@ -0,0 +1,44 @@
package com.example.hpostesting.util
import android.accounts.AbstractAccountAuthenticator
import android.accounts.Account
import android.accounts.AccountAuthenticatorResponse
import android.accounts.NetworkErrorException
import android.content.Context
import android.os.Bundle
class MyAuthenticator(context: Context) : AbstractAccountAuthenticator(context) {
override fun editProperties(response: AccountAuthenticatorResponse?, accountType: String?): Bundle {
throw UnsupportedOperationException()
}
override fun addAccount(response: AccountAuthenticatorResponse?, accountType: String?, authTokenType: String?, requiredFeatures: Array<out String>?, options: Bundle?): Bundle? {
// Add your logic to add an account
return null
}
override fun confirmCredentials(response: AccountAuthenticatorResponse?, account: Account?, options: Bundle?): Bundle? {
// Add your logic to confirm credentials
return null
}
override fun getAuthToken(response: AccountAuthenticatorResponse?, account: Account?, authTokenType: String?, options: Bundle?): Bundle? {
// Add your logic to get an authentication token
return null
}
override fun getAuthTokenLabel(authTokenType: String?): String? {
// Label for the auth token type
return null
}
override fun updateCredentials(response: AccountAuthenticatorResponse?, account: Account?, authTokenType: String?, options: Bundle?): Bundle? {
// Add your logic to update credentials
return null
}
override fun hasFeatures(response: AccountAuthenticatorResponse?, account: Account?, features: Array<out String>?): Bundle? {
// Add your logic to check for specific account features
return null
}
}

View File

@@ -0,0 +1,12 @@
package com.example.hpostesting.util
import android.app.Service
import android.content.Intent
import android.os.IBinder
class MyAuthenticatorService : Service() {
override fun onBind(intent: Intent?): IBinder? {
val authenticator = MyAuthenticator(this)
return authenticator.iBinder
}
}

View File

@@ -0,0 +1,33 @@
package com.example.hpostesting.util
import android.content.Context
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey
class SecureStorage(context: Context) {
private val masterKey = MasterKey.Builder(context)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build()
private val sharedPreferences = EncryptedSharedPreferences.create(
context,
"secure_prefs",
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
fun storePassword(password: String) {
sharedPreferences.edit().putString("shared_password", password).apply()
}
fun storeAdminPassword(password: String) {
sharedPreferences.edit().putString("admin_password", password).apply()
}
fun getAdminPassword(): String? {
return sharedPreferences.getString("admin_password", null)
}
fun getPassword(): String? {
return sharedPreferences.getString("shared_password", null)
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

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:autoMirrored="true" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M2.01,21L23,12 2.01,3 2,10l15,2 -15,2z"/>
</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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 828 KiB

View File

@@ -23,18 +23,18 @@
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"/>-->
<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_device"

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

@@ -17,7 +17,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".presentation.KitScanActivity">
>
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar_layout"
@@ -45,6 +45,7 @@
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:text="@string/scan_qr_code_of_the_kit"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/app_bar_layout" />
@@ -58,6 +59,7 @@
android:textColor="@color/black"
app:backgroundTint="@color/blue_app_light"
app:cornerRadius="100dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_title" />
@@ -128,7 +130,7 @@
android:id="@+id/name_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLength="17"
android:maxLength="27"
android:inputType="text"
android:hint="@string/serial_number" />

View File

@@ -92,6 +92,7 @@
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
app:cardElevation="8dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@+id/cv_item1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/cv_item1"
@@ -132,6 +133,7 @@
android:id="@+id/cv_item3"
android:layout_width="128dp"
android:layout_height="128dp"
android:visibility="gone"
android:layout_marginTop="32dp"
android:layout_marginStart="16dp"
app:cardElevation="8dp"
@@ -178,6 +180,7 @@
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
app:cardElevation="8dp"
android:visibility="gone"
app:layout_constraintTop_toTopOf="@id/cv_item3"
app:layout_constraintBottom_toBottomOf="@id/cv_item3"
app:layout_constraintStart_toEndOf="@id/cv_item3"

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Reset Password"
android:textStyle="bold"
android:textColor="@color/black"
android:textSize="27sp"
android:layout_marginTop="15dp"/>
<EditText
android:id="@+id/editTextNewPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/black"
android:layout_marginTop="30dp"
android:textSize="20sp"
android:hint="Enter new password"
android:inputType="textPassword" />
<Button
android:id="@+id/buttonResetPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:textColor="@color/white"
android:text="Reset Password" />
</LinearLayout>

View File

@@ -0,0 +1,136 @@
<?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.diagnostics.DiagnosticsFragment">
<TextView
android:id="@+id/tv_subtitle2"
style="@style/title2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:textSize="20sp"
android:textColor="@color/black"
android:textStyle="bold"
android:text="Update values of ABS Limits"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="@+id/main_ll"
style="@style/title1_1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle2">
<EditText
android:id="@+id/et_2mmled1_ll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="2mm Led 1 lower limit"
android:inputType="numberDecimal" />
<EditText
android:id="@+id/et_2mmled1_ul"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:hint="2mm Led 1 upper limit"
android:inputType="numberDecimal" />
<EditText
android:id="@+id/et_2mmled2_ll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:hint="2mm Led 2 lower limit"
android:inputType="numberDecimal" />
<EditText
android:id="@+id/et_2mmled2_ul"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:hint="2mm Led 2 upper limit"
android:inputType="numberDecimal" />
<EditText
android:id="@+id/et_10mmled1_ll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:hint="10mm Led 1 lower limit"
android:inputType="numberDecimal" />
<EditText
android:id="@+id/et_10mmled1_ul"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:hint="10mm Led 1 upper limit"
android:inputType="numberDecimal" />
<EditText
android:id="@+id/et_10mmled2_ll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:hint="10mm Led 2 lower limit"
android:inputType="numberDecimal" />
<EditText
android:id="@+id/et_10mmled2_ul"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:hint="10mm Led 2 upper limit"
android:inputType="numberDecimal" />
</LinearLayout>
<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:gravity="center"
android:text="@string/submit"
android:textColor="@color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/main_ll" />
<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

@@ -11,6 +11,7 @@
~ // is strictly forbidden unless prior written permission is obtained
~ // from ShanMukha Innovations Pvt. Ltd.
-->
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
@@ -19,28 +20,29 @@
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="wrap_content">
<ImageView
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_gravity="center"
android:layout_marginTop="20dp"
android:src="@drawable/smi_logo"
android:contentDescription="@string/smi" />
<TextView
android:id="@+id/titleText"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/smi_desp"
android:layout_marginTop="12dp"
android:layout_marginEnd="12dp"
android:layout_marginStart="12dp"
android:textSize="18sp"
android:textColor="@color/black"
/>
android:orientation="vertical"
android:layout_height="wrap_content">
<ImageView
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_gravity="center"
android:layout_marginTop="20dp"
android:src="@drawable/smi_logo"
android:contentDescription="@string/smi" />
<TextView
android:id="@+id/titleText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/smi_desp"
android:layout_marginTop="12dp"
android:layout_marginEnd="12dp"
android:layout_marginStart="12dp"
android:textSize="18sp"
android:textColor="@color/black"
/>
<TextView
android:id="@+id/link_click"
android:clickable="true"
@@ -54,4 +56,4 @@
android:textColor="@color/red"
android:focusable="true" />
</LinearLayout>
</ScrollView>
</ScrollView>

View File

@@ -38,7 +38,9 @@
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:text="@string/auto_dac"
android:textSize="22sp"
android:textStyle="bold"
android:text="@string/calibrate_device"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@@ -63,9 +65,10 @@
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:gravity="center"
android:scrollbars="vertical"
android:text="Start"
android:textColor="@color/black"
android:textSize="11sp"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle3" />
@@ -79,7 +82,7 @@
android:layout_marginTop="24dp"
android:clickable="false"
android:gravity="center"
android:text="Start Auto DAC"
android:text="@string/calibrate_device"
android:textColor="@color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
@@ -93,6 +96,7 @@
android:layout_marginTop="24dp"
android:clickable="false"
android:gravity="center"
android:visibility="gone"
android:text="Read Current DAC Values"
android:textColor="@color/white"
app:layout_constraintEnd_toEndOf="parent"

View File

@@ -38,7 +38,7 @@
style="@style/title1_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:layout_marginTop="100dp"
android:gravity="center"
android:text="Start"
android:textColor="@color/black"

View File

@@ -81,7 +81,6 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle4"/>
<Button
android:id="@+id/btn_submit"
android:layout_width="wrap_content"
@@ -90,7 +89,7 @@
android:layout_marginTop="24dp"
android:clickable="false"
android:gravity="center"
android:text="Start"
android:text="@string/start"
android:textColor="@color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"

View File

@@ -76,7 +76,7 @@
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:text="@string/auto_dac"
android:text="@string/calibrate_device"
android:textColor="@color/white"
app:cornerRadius="16dp"
app:layout_constraintEnd_toEndOf="parent"
@@ -140,6 +140,32 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_deviceInfo" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_reset_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:text="@string/reset_password_for_this_device"
android:textColor="@color/white"
app:cornerRadius="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_deviceProvision" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_update_values"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:text="Update values"
android:textColor="@color/white"
app:cornerRadius="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_reset_password" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_firefox"
android:layout_width="match_parent"
@@ -152,7 +178,7 @@
app:cornerRadius="16dp"
app:layout_constraintEnd_toEndOf="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
android:id="@+id/btn_files"

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

@@ -16,74 +16,78 @@
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.example.hpostesting.presentation.hemocube.HemoCubeFragment">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_parent"
android:layout_width="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
android:id="@+id/tv_title"
style="@style/title1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:text="@string/Instructions"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_parent"
android:layout_width="match_parent"
android:layout_height="match_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"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_title" />
<TextView
android:id="@+id/tv_title"
style="@style/title1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:text="@string/Instructions"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_name"
style="@style/title2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:gravity="center"
android:padding="12dp"
android:layout_marginTop="26dp"
android:textSize="14sp"
android:textFontWeight="700"
android:text="Name: SMI\n ID: 1672282828"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="MissingConstraints" />
<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"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_title" />
<!-- <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"-->
<!-- android:text="@string/step5"-->
<!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toBottomOf="@id/tv_subtitle2" />-->
<TextView
android:id="@+id/tv_name"
style="@style/title2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:gravity="center"
android:padding="12dp"
android:layout_marginTop="26dp"
android:textFontWeight="700"
android:text="Name: SMI\n ID: 1672282828"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="MissingConstraints" />
<TextView
android:id="@+id/tv_subtitle4"
style="@style/title1_1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="72dp"
android:gravity="center"
android:textColor="@color/red"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/et_abha_id" />
<TextView
android:id="@+id/tv_subtitle4"
style="@style/title1_1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="72dp"
android:gravity="center"
android:textColor="@color/red"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/et_abha_id" />
<!-- <Button-->
@@ -246,8 +250,10 @@
android:gravity="center"
android:text="no device message"
android:textColor="@color/black"
android:scrollbars="vertical"
android:textSize="11sp"
android:visibility="visible"
android:visibility="gone"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/ll_btns" />
@@ -265,14 +271,25 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/error_message" />
<ImageView
<pl.droidsonroids.gif.GifImageView
android:id="@+id/testing"
android:visibility="gone"
android:layout_width="180dp"
android:layout_height="150dp"
android:layout_marginTop="10dp"
android:importantForAccessibility="no"
android:src="@drawable/virtual_lab"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_device_messages" />
<pl.droidsonroids.gif.GifImageView
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"
android:src="@drawable/verified"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_device_messages" />

Some files were not shown because too many files have changed in this diff Show More