Compare commits

..

123 Commits

Author SHA1 Message Date
Sathwik C S
b70c129b1b Edit README.md 2025-08-17 12:18:15 +05:30
Sathwik C S
a9e7d2e6e6 Edit README.md 2025-08-07 12:19:39 +05:30
Sathwik
dd887802bc updated settings, and report gen 2025-08-06 17:04:08 +05:30
Sathwik
92f426d7be auto smbt button now only shows up on admin mode 2025-07-29 15:51:19 +05:30
Sathwik
7a0064a0d3 Updted the string, added the sutosmbt button in settings 2025-07-28 16:50:44 +05:30
Sathwik
669cf00d60 added print option in panels, created , activity fragment , and viewmodel , added the xml views and cards 2025-07-24 11:31:47 +05:30
Sathwik
00b341169d Merge remote-tracking branch 'origin/dev-server-2.1.134-with-printer' into dev-server-2.1.134-with-printer 2025-07-24 11:24:42 +05:30
sathwik
4293e87f07 added print option in panels, created , activity fragment , and viewmodel , added the xml views and cards 2025-07-24 11:24:22 +05:30
sathwik
05ce1d8411 added print option in panels, created , activity fragment , and viewmodel , added the xml views and cards 2025-07-16 18:21:12 +05:30
sathwik
b6ae754f1b updated the uto manifest 2025-07-16 18:17:21 +05:30
sathwik
c3acb41590 updated the uto sumbit 2025-07-15 14:57:19 +05:30
sathwik
2ee6b65ca5 implementing the secure storage using ndk 2025-07-08 11:25:04 +05:30
sathwik
28b8409207 implementing the secure storage using ndk 2025-07-01 16:27:55 +05:30
sathwik
5c56ef7630 implementing the secure storage using ndk 2025-07-01 16:27:30 +05:30
sathwik
2fbc280b4a implementing the secure storage 2025-06-19 11:58:47 +05:30
sathwikcs
e9c8a9a887 R&D app 2025-05-15 19:04:23 +05:30
sathwikcs
e7ecf7eedf R&D app 2025-05-15 12:57:53 +05:30
sathwikcs
e3435f2182 131-STABLE-super-server 2025-03-13 15:50:04 +05:30
sathwikcs
f6cdd64ef6 131-STABLE-super-server 2025-03-13 15:49:25 +05:30
sathwikcs
7ad21ea5a9 131-STABLE-super-server 2025-03-13 15:23:15 +05:30
sathwikcs
6c89efeb5e 131-STABLE-smi... 2025-03-13 14:08:04 +05:30
sathwikcs
63eaf1cadc Merge remote-tracking branch 'origin/dev-server-2.1.131-stable-smi' into dev-server-2.1.131-stable-smi 2025-03-13 12:45:23 +05:30
sathwikcs
c180f7be31 131-STABLE-smi... 2025-03-13 12:45:04 +05:30
sathwikcs
c243ec6c8f 131-STABLE-smi... 2025-03-13 12:37:23 +05:30
sathwikcs
7c9238591b 131-STABLE-molbio 2025-03-04 13:36:33 +05:30
sathwikcs
5c843ca232 131-STABLE 2025-03-03 14:55:41 +05:30
sathwikcs
736dff2b11 Fixed the issue where dialogue is showing wrong 2025-02-20 18:23:10 +05:30
sathwikcs
20dd1e41eb Fixed the issue where app wil crash when switched to pre pod 2025-02-19 18:41:11 +05:30
sathwikcs
ad6670a1e8 Merge remote-tracking branch 'origin/dev-server-2.1.132' into dev-server-2.1.132 2025-02-19 15:42:43 +05:30
sathwikcs
e6f8ab69e9 Fixed the issue where app wil crash when switched to pre pod 2025-02-19 15:42:23 +05:30
Sathwik C S
ccd2138f66 Update file README.md 2025-02-18 09:31:30 +00:00
sathwikcs
d54436996d added dev icon 2025-02-18 14:53:36 +05:30
sathwikcs
52a555a63a Changes in josn - default : prod 2025-02-18 14:53:14 +05:30
sathwikcs
8e80cfe525 SettingsFragment.kt 2025-02-18 14:52:02 +05:30
sathwikcs
f26f54e51d Added the developer shared pref 2025-02-18 14:51:31 +05:30
sathwikcs
1d029b8ff8 removed the selector drop down 2025-02-18 14:50:40 +05:30
sathwikcs
c88efd148b App version Tap manager 2025-02-18 14:50:08 +05:30
sathwikcs
cb27983d21 NetworkStatusLiveData.kt has been removed 2025-02-17 12:38:11 +05:30
Sathwik C S
0b268dda47 Edit README.md 2025-01-29 11:02:47 +00:00
Sathwik C S
d9777edf02 Edit README.md 2025-01-29 11:01:52 +00:00
sathwikcs
238424ad89 NetworkStatusLiveData.kt has been removed 2025-01-29 15:39:47 +05:30
sathwikcs
c1f02c878c updated the NetworkChecker.kt 2025-01-29 15:39:29 +05:30
sathwikcs
b344dbcb69 updated the test case 2025-01-28 17:12:06 +05:30
sathwikcs
af7b426416 Merge remote-tracking branch 'origin/dev-server-2.1.131-network' into dev-server-2.1.131-network 2025-01-28 16:12:21 +05:30
sathwikcs
07abfcce6c updated build.gradle to make the api 31 as the min sdk from 21 -> 30 as device targets api 31 2025-01-28 16:12:00 +05:30
sathwikcs
2c62cc11ba updated build.gradle to make the api 31 as the min sdk from 21 -> 30 as device targets api 31 2025-01-28 16:11:42 +05:30
sathwikcs
312e2da79a TrueHemeViewmodel to fit new network Checker 2025-01-28 16:10:40 +05:30
sathwikcs
9768a0a835 updated TrueHeme TestViewmodel.kt NetworkChecker.kt 2025-01-28 16:08:29 +05:30
sathwikcs
db7aba4549 updated NetworkChecker.kt 2025-01-28 16:07:27 +05:30
sathwikcs
302239d191 Network Checker updated in TestRightViewModel 2025-01-28 12:50:14 +05:30
sathwikcs
cc1ae1ff82 Network Checker updated in NetworkStatusLiveData.kt 2025-01-28 12:49:06 +05:30
sathwikcs
d420a42fcc Network Checker 2025-01-28 12:47:39 +05:30
sathwikcs
21b3960ca9 Merge remote-tracking branch 'origin/dev-server-2.1.130-review-retryUsb' into dev-server-2.1.130-review-retryUsb 2025-01-22 15:00:55 +05:30
chandrashekhar reddy
9183216cfe app version 131, remote config removed,default classification values updated 2025-01-17 17:27:50 +05:30
chandrashekhar reddy
a72bd3d59e app version 130.2, default remote config values updated 2025-01-13 16:49:21 +05:30
chandrashekhar reddy
54be3a1037 app version 130.1, without borderline classification and buffer limit 2024-12-31 15:10:53 +05:30
chandrashekhar reddy
69055b5498 app version 130, without borderline classification 2024-12-30 12:00:39 +05:30
chandrashekhar reddy
7dde6bf976 app version 130, without borderline classification 2024-12-30 11:42:04 +05:30
chandrashekhar reddy
ee0f1d748a Merge remote-tracking branch 'origin/dev-server-2.1.130' into dev-server-2.1.130 2024-12-30 11:36:57 +05:30
chandrashekhar reddy
d32e7b6cbb app version 130, without borderline classification 2024-12-30 11:36:08 +05:30
Chandrashekhar Reddy
d306d0b9fa Update .gitlab-ci.yml file 2024-10-16 09:23:33 +00:00
chandrashekhar reddy
8e074e01c9 rename of the branch 2024-10-15 15:56:03 +05:30
chandrashekhar reddy
6b0c81213e rename of the branch 2024-10-15 15:04:39 +05:30
sathwikcs
51480393da optimised the unnecessary code in json
added sever info in home fragment
removed basic data test
2024-10-09 16:55:44 +05:30
chandrashekhar reddy
d9221a3bb6 Submit button check in HemoCubeFragment 2024-10-09 15:06:05 +05:30
sathwikcs
569155d193 Server switching is implemented
pipeline fixed
version 2.1.128
2024-10-08 17:19:38 +05:30
sathwikcs
ad029e4cce Server switching is implemented
version 2.1.128
2024-10-08 17:03:32 +05:30
sathwikcs
31654be3bb Server switching is implemented
version 2.1.128
2024-10-08 16:53:44 +05:30
sathwikcs
738375afc5 Server switching is implemented
version 2.1.128
2024-10-08 16:44:43 +05:30
chandrashekhar reddy
e77b4d9a23 Changes in 127, added HBTest screen option 2024-09-17 12:47:53 +05:30
chandrashekhar reddy
cf429b4fc3 Changes in 127, added HBTest screen option 2024-09-11 17:11:53 +05:30
chandrashekhar reddy
30df9732a7 127 version with all updates, credential.txt file location changed, Ui updated. 2024-09-10 11:43:48 +05:30
chandrashekhar reddy
a1ce200ad8 127 version with all updates, credential.txt file location changed, Ui updated. 2024-09-10 11:37:00 +05:30
chandrashekhar reddy
2512556e8a 127 version, pipeline fixed 2024-08-24 11:24:16 +05:30
chandrashekhar reddy
4c1429f3cb 127 version, updated the normal threshold 2024-08-22 18:59:25 +05:30
chandrashekhar reddy
d0f33582df 127 version, updated the normal threshold 2024-08-22 18:57:23 +05:30
chandrashekhar reddy
6be6a65e95 127 version, refresh buffer separated, added buffer flag, added remote config to manage threshold, remove cards direct test can be performed 2024-08-09 12:02:13 +05:30
chandrashekhar reddy
b32c5e29d0 127 version, refresh buffer separated, added buffer flag, added remote config to manage threshold 2024-08-03 22:33:34 +05:30
chandrashekhar reddy
453af33baa 125 version, net kit button issue resolved 2024-07-25 12:49:54 +05:30
chandrashekhar reddy
dd345a1b31 new 125 version, changes in HemoCubeFragment Ip address in home, led1Average at line 1004 change if condition, in home download csv for all. 2024-07-15 20:29:39 +05:30
chandrashekhar reddy
ba52efc670 new 125 version, changes in HemoCubeFragment Ip address in home, led1Average at line 1004 change if condition, in home download csv for all. 2024-07-15 15:15:58 +05:30
chandrashekhar reddy
eb60025add new 125 version, changes in HemoCubeFragment Ip address in home, led1Average at line 1004 change if condition, in home download csv for all. 2024-07-15 15:07:42 +05:30
chandrashekhar reddy
5e1283873d new 125 version, changes in HemoCubeFragment Ip address in home, led1Average at line 1004 change if condition, in home download csv for all. 2024-07-15 14:44:19 +05:30
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
chandrashekhar reddy
31e92a0cbb HemoCubeFragment changes in device ratio and borderline metric 2024-03-30 13:45:47 +05:30
chandrashekhar reddy
96ba5ce92f HomeFragment network change edited 2024-03-28 16:32:21 +05:30
chandrashekhar reddy
0635cb6813 Location fetch code added in login fragment without gps 2024-03-27 15:13:37 +05:30
chandrashekhar reddy
326936fc26 Merge remote-tracking branch 'origin/dev' into dev
# Conflicts:
#	app/src/main/java/com/example/hpostesting/data/constant/Constants.kt
#	app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt
2024-03-27 15:12:57 +05:30
chandrashekhar reddy
da195ab573 Location fetch code added in login fragment without gps 2024-03-27 15:10:06 +05:30
Mariya
47f586ff63 Merge remote-tracking branch 'origin/dev' into dev
# Conflicts:
#	app/src/main/res/values-hi/strings.xml
#	app/src/main/res/values-kn/strings.xml
#	app/src/main/res/values/strings.xml
2024-03-26 12:32:30 +05:30
Mariya
9c22bdabf9 Lab Name is Added inside the settings screen, and added for molbio login request 2024-03-26 12:30:51 +05:30
chandrashekhar reddy
0a103795cd About screen added in drawer 2024-03-25 17:12:24 +05:30
Mariya
541b555c05 Panel screen specific options will only visible to ADMIN only 2024-03-23 17:22:32 +05:30
Mariya
d14afa0942 Merge remote-tracking branch 'origin/dev-usb-terminal-inapp' into dev 2024-03-23 17:02:12 +05:30
Mariya
71a364a9a2 csv file downloading changes added 2024-03-23 15:29:40 +05:30
Mariya
9aa89f810e error fixing 2024-03-23 12:21:49 +05:30
chandrashekhar reddy
262c3c19d2 new changes in UsbTerminalActivity 2024-03-22 15:47:47 +05:30
Mariya
12af81d142 error fixing 2024-03-22 15:16:09 +05:30
Mariya
29115786fa changed reverted back for csv option for ADMIN 2024-03-21 20:53:48 +05:30
Mariya
614192c04c Revert "changes made for dropdownlist for pq , for iocl 122 version added, for E command , RS AND RC changed to ES and EC"
This reverts commit 4fe1a0e187.
2024-03-20 18:04:22 +05:30
135 changed files with 8131 additions and 2038 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
@@ -98,4 +125,4 @@ publishTestResults:
artifacts:
when: always
reports:
junit: app/build/test-results/testDebugUnitTest/*.xml
junit: app/build/test-results/testDebugUnitTest/*.xml

View File

@@ -1,4 +1,23 @@
# Latest hpos app version
### current version : 2.1.133
### Release key
key0: prime24
#### **Change logs :**
- [✅] Auto Sumbmit
- [✅] Auto Sumbmit Toggle
- [✅] Genegrate report
- [✅] Report Selector
- [✅] Report Printer
- [✅] Report Disclaimer Editor
#### **Completed 👌**
**version of android studio used**
`Android Studio Koala Feature Drop | 2024.1.2 Patch 1`

View File

@@ -7,6 +7,7 @@ plugins {
id 'androidx.navigation.safeargs.kotlin'
id 'kotlin-kapt'
id 'com.google.firebase.crashlytics'
id 'kotlin-parcelize'
}
//apply plugin: 'kotlin-android'
@@ -15,14 +16,19 @@ 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.iocl"
minSdk 21
applicationId "in.sminnovations.hpostesting.server"
minSdk 30
targetSdk 34
versionCode 122
versionName "2.1.122"
versionCode 139
versionName "2.1.133"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags ''
}
}
}
@@ -30,6 +36,7 @@ android {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.debug
}
}
compileOptions {
@@ -53,6 +60,12 @@ android {
packagingOptions {
exclude 'mockito-extensions/org.mockito.plugins.MockMaker'
}
externalNativeBuild {
cmake {
path file('src/main/cpp/CMakeLists.txt')
version '3.22.1'
}
}
// testOptions {
// unitTests {
// includeAndroidResources = true
@@ -62,6 +75,7 @@ android {
dependencies {
implementation "com.google.dagger:hilt-android:2.46"
implementation 'androidx.activity:activity:1.8.0'
kapt "com.google.dagger:hilt-android-compiler:2.46"
implementation 'androidx.core:core-ktx:1.12.0'
@@ -88,7 +102,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'
@@ -120,10 +133,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'
@@ -137,6 +149,7 @@ dependencies {
implementation "androidx.room:room-ktx:2.6.1"
implementation "androidx.room:room-runtime:2.6.1"
kapt ("androidx.room:room-compiler:2.6.1")
implementation "net.zetetic:android-database-sqlcipher:4.4.0"
//image
implementation 'com.github.bumptech.glide:glide:4.13.2'
@@ -162,9 +175,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

@@ -1,26 +1,36 @@
{
"project_info": {
"project_number": "630821402019",
"project_id": "iocl-iisc",
"storage_bucket": "iocl-iisc.appspot.com"
"project_number": "1012719870714",
"project_id": "hpos-prod",
"storage_bucket": "hpos-prod.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:630821402019:android:ed56bae066ac32b51dd616",
"mobilesdk_app_id": "1:1012719870714:android:d8d7c962d96f4097de5f43",
"android_client_info": {
"package_name": "in.sminnovations.hpostesting.iocl"
"package_name": "in.sminnovations.hpostesting.server"
}
},
"oauth_client": [],
"oauth_client": [
{
"client_id": "1012719870714-uli6cdjea3lfnnueh6e4r15i10ei1vlj.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyABIdxI89eTZ8BqU2cIoJOgJ1lS1cFLCtQ"
"current_key": "AIzaSyA_O0oZGzy3Kiw9fiLQ3OFPME-xQJP88vs"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": []
"other_platform_oauth_client": [
{
"client_id": "1012719870714-uli6cdjea3lfnnueh6e4r15i10ei1vlj.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
}

View File

@@ -1,20 +0,0 @@
{
"version": 3,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "in.sminnovations.hpostesting.quality",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 101,
"versionName": "2.1.101",
"outputFile": "app-release.apk"
}
],
"elementType": "File"
}

View File

@@ -1,25 +1,14 @@
<?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.
-->
<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" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission
android:name="android.permission.BATTERY_STATS"
tools:ignore="ProtectedPermissions" />
@@ -35,36 +24,75 @@
<uses-feature android:name="android.hardware.usb.host" />
<uses-permission android:name="android.permission.USB_PERMISSION" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission
android:name="android.permission.ACCOUNT_MANAGER"
tools:ignore="ProtectedPermissions" />
<application
android:name="com.example.hpostesting.HPOSTestingApplication"
android:largeHeap="true"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/hpos_icon"
android:label="@string/app_name"
android:largeHeap="true"
android:roundIcon="@mipmap/hpos_icon_round"
android:supportsRtl="true"
android:theme="@style/Theme.HPOSTesting"
tools:targetApi="31">
<activity
android:name="com.example.hpostesting.presentation.deviceinfo.DeviceActivity"
android:name="com.example.hpostesting.presentation.reportgen.ReportActivity"
android:exported="false" />
<activity
android:name="com.example.hpostesting.presentation.hemocube.DigitalCardActivity"
android:name="com.example.hpostesting.presentation.main_base.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.main_base.ui.PasswordResetActivity"
android:exported="false"
android:screenOrientation="portrait" />
<activity
android:name="com.example.hpostesting.presentation.usb_teminal.UsbTerminalActivity"
android:exported="false"
android:screenOrientation="portrait" />
<activity
android:name="com.example.hpostesting.presentation.deviceinfo.DeviceActivity"
android:exported="false"
android:theme="@style/Theme.HPOS.NoActionBar" />
<activity
android:name="com.example.hpostesting.presentation.trueheme_test.DigitalCardActivity"
android:exported="false" />
<activity
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"
android:theme="@style/Theme.HPOS.NoActionBar" />
<activity
android:name="com.example.hpostesting.presentation.jig.JigActivity"
android:exported="false"
android:exported="true"
android:theme="@style/Theme.HPOS.NoActionBar" />
<activity
android:name="com.example.hpostesting.presentation.deviceprovision.DeviceProvisionActivity"
@@ -73,23 +101,20 @@
<activity
android:name="com.example.hpostesting.presentation.calibration.CalibrationActivity"
android:exported="false"
android:theme="@style/Theme.HPOS.NoActionBar"/>
android:theme="@style/Theme.HPOS.NoActionBar" />
<activity
android:name="com.example.hpostesting.presentation.assurance.AssuranceControlsActivity"
android:exported="false"
android:screenOrientation="portrait"
android:theme="@style/Theme.HPOS.NoActionBar"/>
android:theme="@style/Theme.HPOS.NoActionBar" />
<activity
android:name="com.example.hpostesting.presentation.hemocube.HemocubeActivity"
android:name="com.example.hpostesting.presentation.trueheme_test.TrueHemeTestActivity"
android:exported="false"
android:noHistory="true"
android:screenOrientation="portrait"
android:parentActivityName="com.example.hpostesting.presentation.MainActivity"
android:screenOrientation="portrait"
android:theme="@style/Theme.HPOS.NoActionBar"
android:windowSoftInputMode="adjustPan" />
<activity
android:name="com.example.hpostesting.presentation.trueheme.TrueHemeActivity"
android:exported="false"
@@ -97,7 +122,6 @@
android:parentActivityName="com.example.hpostesting.presentation.MainActivity"
android:theme="@style/Theme.HPOS.NoActionBar"
android:windowSoftInputMode="adjustPan" />
<activity
android:name="com.example.hpostesting.presentation.buffercheck.HemocubeBufferCheckActivity"
android:exported="false"
@@ -111,23 +135,23 @@
android:noHistory="true"
android:theme="@style/Theme.HPOS.NoActionBar" />
<activity
android:name="com.example.hpostesting.presentation.dashboard.DashboardActivity"
android:exported="false"
android:name="com.example.hpostesting.presentation.main_base.DashboardActivity"
android:exported="true"
android:label="@string/title_activity_dashboard"
android:theme="@style/Theme.HPOS.NoActionBar"
android:screenOrientation="portrait"
android:theme="@style/Theme.HPOS.NoActionBar"
tools:ignore="AppLinkUrlError,MissingClass">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="content" />
<data android:scheme="file" />
<data android:mimeType="application/vnd.android.package-archive" />
</intent-filter>
</activity>
<service
android:name="com.example.hpostesting.util.UsbService"
android:enabled="true"
@@ -138,22 +162,23 @@
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.LAUNCHER"/>-->
<!-- </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.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.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.example.hpostesting.presentation.testRight.TestRightActivity"
android:exported="false"
android:exported="true"
android:noHistory="true"
android:parentActivityName="com.example.hpostesting.presentation.MainActivity"
android:theme="@style/Theme.HPOS.NoActionBar"
@@ -185,8 +210,7 @@
android:name="com.journeyapps.barcodescanner.CaptureActivity"
android:screenOrientation="portrait"
android:stateNotNeeded="true"
tools:replace="android:screenOrientation" />
<!-- ${applicationId}-->
tools:replace="android:screenOrientation" /> <!-- ${applicationId} -->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
@@ -196,7 +220,6 @@
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
</manifest>

View File

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

View File

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

View File

@@ -0,0 +1,254 @@
package com.example.hpostesting.FHIRFormater
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.UserData
import org.json.JSONArray
import org.json.JSONObject
class RecommendedFHIRConverter {
private fun createPatient(data: HemoCubeTestData, useStandardCodes: Boolean): JSONObject {
val patient = JSONObject()
patient.put("resourceType", "Patient")
patient.put("id", "patient-${data.sampleid}")
// Structured name
val nameArray = JSONArray()
val nameObj = JSONObject()
nameObj.put("use", "official")
nameObj.put("text", data.name)
nameArray.put(nameObj)
patient.put("name", nameArray)
// Gender (FHIR uses "male", "female", "other", "unknown")
patient.put("gender", data.gender.lowercase())
// Birth date estimation from age (optional: validate or remove if unknown)
val birthYear = try {
2025 - data.age.toInt()
} catch (e: Exception) {
null
}
if (birthYear != null) patient.put("birthDate", "$birthYear-01-01")
// ABHA ID as identifier
if (data.abhaId.isNotBlank()) {
val identifiers = JSONArray()
val identifier = JSONObject()
identifier.put("system", "https://healthid.ndhm.gov.in")
identifier.put("value", data.abhaId)
identifiers.put(identifier)
patient.put("identifier", identifiers)
}
return patient
}
private fun createDevice(data: HemoCubeTestData): JSONObject {
val device = JSONObject()
device.put("resourceType", "Device")
device.put("id", "device-${data.deviceSerialNumber}")
device.put("serialNumber", data.deviceSerialNumber)
// Device type as codeable concept
val type = JSONObject()
type.put("text", data.deviceType)
device.put("type", type)
// Device version
if (!data.appVersion.isNullOrBlank()) {
val versions = JSONArray()
val version = JSONObject()
version.put("type", JSONObject().put("text", "appVersion"))
version.put("value", data.appVersion)
versions.put(version)
device.put("version", versions)
}
return device
}
private fun createHemoglobinObservation(data: HemoCubeTestData, useStandardCodes: Boolean): JSONObject {
val observation = JSONObject()
observation.put("resourceType", "Observation")
observation.put("id", "hemoglobin-${data.sampleid}")
observation.put("status", if (data.testStatus == true) "final" else "preliminary")
// Standard LOINC code or fallback
val code = JSONObject()
val codingArray = JSONArray()
if (useStandardCodes) {
val coding = JSONObject()
coding.put("system", "http://loinc.org")
coding.put("code", "718-7") // LOINC for Hemoglobin [Mass/volume] in Blood
coding.put("display", "Hemoglobin [Mass/volume] in Blood")
codingArray.put(coding)
}
code.put("coding", codingArray)
code.put("text", "Hemoglobin Analysis")
observation.put("code", code)
// Subject reference to patient
observation.put("subject", JSONObject().put("reference", "Patient/patient-${data.sampleid}"))
// Device reference
observation.put("device", JSONObject().put("reference", "Device/device-${data.deviceSerialNumber}"))
// Time of observation
if (!data.testTime.isNullOrBlank()) {
observation.put("effectiveDateTime", data.testTime)
}
// Main result: if hb3 or hb4 exists, use as value
val hbValue = data.hb3 ?: data.hb4
if (hbValue != null) {
val valueQuantity = JSONObject()
valueQuantity.put("value", hbValue)
valueQuantity.put("unit", "g/dL")
valueQuantity.put("system", "http://unitsofmeasure.org")
valueQuantity.put("code", "g/dL")
observation.put("valueQuantity", valueQuantity)
}
// Optional extensions
val components = JSONArray()
fun addComponent(codeText: String, value: Double?) {
if (value != null) {
val comp = JSONObject()
comp.put("code", JSONObject().put("text", codeText))
comp.put("valueQuantity", JSONObject().put("value", value))
components.put(comp)
}
}
addComponent("HB3", data.hb3)
addComponent("HB4", data.hb4)
addComponent("Device Ratio", data.deviceRatio)
addComponent("Blood Group", null) // can't use non-numeric here unless coded properly
if (components.length() > 0) {
observation.put("component", components)
}
return observation
}
private fun createBundleEntry(resource: JSONObject): JSONObject {
val entry = JSONObject()
entry.put("fullUrl", "urn:uuid:${resource.getString("id")}")
entry.put("resource", resource)
entry.put("request", JSONObject().apply {
put("method", "POST")
put("url", resource.getString("resourceType"))
})
return entry
}
fun convertToFHIR(data: HemoCubeTestData, useStandardCodes: Boolean = false): String {
val bundle = JSONObject()
bundle.put("resourceType", "Bundle")
bundle.put("id", "hemocube-test-${data.sampleid}")
bundle.put("type", "collection")
val entries = JSONArray()
entries.put(createBundleEntry(createPatient(data, useStandardCodes)))
entries.put(createBundleEntry(createDevice(data)))
entries.put(createBundleEntry(createHemoglobinObservation(data, useStandardCodes)))
bundle.put("entry", entries)
return bundle.toString(2)
}
}
fun sus() {
val sampleData = HemoCubeTestData(
sampleid = 1234,
_id = "local-001",
name = "John Doe",
incubationTime = "15",
bloodGroup = "B+",
age = "30",
state = "Karnataka",
abhaId = "29-1234-4567",
userImageURL = "https://example.com/user.jpg",
location = UserData.Location(latitude = 12.9716, longitude = 77.5946),
reportUploadTime = "2025-07-15T09:30:00+05:30",
testType = "HEMOCUBE",
testTime = "2025-07-15T09:15:00+05:30",
testStatus = true,
gender = "male",
localFlag = true,
deviceId = "device-5678",
appVersion = "1.4.2",
deviceSerialNumber = "SN-001-XY",
deviceType = "HEMOCUBE",
kitSerial = "KIT-20250715",
resultData = "Raw data goes here",
led1Buffer = 0.123,
led2Buffer = 0.456,
led3Buffer = 0.789,
led4Buffer = 0.321,
led1Sample = 0.654,
led2Sample = 0.987,
led3Sample = 0.432,
led4Sample = 0.210,
led1Average = 0.300,
led2Average = 0.500,
led3Average = 0.400,
led4Average = 0.450,
abs1 = 0.12,
abs2 = 0.23,
abs3 = 0.34,
abs4 = 0.45,
hb3 = 13.5,
hb4 = 13.7,
led1Gain1 = 1.1,
led2Gain1 = 1.2,
led3Gain1 = 1.3,
led4Gain1 = 1.4,
deviceRatio = 0.87,
calculatedRatio = 0.89,
predictedDenovixRatio = 0.91,
slopeRatio = 0.93,
coefficients = "a=1.0,b=2.0,c=3.0",
classificationResult = "Normal",
prdClassification = "PRD1",
deviceRatioClass = "A",
slopeRatioClass = "B",
borderlineMethod2Class = "C",
errorMessages = "",
batteryLevel = "85%",
batteryCapacity = "2800mAh",
batteryMaxCapacity = "3000mAh",
batteryTemperature = "35C",
batteryVoltage = "3.7V",
molbioFlag = false,
quickCapture = false,
solution = "Blood Sample",
concentration = "13.5g/dL",
filter = "None",
volume = "20uL",
isCSVCreated = true,
labName = "ABC Labs",
cuvetteSize = "Standard",
district = "Bangalore Urban",
centerName = "Health Center 1",
ipAddress = "192.168.1.101",
configUpdatedRecent = "true"
)
val converter = RecommendedFHIRConverter()
val standardFhir = converter.convertToFHIR(sampleData, useStandardCodes = true)
println("FHIR Bundle Output:\n$standardFhir")
}

View File

@@ -14,25 +14,37 @@
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)
companion object {
init {
System.loadLibrary("native-server")
}
}
@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.getCurrentFirestore()
firestore.firestoreSettings = firestoreSettings
}
}

View File

@@ -23,6 +23,7 @@ import com.example.hpostesting.data.model.updates.CheckUpdateResponse
import com.example.hpostesting.data.model.updates.DeviceUpdateRequest
import okhttp3.MultipartBody
import okhttp3.ResponseBody
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.Multipart
@@ -31,7 +32,6 @@ import retrofit2.http.PUT
import retrofit2.http.Part
interface MolbioResultApi {
@PUT("deviceService/results/HPOS")
suspend fun uploadResults(
@Body molbioV2ResultRequest: MolbioV2ResultRequest,
@@ -42,10 +42,15 @@ interface MolbioResultApi {
@Body checkUpdateRequest: CheckUpdateRequest,
): CheckUpdateResponse
// @POST("deviceService/device/getUpdate")
// suspend fun deviceUpdate(
// @Body deviceUpdateRequest: DeviceUpdateRequest,
// ): ResponseBody
@POST("deviceService/device/getUpdate")
suspend fun deviceUpdate(
@Body deviceUpdateRequest: DeviceUpdateRequest,
): ResponseBody
): Response<ResponseBody>
@GET("deviceService/device/getClientCertificate")
suspend fun downloadClientCertificate(
@@ -57,7 +62,6 @@ interface MolbioResultApi {
@Part logFile: MultipartBody.Part,
): UploadLogsResponse
@PUT("deviceService/device/uploadDeviceDiagnostics")
suspend fun deviceDiagnostics(
@Body deviceDiagnosticsRequest: DeviceDiagnosticsRequest

View File

@@ -14,14 +14,22 @@
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"
const val BASE_URL = "www.google.com"
const val DOCUMENT_ID_FOR_UPDATE ="2o71vBKLqdgEKYtFG8Lb"
const val ABHA_APP_PACKAGE = "in.ndhm.phr"
const val MOLBIO_INTEGRATION = true
var MOLBIO_INTEGRATION = true
var FIREBASE_INTEGRATION = false
const val deviceProvisionEmail = "HPOS_provisioner@bigtec.co.in"
const val deviceProvisionPassword = "f2ab0e7f9d69"
const val DEVICE_ID_API = "deviceIDAPI"
@@ -36,8 +44,9 @@ object Constants {
const val DELAY_BETWEEN_COMMANDS: Long = 1000
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 MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE10MM_RANDD= 129
const val RANGE_IN_RESULT_CALCULATIONS = 10
@@ -78,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"
@@ -259,7 +106,9 @@ object Constants {
const val BUFFER_VALUE_3 = "BufferValue3"
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 IS_TOKEN_AVAILABLE = "IS_TOKEN_AVAILABLE"
const val BUFFER_LED_LOWER_BOUND = 21000
const val BUFFER_LED_UPPER_BOUND = 23500
@@ -1236,7 +1085,8 @@ 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
@@ -1733,5 +1583,227 @@ object Constants {
listOf(0.0, 0.0)
)
)
//Trueheme for 10mm
//Before changing below values review before
//classification borderline metric
const val positiveBoderLineMetricCheck10mmMin = 1.3
const val positiveBoderLineMetricCheck10mmMax = 1.66
const val negativeBoderLineMetricCheck10mmMin = 2.0
const val negativeBoderLineMetricCheck10mmMax = 2.4
//classification device ratio
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 positiveBoderlineMin10mm = 0.31
const val positiveBoderlineMax10mm = 0.39
const val sickleCellDiseaseMin10mm = 0.39
const val sickleCellDiseaseMax10mm = 0.7
//Trueheme for 2mm
//classification borderline metric
const val positiveBoderLineMetricCheck2mmMin = 0.8
const val positiveBoderLineMetricCheck2mmMax = 1.1
const val negativeBoderLineMetricCheck2mmMin = 1.5
const val negativeBoderLineMetricCheck2mmMax = 1.9
//classification device ratio
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
//Check used in handling the buffer values on buffer complete
const val bufferMinLed1 = 21000.00
const val bufferMaxLed1 = 23000.00
const val bufferMinLed2 = 17000.00
const val bufferMaxLed2 = 19000.00
// 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",
// )
//
}

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,8 +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 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

@@ -26,10 +26,10 @@ interface HemoCubeDao {
@Query("SELECT * from hemo_cube_test_table")
fun getAll(): LiveData<List<HemoCubeTestData>>
@Query("SELECT * from hemo_cube_test_table WHERE molbioFlag=false")
@Query("SELECT * from hemo_cube_test_table WHERE molbioFlag=0")
fun getMolbioPending(): List<HemoCubeTestData>
@Query("SELECT * from hemo_cube_test_table WHERE localFlag=false")
@Query("SELECT * from hemo_cube_test_table WHERE localFlag=0")
fun getFirebasePending():List<HemoCubeTestData>
@Insert(onConflict = OnConflictStrategy.REPLACE)
@@ -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)
@@ -53,4 +54,8 @@ interface HemoCubeDao {
@Query("SELECT * from hemo_cube_test_table WHERE localFlag = 0")
fun getPendingUser(): LiveData<List<HemoCubeTestData>>
@Update
suspend fun updateTest(hemoCubeTestData: HemoCubeTestData)
}

View File

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

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

@@ -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,4 +106,10 @@ data class HemoCubeTestData(
var filter: String? = "",
var volume: String? = "",
var isCSVCreated: Boolean = false,
var labName: String? = "",
var cuvetteSize: String? = "",
var district: String? = "",
var centerName: String? = "",
var ipAddress:String?= "",
var configUpdatedRecent: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 = "",
@@ -43,6 +43,7 @@ data class UserData(
var result: TestRightResultType? = null,
var resultRatio: Double? = null,
var prdClassification: String = "",
var sampleid: Int = 0
) {
enum class Gender {
MALE,
@@ -59,8 +60,10 @@ data class UserData(
fun UserData.toHemoCubeTestData() = HemoCubeTestData(
_id = _id,
name = name,
sampleid = sampleid,
bloodGroup = bloodGroup,
birthYear = birthYear,
incubationTime = incubationTime,
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,6 +14,9 @@
package com.example.hpostesting.data.repository
import android.net.Uri
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import com.example.hpostesting.util.Result
import com.example.hpostesting.data.api.MolbioAuthApi
import com.example.hpostesting.data.api.MolbioResultApi
@@ -37,17 +40,18 @@ import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.data.model.updates.CheckUpdateRequest
import com.example.hpostesting.data.model.updates.CheckUpdateResponse
import com.example.hpostesting.data.model.updates.DeviceUpdateRequest
import com.example.hpostesting.firebase.FirebaseManager
import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.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 java.io.File
import java.net.ConnectException
import java.net.SocketTimeoutException
import java.time.LocalTime
import javax.inject.Inject
import javax.inject.Named
@@ -55,11 +59,30 @@ class NetworkException(message: String, cause: Throwable) : Exception(message, c
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.getCurrentFirestore()
private val localStg: FirebaseStorage
get() = firebaseManager.getCurrentStorage()
// // Example function to add data to Firestore , like the basic data as test data
// @RequiresApi(Build.VERSION_CODES.O)
// fun addtodb(data: String) {
// val date = LocalTime.now()
// localdb.collection("BasicData")
// .add(mapOf("data $date" to data))
// .addOnSuccessListener {
// Log.d("UPLOAD", "Data uploaded successfully ${localdb.app.name}")
// }
// .addOnFailureListener { exception ->
// Log.d("UPLOAD", "Failed to upload data: ${exception.message} ${localdb.app.name}")
// }
// }
private suspend fun <T : Any> safeApiCall(apiCall: suspend () -> T): Result<T> {
return try {
val response = apiCall.invoke()
@@ -89,8 +112,8 @@ class DatabaseRepository @Inject constructor(
return safeApiCall { molbioResultApi.checkUpdate(checkUpdateRequest) }
}
override suspend fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest): Result<ResponseBody> {
return safeApiCall { molbioResultApi.deviceUpdate(deviceUpdateRequest) }
override suspend fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest): retrofit2.Response<ResponseBody> {
return molbioResultApi.deviceUpdate(deviceUpdateRequest)
}
override suspend fun deviceDiagnostics(deviceDiagnosticsRequest: DeviceDiagnosticsRequest): Result<DeviceDiagnosticsResponse> {
@@ -108,18 +131,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")
@@ -127,7 +160,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)
@@ -137,7 +170,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)
@@ -145,9 +178,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)
@@ -161,7 +195,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) {
@@ -172,7 +206,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)
@@ -185,7 +219,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)
@@ -203,7 +237,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) {
@@ -213,11 +247,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
@@ -226,7 +260,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)
@@ -236,7 +270,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)
@@ -251,13 +285,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

@@ -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>
@@ -64,7 +65,7 @@ interface Repository {
suspend fun checkUpdate(checkUpdateRequest: CheckUpdateRequest): Result<CheckUpdateResponse>
suspend fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest): Result<ResponseBody>
suspend fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest): retrofit2.Response<ResponseBody>
suspend fun deviceDiagnostics(deviceDiagnosticsRequest: DeviceDiagnosticsRequest): Result<DeviceDiagnosticsResponse>
suspend fun downloadClientCertificate(): Result<ResponseBody>
suspend fun uploadLogs(logFile: MultipartBody.Part): Result<UploadLogsResponse>

View File

@@ -20,7 +20,7 @@ import android.content.res.AssetManager
import androidx.room.Room
import com.example.hpostesting.data.api.MolbioAuthApi
import com.example.hpostesting.data.api.MolbioResultApi
import com.example.hpostesting.util.PropertyProvider
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.dao.HemoCubeBufferDao
import com.example.hpostesting.data.dao.HemoCubeDao
import com.example.hpostesting.data.dao.MyDatabase
@@ -35,14 +35,21 @@ 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.NetworkMonitor
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
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import net.sqlcipher.database.SQLiteDatabase
import net.sqlcipher.database.SupportFactory
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
@@ -57,9 +64,12 @@ object AppModule {
@Provides
@Singleton
fun provideMyDatabase(@ApplicationContext context: Context): MyDatabase {
val passphraseBytes: ByteArray = SQLiteDatabase.getBytes(Constants.passphrase.toCharArray())
val factory = SupportFactory(passphraseBytes)
return Room.databaseBuilder(
context, MyDatabase::class.java, "my_database"
).fallbackToDestructiveMigration().build()
).openHelperFactory(factory).fallbackToDestructiveMigration().build()
}
@Provides
@@ -101,22 +111,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
@@ -200,4 +240,13 @@ object AppModule {
fun provideUsbServiceListener(context: Context): UsbServiceListener {
return UsbServiceListenerImpl(context)
}
@Provides
@Singleton
fun provideNetworkMonitor(
@ApplicationContext context: Context
): NetworkMonitor {
return NetworkMonitor(context).apply { startMonitoring() }
}
}

View File

@@ -0,0 +1,240 @@
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 android.util.Log
import androidx.core.content.edit
import com.example.hpostesting.data.constant.Constants
import com.google.firebase.FirebaseApp
import com.google.firebase.FirebaseOptions
import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.storage.FirebaseStorage
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import javax.inject.Inject
class FirebaseManager @Inject constructor(private val context: Context) {
private var defaultServers = mutableListOf<FirebaseConfig>()
external fun getFirebaseDataMap(): Map<String, Map<String, String>>
private val map: Map<String, Map<String, String>> = getFirebaseDataMap()
companion object {
init {
System.loadLibrary("native-server") //use NDK ro secure somethings
}
}
private val sharedPreferencesServerConfig = context.getSharedPreferences("FirebaseConfigPrefs", Context.MODE_PRIVATE)
private val sharedPreferencesDev = context.getSharedPreferences("DevMode",Context.MODE_PRIVATE)
private var currentFirestore: FirebaseFirestore = FirebaseFirestore.getInstance()
private var currentStorage: FirebaseStorage = FirebaseStorage.getInstance()
private var updateStatus = false
private fun Map<String, String>.toFirebaseConfig(server: String): FirebaseConfig? {
val apiKey = this["apiKey"] ?: return null
val appId = this["appId"] ?: return null
val projectId = this["projectId"] ?: return null
val storageBucket = this["storageBucket"] ?: return null
return FirebaseConfig(
serverName = server,
projectId = projectId,
appId = appId,
apiKey = apiKey,
storageBucket = storageBucket
)
}
fun populate() {
defaultServers.clear()
map.forEach { (server, config) ->
config.toFirebaseConfig(server)?.let {
defaultServers.add(it)
} ?: Log.w("Firebase", "Skipping $server due to missing keys")
}
}
init {
populate()
val lastSelectedServer = getLastSelectedServer()
switchServer(lastSelectedServer)
}
fun setDevModeOn(state : Boolean){
sharedPreferencesDev.edit {
putBoolean( "isDevModeOn",state )
}
}
fun getDevMode(): Boolean {
return sharedPreferencesDev.getBoolean("isDevModeOn",false)
}
fun getCurrentFirestore(): FirebaseFirestore = currentFirestore
fun getCurrentStorage(): FirebaseStorage = currentStorage
fun switchServer(firebaseConfig: FirebaseConfig) {
if (firebaseConfig.serverName =="molbio" ||firebaseConfig.apiKey == "molbio"){
saveSelectedServer(firebaseConfig)
makeMolbioAsBackEnd()
}else {
makeSMIBackEnd()
saveSelectedServer(firebaseConfig)
val firebaseApp = getOrInitializeFirebaseApp(firebaseConfig)
currentFirestore = FirebaseFirestore.getInstance(firebaseApp)
currentStorage = FirebaseStorage.getInstance(firebaseApp)
updateStatus = true
}
}
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(sharedPreferencesServerConfig.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 =
sharedPreferencesServerConfig.getString("selectedServerName", defaultServers.first().serverName)
val projectId = sharedPreferencesServerConfig.getString("projectId", defaultServers.first().projectId)
val appId = sharedPreferencesServerConfig.getString("appId", defaultServers.first().appId)
val apiKey = sharedPreferencesServerConfig.getString("apiKey", defaultServers.first().apiKey)
val storageBucket =
sharedPreferencesServerConfig.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
}
private fun makeMolbioAsBackEnd(){
Constants.FIREBASE_INTEGRATION = false
Constants.MOLBIO_INTEGRATION = true
restartApp()
}
private fun makeSMIBackEnd(){
Constants.FIREBASE_INTEGRATION = true
Constants.MOLBIO_INTEGRATION = false
}
}
fun restartApp(context: Context) {
val intent = context.packageManager.getLaunchIntentForPackage(context.packageName)
intent?.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(intent)
Process.killProcess(Process.myPid())
}
@OptIn(DelicateCoroutinesApi::class)
fun delayedRestart(context: Context) {
GlobalScope.launch(Dispatchers.Main) {
delay(5000L)
restartApp(context)
}
}
//
//
//private val firebaseConfigDev = FirebaseConfig(
// serverName = "dev",
// apiKey = "AIzaSyAVdNGCev_AFX0qmuZJF6kxzRzXUTeAW5I",
// appId = "1:650071678820:android:a53292637abb7c0d6c6471",
// projectId = "hpos-af3cc",
// storageBucket = "hpos-af3cc.appspot.com"
//)
//private val firebaseConfigQaQc = FirebaseConfig(
// serverName = "qc-qa",
// apiKey = "AIzaSyC4d4GhWHr_NMJAeBvnztQ_yQ3Qe9MAnLs",
// appId = "1:1004619739289:android:3dbcefb10ea99654e5c808",
// projectId = "hpos-qa",
// storageBucket = "hpos-qa.appspot.com"
//)
//
//private val firebaseConfigProd = FirebaseConfig(
// serverName = "prod",
// apiKey = "AIzaSyA_O0oZGzy3Kiw9fiLQ3OFPME-xQJP88vs",
// appId = "1:1012719870714:android:d8d7c962d96f4097de5f43",
// projectId = "hpos-prod",
// storageBucket = "hpos-prod.appspot.com"
//)
//
//private val firebaseConfigPreProd = FirebaseConfig(
// serverName = "pre prod",
// apiKey = "AIzaSyDYySi27LioZGNisP1NfnNU5inJX_0FT38",
// appId = "1:121176529204:android:e6841fdac57bdc95bbed61",
// projectId = "hpos-preprod",
// storageBucket = "hpos-preprod.appspot.com"
//)
//
//private val firebaseConfigSmiRandD= FirebaseConfig(
// serverName = "SMI R&D",
// apiKey = "AIzaSyAVxpilbB804iRCCpMBDjjmdZhQguctGHM",
// appId = "1:327771387914:android:a3b4ed2e42ea6e38dc87f3",
// projectId = "hposrandd",
// storageBucket = "hposrandd.firebasestorage.app"
//)
//
//private val configMolbio = FirebaseConfig(
// serverName = "molbio",
// apiKey = "molbio",
// appId = "molbio",
// projectId = "molbio",
// storageBucket = "molbio"
//)

View File

@@ -1,3 +1,4 @@
package com.example.hpostesting.firebase
/*
* // Copyright (c) 2024 ShanMukha Innovations Pvt. Ltd. All rights reserved.
* // Notice: All information contained herein is, and remains
@@ -10,9 +11,11 @@
* // 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
)
package com.example.hpostesting.presentation.dashboard
interface ItemClickListener {
fun onClick(pos: Int)
}

View File

@@ -19,18 +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 androidx.core.content.ContentProviderCompat.requireContext
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.example.hpostesting.presentation.hemocube.HemocubeActivity
import com.example.hpostesting.data.model.test.TestType
import com.example.hpostesting.firebase.FirebaseManager
import com.example.hpostesting.presentation.main_base.DashboardActivity
import com.example.hpostesting.presentation.hb_test.HBTestActivity
import com.example.hpostesting.presentation.trueheme_test.TrueHemeTestActivity
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
@@ -44,12 +45,16 @@ 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 TAG = "KitScanActivity"
private lateinit var binding: ActivityKitScanBinding
private lateinit var firebaseManager: FirebaseManager
private lateinit var sharedPreference: SharedPreferences
var sdkHandler: SDKHandler? = null
@@ -67,8 +72,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("SMI/SC/")) {
with(sharedPreference.edit()) {
putString(Constants.CUVETTE_SIZE, "2mm")
apply()
}
Toast.makeText(this, "Selected cuvette size: 2mm", Toast.LENGTH_SHORT).show()
binding.nameEditText.setText(contents)
} else if (contents.contains("SMI/SC-2-D10/")) {
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?) {
@@ -108,14 +129,52 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
firebaseManager = FirebaseManager(this)
val currentServer = firebaseManager.getLastSelectedServer().serverName
binding = ActivityKitScanBinding.inflate(layoutInflater)
sharedPreference = this.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
setContentView(binding.root)
binding.toolbar.title = "Kit Serial Number"
fromWhere = intent.getStringExtra("fromWhere").toString()
if (DataHolder.sampleReadCounter <= Constants.MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE && DataHolder.isReferenceTaken) {
DataHolder.selectedTest!!.kitSerial = DataHolder.kitSerial
val maxTest = if (currentServer == "SMI R&D"){
Constants.MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE10MM_RANDD
Log.d(TAG, "onCreate RandD mode")
}else {
if (sharedPreference.getString(Constants.CUVETTE_SIZE, "10mm").toString() == "2mm") {
Constants.MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE
} else {
Constants.MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE10MM
}
}
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 (sharedPreference.getString(Constants.USER_ID, "").toString() == "ADMIN") {
// moveToNext()
// }else{
if (sharedPreference.getString(Constants.USER_ID, "").toString() == "ADMIN") {
moveToNext()
} else {
if (DataHolder.sampleReadCounter <= maxTest && kitNum != "" && time < Constants.MAX_KIT_TIME) {
moveToNext()
} else {
Toast.makeText(
this@KitScanActivity,
"Limit Reached, Use New KIT for testing",
Toast.LENGTH_SHORT
).show()
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 +191,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,20 +226,39 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
binding.btnGo.setOnClickListener {
val serialNumber = binding.nameEditText.text.toString().trim()
if (serialNumber.isNotEmpty() && isSerialValid(serialNumber)) {
if (serialNumber.contains("SMI/SC/")) {
with(sharedPreference.edit()) {
putString(Constants.CUVETTE_SIZE, "2mm")
apply()
}
Toast.makeText(this, "Selected cuvette size: 2mm", Toast.LENGTH_SHORT).show()
} else if (serialNumber.contains("SMI/SC-2-D10/")) {
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()
@@ -192,6 +266,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()
@@ -202,21 +279,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
@@ -238,7 +315,8 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
if (mScannerInfoList.isNotEmpty()) {
sdkHandler!!.dcssdkEstablishCommunicationSession(mScannerInfoList[0].scannerID)
} else {
Toast.makeText(this,"Scanner Is not available In this device", Toast.LENGTH_LONG).show()
Toast.makeText(this, "Scanner Is not available In this device", Toast.LENGTH_LONG)
.show()
}
}
@@ -275,42 +353,60 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
Log.d("BARCODE", result)
runOnUiThread {
val editableResult: Editable = Editable.Factory.getInstance().newEditable(result)
binding.nameEditText.text = editableResult
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("SMI/SC/")) {
if (s.length != 17) {
binding.nameEditText.error =
"Invalid Kit Serial Number, correct example SMI/SC/000/00/000"
return false
}
} else if (s.contains("SMI/SC-2-D10/")) {
if (s.length != 27) {
binding.nameEditText.error =
"Invalid Kit Serial Number, correct example SMI/SC-2-D10/000000/000/000"
return false
}
} else {
return false
}
return true
}
private fun moveToNext() {
if (fromWhere == "Main") {
if (DataHolder.selectedTestType == TestType.HB_EST) {
val i = Intent(applicationContext, HBTestActivity::class.java)
startActivity(i)
} else {
DataHolder.deviceType.observe(this) { deviceType ->
when (deviceType) {
Constants.DEVICE_TYPE_HEMOCUBE -> {
val i = Intent(applicationContext, TrueHemeTestActivity::class.java)
startActivity(i)
}
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_TEST_RIGHT -> {
val i = Intent(applicationContext, TestRightActivity::class.java)
startActivity(i)
}
Constants.DEVICE_TYPE_TRUEHEME -> {
val i = Intent(applicationContext, HemocubeActivity::class.java)
startActivity(i)
Constants.DEVICE_TYPE_TRUEHEME -> {
val i = Intent(applicationContext, TrueHemeTestActivity::class.java)
startActivity(i)
}
}
}
}
}
@@ -346,4 +442,19 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
true
}
}
private fun timeDifference(createdAt: String): Long {
val currentTime = Calendar.getInstance().time
val formatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
val createdAtDate: Date = if (createdAt.isEmpty()) {
currentTime
} else {
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,12 +31,11 @@ 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.example.hpostesting.presentation.main_base.DashboardActivity
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationCallback
import com.google.android.gms.location.LocationRequest
@@ -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,26 +73,32 @@ class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
sharedPreference = getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
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 ->
DataHolder.location =
UserData.Location(location.latitude, location.longitude)
DataHolder.selectedTest?.location =
UserData.Location(location.latitude, location.longitude)
// DataHolder.location =
// UserData.Location(location.latitude, location.longitude)
// DataHolder.selectedTest?.location =
// UserData.Location(location.latitude, location.longitude)
Log.i("Location", DataHolder.location.toString())
}
}
}
val usbFilter = IntentFilter().apply {
addAction(UsbManager.ACTION_USB_DEVICE_DETACHED)
addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED)
@@ -111,12 +117,13 @@ 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 checkAndUpdateUsbConnection() {
val availableDrivers = UsbSerialProber.getDefaultProber()
.findAllDrivers(getSystemService(Context.USB_SERVICE) as UsbManager)
@@ -220,6 +227,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 +235,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()
}
@@ -314,14 +330,14 @@ class MainActivity : AppCompatActivity() {
fusedLocationClient.lastLocation.addOnSuccessListener { location: Location? ->
location?.let {
if (DataHolder.selectedTest != null) {
DataHolder.selectedTest!!.location =
UserData.Location(location.latitude, location.longitude)
// DataHolder.selectedTest!!.location =
// UserData.Location(location.latitude, location.longitude)
} else {
startActivity(Intent(this, DashboardActivity::class.java))
finish()
}
DataHolder.location =
UserData.Location(location.latitude, location.longitude)
// DataHolder.location =
// UserData.Location(location.latitude, location.longitude)
} ?: run {
requestLocationUpdates()
}

View File

@@ -14,6 +14,7 @@
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
@@ -28,11 +29,12 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.example.hpostesting.presentation.main_base.DashboardActivity
import com.example.hpostesting.util.MyUtils
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivitySplashBinding
@SuppressLint("CustomSplashScreen")
class SplashActivity : AppCompatActivity() {
private lateinit var binding: ActivitySplashBinding

View File

@@ -16,6 +16,7 @@ package com.example.hpostesting.presentation.adapter
import android.annotation.SuppressLint
import android.content.Context
import android.content.res.Resources
import android.provider.ContactsContract.Data
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -35,7 +36,7 @@ import java.util.Calendar
import java.util.Date
import java.util.Locale
class OfflineUserListAdapter(private val view: View, private val batLevel: Int) :
class OfflineUserListAdapter(private val view: View, private val batLevel: Int,private val fromWhere:String) :
RecyclerView.Adapter<OfflineUserListAdapter.OfflineUserListViewHolder>() {
inner class OfflineUserListViewHolder(val binding: OfflineUserListViewBinding) :
@@ -72,7 +73,7 @@ class OfflineUserListAdapter(private val view: View, private val batLevel: Int)
override fun onBindViewHolder(holder: OfflineUserListViewHolder, position: Int) {
val userList = differ.currentList[position]
holder.binding.apply {
userID.text = "User ID: ${userList._id}"
userID.text = "Sample ID: ${userList._id}"
bloodGroup.text = "Blood group: ${userList.bloodGroup}"
time.text = "Time: ${isBetween15And30Minutes(userList.incubationTime)} \n Started at: ${
SimpleDateFormat("HH:mm:ss").format(
@@ -88,33 +89,32 @@ class OfflineUserListAdapter(private val view: View, private val batLevel: Int)
} else {
teststatus.text = view.context.getString(R.string.test_pending)
}
userCard.setOnClickListener {
if (false) {
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!!) {
if(fromWhere == "Home") {
userCard.setOnClickListener {
if (false) {
Toast.makeText(
view.context,
view.context.getString(R.string.test_already_conducted),
view.context.getString(R.string.low_battery_warning),
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) {
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),
@@ -122,24 +122,25 @@ class OfflineUserListAdapter(private val view: View, private val batLevel: Int)
).show()
} else {
DataHolder.selectedTest = UserData(
_id = userList._id,
bloodGroup = userList.bloodGroup,
incubationTime = userList.incubationTime
sampleid = userList.sampleid,
_id = userList._id,
bloodGroup = userList.bloodGroup,
incubationTime = userList.incubationTime
)
view.findNavController()
.navigate(R.id.action_nav_home_to_mainActivity)
.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()
} else {
Toast.makeText(
view.context,
view.context.getString(R.string.incubation_not_started),
Toast.LENGTH_SHORT
).show()
}
}
}
}
}
}
}

View File

@@ -29,7 +29,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.example.hpostesting.presentation.trueheme_test.TrueHemeTestViewModel
import com.firebase.ui.firestore.FirestoreRecyclerAdapter
import com.firebase.ui.firestore.FirestoreRecyclerOptions
import com.google.firebase.firestore.FirebaseFirestore
@@ -41,9 +41,8 @@ import java.util.Date
import java.util.Locale
class UserListAdapter(
private val context: Context,
private val hemoCubeViewModel: HemoCubeViewModel,
private val trueHemeTestViewModel: TrueHemeTestViewModel,
options: FirestoreRecyclerOptions<UserData>,
private val view: View,
private val batLevel: Int,

View File

@@ -31,7 +31,7 @@ import androidx.fragment.app.Fragment
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.presentation.hemocube.HemocubeActivity
import com.example.hpostesting.presentation.trueheme_test.TrueHemeTestActivity
import `in`.sminnovations.hpostesting.databinding.FragmentAssuranceControlsBinding
import java.time.Instant
@@ -259,7 +259,7 @@ class AssuranceControlsFragment : Fragment() {
apply()
}
val i = Intent(requireContext(), HemocubeActivity::class.java)
val i = Intent(requireContext(), TrueHemeTestActivity::class.java)
startActivity(i)
}
}

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,13 +37,14 @@ 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 val messages = MutableLiveData<String>()
private var startListening = MutableLiveData(false)
override fun onCreateView(
@@ -64,14 +66,25 @@ class AutoDacFragment : Fragment() {
binding.btnSubmit.visibility = View.GONE
listenToHemoCube()
getDeviceId()
binding.tvSubtitle4.movementMethod = ScrollingMovementMethod()
binding.btnSubmit.setOnClickListener {
resultData += "Calibrating the device...\n"
autoDacViewModel.messages.postValue(resultData)
testStatusCode = 0.5
binding.btnSubmit.visibility = View.GONE
runAutoDacCommand()
runJCommand()
}
binding.btnReadDac.setOnClickListener {
readClick = true
binding.btnReadDac.visibility = View.GONE
readCurrentDACValuesCommand()
runECommand()
}
if (sharedPreferences.getString(Constants.USER_ID, "").toString() == "ADMIN") {
binding.btnReadDac.visibility = View.VISIBLE
}else{
binding.btnReadDac.visibility = View.GONE
}
}
private fun observeViewModel() {
@@ -80,7 +93,7 @@ class AutoDacFragment : Fragment() {
currentDeviceData = it
}
messages.observe(viewLifecycleOwner) {
autoDacViewModel.messages.observe(viewLifecycleOwner) {
binding.tvSubtitle4.text = it
}
@@ -114,8 +127,33 @@ class AutoDacFragment : Fragment() {
}
})
}
private fun runJCommand() {
autoDacViewModel.progressBar.postValue(true)
(activity as AutoDacActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.J_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
}
private fun runAutoDacCommand() {
override fun onUsbError(e: Exception?) {
autoDacViewModel.progressBar.postValue(false)
}
})
}
private fun runDCommand() {
autoDacViewModel.progressBar.postValue(true)
(activity as AutoDacActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.DIAGNOSTICS_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
}
override fun onUsbError(e: Exception?) {
autoDacViewModel.progressBar.postValue(false)
}
})
}
private fun runCCommand() {
autoDacViewModel.progressBar.postValue(true)
(activity as AutoDacActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.AUTO_DAC_COMMAND,
@@ -128,6 +166,33 @@ class AutoDacFragment : Fragment() {
}
})
}
private fun runGCommand() {
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 runECommand() {
autoDacViewModel.progressBar.postValue(true)
(activity as AutoDacActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.LOAD_DAC_VALUES,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
}
override fun onUsbError(e: Exception?) {
autoDacViewModel.progressBar.postValue(false)
}
})
}
private fun setAutoDacValuesCommand() {
autoDacViewModel.progressBar.postValue(true)
@@ -168,10 +233,12 @@ class AutoDacFragment : Fragment() {
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 (sharedPreferences.getString(Constants.USER_ID, "").toString() == "ADMIN") {
autoDacViewModel.messages.postValue(resultData)
}
// binding.tvSubtitle4.text = resultData
if (stringData.contains("SN")) {
val slData = stringData.split(" ")
if (slData.size > 1) {
@@ -186,10 +253,56 @@ class AutoDacFragment : Fragment() {
}
}
}
if (resultData.contains("#CC")) {
if (resultData.contains("#JC") && testStatusCode < 1.0) {
testStatusCode = 1.1
runDCommand()
}
if (resultData.contains("#DC") && testStatusCode < 1.2) {
testStatusCode = 1.3
if(validateDacValues()){
if (sharedPreferences.getString(Constants.USER_ID, "").toString() == "ADMIN") {
resultData += "Calibrating the device, Please wait...\n"
}else{
resultData = "Calibrating the device, Please wait...\n"
}
autoDacViewModel.messages.postValue(resultData)
runCCommand()
}else{
activity?.runOnUiThread {
if (sharedPreferences.getString(Constants.USER_ID, "").toString() == "ADMIN") {
resultData += "Calibration failed!\nContact us for help at support@sminnovations.in"
}else{
resultData = "Calibration failed!\nContact us for help at support@sminnovations.in"
}
autoDacViewModel.messages.postValue(resultData)
binding.btnReadDac.visibility = View.GONE
}
}
}
if (resultData.contains("#GC") && testStatusCode < 1.6) {
testStatusCode = 1.7
runECommand()
}
if (resultData.contains("#EC") && testStatusCode < 1.8) {
testStatusCode = 1.9
if (sharedPreferences.getString(Constants.USER_ID, "").toString() == "ADMIN") {
resultData += "Calibration Completed\n"
}else{
resultData = "Calibration Completed\n"
}
autoDacViewModel.messages.postValue(resultData)
activity?.runOnUiThread {
Toast.makeText(requireActivity(), "Calibration completed", Toast.LENGTH_LONG).show()
binding.ivCheck.visibility = View.VISIBLE
}
}
if (resultData.contains("#EC") && readClick && testStatusCode < 2.1) {
testStatusCode = 2.2
readCurrentDACValuesCommand()
}
if (resultData.contains("#CC") && testStatusCode < 1.4) {
testStatusCode = 1.5
setAutoDacValuesCommand()
autoDacViewModel.addAutoDacDataToDb(
DiagnosticsData(
deviceId = sharedPreferences.getString(Constants.DEVICE_ID, "")
@@ -212,9 +325,7 @@ class AutoDacFragment : Fragment() {
).format(Calendar.getInstance().time)
)
)
activity?.runOnUiThread {
binding.ivCheck.visibility = View.VISIBLE
}
}
if (resultData.contains("#WC")) {
@@ -230,6 +341,27 @@ class AutoDacFragment : Fragment() {
Firebase.crashlytics.recordException(e)
}
}
fun extractSubstring(input: String): String {
val regex = "#CS(.*?)#CC".toRegex()
val matchResult = regex.find(input)
return matchResult?.groups?.get(1)?.value?.trim() ?: ""
}
private fun validateDacValues(): Boolean {
val pattern = Regex("(LED:\\d+)__DAC:(\\d+)__ADC:(\\d+)")
val matches = pattern.findAll(resultData)
for (match in matches) {
val ledName = match.groupValues[1]
val xValue = match.groupValues[2].toDouble()
val yValue = match.groupValues[3].toDouble()
if(xValue == 3200.0){
if(yValue < 500.0){
return false
}
}
}
return true
}
fun parseData(inputData: List<String>): List<Pair<String, String>> {
val pattern = Regex("([A-Z]+)\\s(\\d+)")

View File

@@ -29,8 +29,8 @@ import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.model.patient.BufferCheckData
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.presentation.utils.UsbServiceListener
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.example.hpostesting.presentation.main_base.DashboardActivity
import com.example.hpostesting.presentation.trueheme_test.TrueHemeTestViewModel
import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.ktx.Firebase
import `in`.sminnovations.hpostesting.R
@@ -44,7 +44,7 @@ import kotlin.math.log10
class HemoCubeBufferCheckFragment : Fragment() {
private lateinit var binding: FragmentHemoCubeReferenceBinding
private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels()
private val trueHemeTestViewModel: TrueHemeTestViewModel by activityViewModels()
private lateinit var sharedPreferences: SharedPreferences
private var currentDeviceData: DeviceData? = null
private var resultData: String = ""
@@ -123,13 +123,13 @@ class HemoCubeBufferCheckFragment : Fragment() {
}
private fun observeViewModel() {
hemoCubeViewModel.deviceData.observe(viewLifecycleOwner) {
trueHemeTestViewModel.deviceData.observe(viewLifecycleOwner) {
currentDeviceData = it
}
hemoCubeViewModel.networkStatusLiveData.observe(viewLifecycleOwner) { isNetworkAvailable ->
trueHemeTestViewModel.networkStatusLiveData.observe(viewLifecycleOwner) { isNetworkAvailable ->
if (isNetworkAvailable) {
hemoCubeViewModel.getDeviceData(sharedPreferences.getString(Constants.USER_ID, ""))
trueHemeTestViewModel.getDeviceData(sharedPreferences.getString(Constants.USER_ID, ""))
} else {
Toast.makeText(
requireContext(), R.string.internt_not, Toast.LENGTH_SHORT
@@ -137,7 +137,7 @@ class HemoCubeBufferCheckFragment : Fragment() {
}
isOnline = isNetworkAvailable
}
hemoCubeViewModel.fireBaseUpload.observe(viewLifecycleOwner) { result ->
trueHemeTestViewModel.fireBaseUpload.observe(viewLifecycleOwner) { result ->
if (result == "Success") {
showToast(R.string.kit_uploaded)
}
@@ -152,11 +152,11 @@ class HemoCubeBufferCheckFragment : Fragment() {
binding.progressBar.visibility = View.GONE
}
hemoCubeViewModel.messages.observe(viewLifecycleOwner) {
trueHemeTestViewModel.messages.observe(viewLifecycleOwner) {
binding.tvSubtitle4.text = it
}
hemoCubeViewModel.deviceMessages.observe(viewLifecycleOwner) {
trueHemeTestViewModel.deviceMessages.observe(viewLifecycleOwner) {
binding.tvDeviceMessages.text = it
}
}
@@ -192,7 +192,7 @@ class HemoCubeBufferCheckFragment : Fragment() {
}
resultData += stringData
hemoCubeViewModel.deviceMessages.postValue(resultData)
trueHemeTestViewModel.deviceMessages.postValue(resultData)
when {
stringData.contains("SN") -> {
@@ -209,11 +209,11 @@ class HemoCubeBufferCheckFragment : Fragment() {
binding.tvSubtitle4.visibility = View.VISIBLE
binding.btnPlacebuffer.visibility = View.VISIBLE
}
hemoCubeViewModel.messages.postValue("Start")
trueHemeTestViewModel.messages.postValue("Start")
}
stringData.contains("#BS") -> {
hemoCubeViewModel.messages.postValue("Buffer Started")
trueHemeTestViewModel.messages.postValue("Buffer Started")
}
stringData.contains("#BC") -> {
@@ -232,7 +232,7 @@ class HemoCubeBufferCheckFragment : Fragment() {
}
stringData.contains("#SC") -> {
hemoCubeViewModel.messages.postValue("Sample Completed \nGathering data")
trueHemeTestViewModel.messages.postValue("Sample Completed \nGathering data")
fetchResult()
}
@@ -351,7 +351,7 @@ class HemoCubeBufferCheckFragment : Fragment() {
}
val prdClassification = absorbanceBasedClassification(_predictedDenovixRatio)
hemoCubeViewModel.messages.postValue(prdClassification)
trueHemeTestViewModel.messages.postValue(prdClassification)
val bufferData = BufferCheckData(
_id = UUID.randomUUID().toString(),
@@ -385,15 +385,15 @@ class HemoCubeBufferCheckFragment : Fragment() {
testTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time),
batteryLevel = hemoCubeViewModel.getBatteryLevel().toString(),
batteryCapacity = hemoCubeViewModel.getBatteryCapacity(requireContext()).toString(),
batteryMaxCapacity = hemoCubeViewModel.getBatteryMaxCapacity(requireContext())
batteryLevel = trueHemeTestViewModel.getBatteryLevel().toString(),
batteryCapacity = trueHemeTestViewModel.getBatteryCapacity(requireContext()).toString(),
batteryMaxCapacity = trueHemeTestViewModel.getBatteryMaxCapacity(requireContext())
.toString(),
batteryTemperature = hemoCubeViewModel.getBatteryTemperature().toString(),
batteryVoltage = hemoCubeViewModel.getBatteryVoltage(requireContext()).toString()
batteryTemperature = trueHemeTestViewModel.getBatteryTemperature().toString(),
batteryVoltage = trueHemeTestViewModel.getBatteryVoltage(requireContext()).toString()
)
hemoCubeViewModel.uploadHemoCubeResultToDatabaseForBufferCheck(isOnline, bufferData)
trueHemeTestViewModel.uploadHemoCubeResultToDatabaseForBufferCheck(isOnline, bufferData)
} catch (e: Exception) {
Toast.makeText(
requireContext(), "Error while processing device data", Toast.LENGTH_SHORT
@@ -404,7 +404,7 @@ class HemoCubeBufferCheckFragment : Fragment() {
private fun findResult(calculatedRatio: Double?): String {
try {
hemoCubeViewModel.messages.postValue("result classification")
trueHemeTestViewModel.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"
@@ -426,7 +426,7 @@ class HemoCubeBufferCheckFragment : Fragment() {
private fun absorbanceBasedClassification(predictedDenovixRatio: Double?): String {
try {
hemoCubeViewModel.messages.postValue("result classification")
trueHemeTestViewModel.messages.postValue("result classification")
if (predictedDenovixRatio != null) {
if (predictedDenovixRatio in 0.0..0.16) return "Kit Passed"
if (predictedDenovixRatio in 0.16..0.165) return "Kit Passed"
@@ -482,20 +482,20 @@ class HemoCubeBufferCheckFragment : Fragment() {
}
private fun getDeviceInfo() {
hemoCubeViewModel.progressBar.postValue(true)
trueHemeTestViewModel.progressBar.postValue(true)
(activity as HemocubeBufferCheckActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.DEVICE_CONFIGURATION_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
data?.let {
val stringData = String(it)
hemoCubeViewModel.messages.postValue(stringData)
trueHemeTestViewModel.messages.postValue(stringData)
binding.tvSubtitle4.text = stringData
}
}
override fun onUsbError(e: Exception?) {
hemoCubeViewModel.progressBar.postValue(false)
trueHemeTestViewModel.progressBar.postValue(false)
}
})
}

View File

@@ -36,7 +36,7 @@ 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.LanguageManager
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.example.hpostesting.presentation.trueheme_test.TrueHemeTestViewModel
import com.example.hpostesting.util.UsbService
import com.hoho.android.usbserial.driver.UsbSerialDriver
import com.hoho.android.usbserial.driver.UsbSerialProber
@@ -47,7 +47,7 @@ import `in`.sminnovations.hpostesting.databinding.ActivityHemocubeBinding
@AndroidEntryPoint
open class HemocubeBufferCheckActivity : AppCompatActivity() {
private lateinit var binding: ActivityHemocubeBinding
private val viewModel by viewModels<HemoCubeViewModel>()
private val viewModel by viewModels<TrueHemeTestViewModel>()
private var myMenu: Menu? = null
private lateinit var mDriver: UsbSerialDriver

View File

@@ -31,7 +31,7 @@ import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.model.calibration.CalibrationData
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.presentation.utils.UsbServiceListener
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.example.hpostesting.presentation.main_base.DashboardActivity
import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.ktx.Firebase
import `in`.sminnovations.hpostesting.databinding.FragmentCalibrationBinding

View File

@@ -1,89 +0,0 @@
/*
* // 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.pm.PackageManager
import android.os.Bundle
import android.widget.Toast
import androidx.preference.ListPreference
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import com.example.hpostesting.data.constant.LanguageManager
import `in`.sminnovations.hpostesting.R
private var isLanguageChanged = false
class SlideshowFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
val preferenceScreen = preferenceManager.createPreferenceScreen(requireContext())
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")
languagePreference.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()) + " ]"
preferenceScreen.addPreference(languagePreference)
preferenceScreen.addPreference(appVersionPreference)
setPreferenceScreen(preferenceScreen)
if (isLanguageChanged) {
Toast.makeText(requireContext(), R.string.language_update, Toast.LENGTH_SHORT).show()
}
}
private fun updateLanguage(context: Context, languageCode: String) {
LanguageManager.persistLanguagePreference(context, languageCode)
LanguageManager.setLocale(context, languageCode)
requireActivity().recreate() // Recreate activity to apply language changes
isLanguageChanged = true
}
private fun getAppVersion(context: Context): String {
return try {
val pInfo = context.packageManager.getPackageInfo(context.packageName, 0)
pInfo.versionName
} catch (e: PackageManager.NameNotFoundException) {
"N/A"
}
}
private fun getAppEnvironment(context: Context): String {
return try {
val pInfo = context.packageManager.getPackageInfo(context.packageName, 0)
pInfo.packageName.substringAfterLast('.')
} catch (e: PackageManager.NameNotFoundException) {
"N/A"
}
}
}

View File

@@ -1,105 +0,0 @@
/*
* // 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.ui
import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import com.example.hpostesting.data.constant.Constants
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentLoginBinding
class LoginFragment : Fragment() {
private var _binding: FragmentLoginBinding? = null
private val binding get() = _binding!!
private lateinit var sharedPreference: SharedPreferences
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
_binding = FragmentLoginBinding.inflate(inflater, container, false)
sharedPreference =
requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
init()
}
private fun init() {
if (isUserLoggedIn()) {
navigateToHomeFragment()
return
}
binding.btnLogin.setOnClickListener {
val loginId = binding.loginId.text.toString()
val password = binding.password.text.toString()
if (loginId.isNotBlank() && password.isNotBlank()) {
performLogin(loginId, password)
} else {
if (loginId.isBlank()) {
binding.loginId.error = R.string.enter_proper_login_id.toString()
}
if (password.isBlank()) {
binding.password.error = R.string.enter_proper_password.toString()
}
}
}
}
private fun isUserLoggedIn(): Boolean {
return sharedPreference.getString(Constants.USER_ID, "")?.isNotBlank() == true
}
private fun navigateToHomeFragment() {
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()
}
}
Toast.makeText(requireContext(), R.string.wrong_user_id, Toast.LENGTH_SHORT).show()
}
private fun saveUserId(userId: String) {
with(sharedPreference.edit()) {
putString(Constants.USER_ID, userId)
apply()
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View File

@@ -1,26 +0,0 @@
/*
* // 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.ui.slideshow
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class SlideshowViewModel : ViewModel() {
private val _text = MutableLiveData<String>().apply {
value = "This is slideshow Fragment"
}
val text: LiveData<String> = _text
}

View File

@@ -29,6 +29,7 @@ import android.os.Bundle
import android.os.IBinder
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
@@ -105,8 +106,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

@@ -26,14 +26,14 @@ import androidx.lifecycle.MutableLiveData
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.presentation.utils.UsbServiceListener
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.example.hpostesting.presentation.trueheme_test.TrueHemeTestViewModel
import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.ktx.Firebase
import `in`.sminnovations.hpostesting.databinding.FragmentDeviceBinding
class DeviceFragment : Fragment() {
private lateinit var binding: FragmentDeviceBinding
private val deviceViewModel: HemoCubeViewModel by activityViewModels()
private val deviceViewModel: TrueHemeTestViewModel by activityViewModels()
private lateinit var sharedPreferences: SharedPreferences
private var deviceId = ""
private var startListening = MutableLiveData(false)
@@ -141,7 +141,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
@@ -34,13 +33,12 @@ 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.main_base.DashboardActivity
import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.ktx.Firebase
import `in`.sminnovations.hpostesting.databinding.FragmentDeviceProvisionBinding
import okio.ByteString.Companion.decodeBase64
import java.io.File
import java.io.FileOutputStream
class DeviceProvisionFragment : Fragment() {
private var resultData: String = ""
@@ -118,12 +116,7 @@ class DeviceProvisionFragment : Fragment() {
)
apply()
}
startActivity(
Intent(
requireContext(),
DashboardActivity::class.java
)
)
Toast.makeText(
activity, "Device registered successfully", Toast.LENGTH_LONG
).show()
@@ -148,18 +141,25 @@ 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,
"An error in device provision: ${response.data.message}",
Toast.LENGTH_LONG
).show()
Log.d("Error in hpos network", "observeViewModel:${response.data.message} ")
binding.btnSubmit.visibility = View.VISIBLE
}
}
is Result.Error -> {
response.exception.let { message ->
Toast.makeText(
@@ -167,7 +167,9 @@ class DeviceProvisionFragment : Fragment() {
"An error occurred in device provision: $message",
Toast.LENGTH_LONG
).show()
Log.d("Error in hpos network 2", "observeViewModel:$message} ")
}
Log.d("Error in hpos network 3", "observeViewModel: $response} ")
}
is Result.Loading -> {
@@ -247,11 +249,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

@@ -18,6 +18,8 @@ import android.content.Intent
import android.content.IntentFilter
import android.content.SharedPreferences
import android.os.Bundle
import android.os.Handler
import android.text.method.ScrollingMovementMethod
import android.util.Log
import android.view.LayoutInflater
import android.view.View
@@ -26,8 +28,6 @@ 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.util.Result.Success
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.model.devicediagnostics.AdditionalDetails
@@ -35,21 +35,33 @@ import com.example.hpostesting.data.model.devicediagnostics.DeviceDiagnosticsReq
import com.example.hpostesting.data.model.diagnostics.DiagnosticsData
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.presentation.utils.UsbServiceListener
import com.example.hpostesting.util.Result
import com.example.hpostesting.util.Result.Success
import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.ktx.Firebase
import `in`.sminnovations.hpostesting.databinding.FragmentDiagnosticsBinding
import org.apache.commons.math3.stat.regression.SimpleRegression
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
class DiagnosticsFragment : Fragment() {
class DiagnosticsFragment : Fragment() {
// Initialize variables to store LED DAC values
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
private var testStatusCode = 0.0
private lateinit var binding: FragmentDiagnosticsBinding
private val diagnosticsViewModel: DiagnosticsViewModel by activityViewModels()
private lateinit var sharedPreferences: SharedPreferences
private var currentDeviceData: DeviceData? = null
private var resultData: String = ""
private val messages = MutableLiveData<String>()
private var currentResultData: String = ""
private var startListening = MutableLiveData(false)
private val batteryStatus: Intent? =
IntentFilter(Intent.ACTION_BATTERY_CHANGED).let { ifilter ->
@@ -73,9 +85,14 @@ class DiagnosticsFragment : Fragment() {
private fun initViews() {
binding.btnSubmit.visibility = View.GONE
binding.tvSubtitle4.movementMethod = ScrollingMovementMethod()
listenToHemoCube()
getDeviceId()
binding.btnSubmit.setOnClickListener {
diagnosticsViewModel.messages.postValue("Processing diagnostics... Please wait.")
binding.progressBarHor.visibility = View.VISIBLE
incrementProgress()
binding.btnSubmit.visibility = View.GONE
runDeviceDiagnostics()
val batteryLevel = "" //diagnosticsViewModel.getBatteryLevel().toString()
@@ -91,12 +108,12 @@ class DiagnosticsFragment : Fragment() {
batteryTemperature = batteryTemperature,
batteryVoltage = batteryVoltage!!
)
diagnosticsViewModel.deviceDiagnostics(
DeviceDiagnosticsRequest(additionalDetails = additionalDetails)
)
if(Constants.MOLBIO_INTEGRATION){
diagnosticsViewModel.deviceDiagnostics(
DeviceDiagnosticsRequest(additionalDetails = additionalDetails)
)
}
}
}
@@ -106,7 +123,7 @@ class DiagnosticsFragment : Fragment() {
currentDeviceData = it
}
messages.observe(viewLifecycleOwner) {
diagnosticsViewModel.messages.observe(viewLifecycleOwner) {
binding.tvSubtitle4.text = it
Log.e("diagnostics", binding.tvSubtitle4.text.toString())
}
@@ -153,6 +170,8 @@ class DiagnosticsFragment : Fragment() {
}
is Result.Loading -> {
}
else -> {}
}
}
@@ -165,11 +184,11 @@ class DiagnosticsFragment : Fragment() {
HemoCubeCommands.DEVICE_CONFIGURATION_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
data?.let {
val stringData = String(it)
diagnosticsViewModel.messages.postValue(stringData)
binding.tvSubtitle4.text = stringData
}
// data?.let {
// val stringData = String(it)
// diagnosticsViewModel.messages.postValue(stringData)
// binding.tvSubtitle4.text = stringData
// }
}
override fun onUsbError(e: Exception?) {
@@ -191,10 +210,35 @@ class DiagnosticsFragment : Fragment() {
}
})
}
private fun readCurrentDACValuesCommand() {
diagnosticsViewModel.progressBar.postValue(true)
(activity as DiagnosticsActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.READ_DAC_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
}
override fun onUsbError(e: Exception?) {
diagnosticsViewModel.progressBar.postValue(false)
}
})
}
private fun loadDACValues() {
diagnosticsViewModel.progressBar.postValue(true)
(activity as DiagnosticsActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.LOAD_DAC_VALUES,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
}
private fun listenToHemoCube() {
override fun onUsbError(e: Exception?) {
diagnosticsViewModel.progressBar.postValue(false)
}
})
}
private fun listenToHemoCube() {
diagnosticsViewModel.messages.postValue("Place cuvette filled with buffer\n and click on start")
val fullReadOutput = StringBuilder()
startListening.postValue(true)
@@ -204,23 +248,24 @@ class DiagnosticsFragment : Fragment() {
override fun onUsbRead(data: ByteArray?) {
data?.let {
val stringData = String(it)
diagnosticsViewModel.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
}
}
handleUsbData(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
// }
// }
}
if (resultData.contains("END") || fullReadOutput.contains("END")) {
@@ -268,6 +313,194 @@ class DiagnosticsFragment : Fragment() {
}
}
private fun handleUsbData(stringData: String) {
resultData += stringData
if (sharedPreferences.getString(Constants.USER_ID, "").toString() == "ADMIN") {
currentResultData += stringData
}
when {
(resultData.contains("SNE") && this.testStatusCode < 1.0) -> {
this.testStatusCode = 1.1
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
}
}
(resultData.contains("#DC") && this.testStatusCode < 1.4) -> {
this.testStatusCode = 1.5
activity?.runOnUiThread {
setProgress(96)
loadDACValues()
}
}
(resultData.contains("#EC") && this.testStatusCode < 1.6) -> {
this.testStatusCode = 1.7
activity?.runOnUiThread {
setProgress(98)
readCurrentDACValuesCommand()
}
}
(resultData.contains("#RC") && this.testStatusCode < 1.8) -> {
this.testStatusCode = 1.9
activity?.runOnUiThread {
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"
diagnosticsViewModel.messages.postValue(currentResultData)
}
}
}
}
private fun finalCalculation() {
val pattern = Regex("(LED:\\d+)__DAC:(\\d+)__ADC:(\\d+)")
// Find all matches in the string
val matches = pattern.findAll(resultData)
// Initialize lists for x and y values for each LED
val ledDataMap = mutableMapOf<String, MutableList<Pair<Double, Double>>>()
// Extract LED name, x, and y values from each match and add to the corresponding lists
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()
}
if ((ledDataMap[ledName]?.size ?: 0) < 7) {
if(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>()
// Print the extracted x and y values for each LED
// Regular expression to match LED DAC values
val regex = Regex("LED(\\d) DAC : (\\d+)")
// Find LED DAC values using regex
regex.findAll(resultData).forEach {
val (led, dac) = it.destructured
val dacValue = dac.toDouble()
when (led.toInt()) {
1 -> led1Dac = dacValue
2 -> led2Dac = dacValue
3 -> led3Dac = dacValue
4 -> led4Dac = dacValue
}
}
println("$led1Dac")
println("LED2 DAC: $led2Dac")
println("LED3 DAC: $led3Dac")
println("LED4 DAC: $led4Dac")
for ((ledName, data) in ledDataMap) {
// println("$ledName x-values: ${data.map { it.first }}")
// println("$ledName y-values: ${data.map { it.second }}")
val message = calculateRegressionAndDAC(ledName, data)
results.add(message)
}
// Print the pass or fail messages for each LED
results.forEach {
currentResultData += it
diagnosticsViewModel.messages.postValue(currentResultData)
println(it)
}
}
private fun calculateRegressionAndDAC(ledName: String, data: List<Pair<Double, Double>>): String {
val regression = SimpleRegression()
data.forEach { (x, y) -> regression.addData(x, y) }
val slope = regression.slope
val constant = regression.intercept
val rSquared = regression.rSquare
// Check R-squared value and generate pass or fail message
val message = if (rSquared > 0.98) {
"$ledName linearity PASS (✓)\n"
} else {
"$ledName linearity FAIL (✗)\n"
}
// Calculation for ADC value
val adcValue = when (ledName) {
"LED:1" -> 22000.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 - ledValue!!
if(resultDAC < 200){
currentResultData += "$ledName DAC LEVEL PASS (✓)\n"
println("$ledName DAC LEVEL PASS")
}else{
currentResultData += "$ledName DAC LEVEL FAIL (✗)\n"
println("$ledName DAC LEVEL FAIL")
}
return message
}
private fun calculateDAC(adc: Double, slope: Double, constant: Double): Double {
return (adc - constant) / slope
}
fun parseData(inputData: List<String>): List<Pair<String, String>> {
val pattern = Regex("([A-Z]+)\\s(\\d+)")
val parsedData = mutableListOf<Pair<String, String>>()
@@ -286,4 +519,19 @@ class DiagnosticsFragment : Fragment() {
private fun showToast(message: String) {
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
}
private fun setProgress(progress: Int) {
binding.progressBarHor.progress = progress
}
private fun incrementProgress() {
val handler = Handler()
handler.postDelayed(object : Runnable {
override fun run() {
if (currentProgress <= targetProgress) {
binding.progressBarHor.progress = currentProgress
currentProgress++
handler.postDelayed(this, delayBetweenIncrements.toLong())
}
}
}, delayBetweenIncrements.toLong())
}
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,45 @@
/*
* // 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.main_base
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import `in`.sminnovations.hpostesting.databinding.FragmentAboutBinding
class AboutFragment : Fragment() {
private lateinit var binding: FragmentAboutBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
): View {
binding = FragmentAboutBinding.inflate(inflater, container, false)
return binding.root
}
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

@@ -11,32 +11,28 @@
* // from ShanMukha Innovations Pvt. Ltd.
*/
package com.example.hpostesting.presentation.dashboard
package com.example.hpostesting.presentation.main_base
import android.content.Context
import android.content.SharedPreferences
import android.os.BatteryManager
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.presentation.adapter.OfflineUserListAdapter
import com.example.hpostesting.presentation.adapter.UserListAdapter
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.example.hpostesting.presentation.testRight.TestRightViewModel
import `in`.sminnovations.hpostesting.R
import com.example.hpostesting.presentation.trueheme_test.TrueHemeTestViewModel
import `in`.sminnovations.hpostesting.databinding.FragmentActivitiesBinding
import `in`.sminnovations.hpostesting.databinding.FragmentHomeBinding
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import java.util.Locale
class ActivitiesFragment : Fragment() {
private lateinit var binding: FragmentActivitiesBinding
private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels()
private val trueHemeTestViewModel: TrueHemeTestViewModel by activityViewModels()
private lateinit var adapter: OfflineUserListAdapter
override fun onCreateView(
@@ -50,15 +46,21 @@ class ActivitiesFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
hemoCubeViewModel.allPendingUserToUpload.observe(viewLifecycleOwner) { userData ->
trueHemeTestViewModel.allPendingUserToUpload.observe(viewLifecycleOwner) { userData ->
if (userData.isNotEmpty()) {
userData.forEach { user ->
if((isBetween15And30Minutes(user.incubationTime) > 30 || isBetween15And30Minutes(user.incubationTime) < 0 ) && user.testStatus == false){
trueHemeTestViewModel.deleteByStatus()
}
}
binding.rvOrderOffline.visibility = View.VISIBLE
binding.noDataText.visibility = View.GONE
val bm =
requireContext().getSystemService(Context.BATTERY_SERVICE) as BatteryManager
val batLevel: Int = bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
adapter = OfflineUserListAdapter(binding.root, batLevel)
adapter = OfflineUserListAdapter(binding.root, batLevel,"Activities")
adapter.differ.submitList(userData)
binding.rvOrderOffline.adapter = adapter
}else{
@@ -68,5 +70,16 @@ class ActivitiesFragment : Fragment() {
}
}
}
private fun isBetween15And30Minutes(createdAt: String): Long {
val formatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
val createdAtDate: Date = formatter.parse(createdAt)!!
val currentTime = Calendar.getInstance().time
val diffMillis = currentTime.time - createdAtDate.time
return diffMillis / (60 * 1000)
}
}

View File

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

View File

@@ -11,7 +11,7 @@
* // from ShanMukha Innovations Pvt. Ltd.
*/
package com.example.hpostesting.presentation.dashboard
package com.example.hpostesting.presentation.main_base
import android.annotation.SuppressLint
import android.content.Context
@@ -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,22 +32,22 @@ 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.LanguageManager
import com.example.hpostesting.data.model.updates.DeviceUpdateRequest
import com.example.hpostesting.presentation.utils.NatsManager
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.example.hpostesting.data.repository.DatabaseRepository
import com.example.hpostesting.firebase.FirebaseManager
import com.example.hpostesting.presentation.trueheme_test.TrueHemeTestViewModel
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 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 onMessageReceived(topic: String, message: String)
@@ -61,7 +60,8 @@ open interface IDataCollector: NatsMessageCallback {
@AndroidEntryPoint
class DashboardActivity : AppCompatActivity(), IDataCollector {
@Inject
lateinit var databaseRepository: DatabaseRepository
val TAG = "DashboardActivity"
private var isRegistered = false
private lateinit var appBarConfiguration: AppBarConfiguration
@@ -69,16 +69,18 @@ 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
private val hemocubeViewModel: TrueHemeTestViewModel by viewModels()
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
@@ -88,16 +90,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
@@ -106,43 +116,34 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
nats.sub("server.hpos.${deviceId}.ping")
nats.pub("server.hpos.${deviceId}.ping", "THIS IS A TEST MSG")
hemocubeViewModel.deviceUpdate.observe(this) { result ->
when (result) {
is Result.Success -> {
// Handle success
val apk = result.data
val file = File(getExternalFilesDir("Updates"), "update.apk")
file.setReadable(true, false) // Ensure the file is readable
apk.byteStream().use { input ->
file.outputStream().use { output ->
input.copyTo(output)
}
}
Log.d("Responsebodyformat", "Responsebodyformat: ")
installApk(file)
Log.e("ApI", "APK URL: $apk")
Toast.makeText(
this,
"${result.data}",
Toast.LENGTH_SHORT
).show()
}
hemocubeViewModel.deviceUpdate.observe(this) {
Log.d("DashboardLogs",it.toString())
is Result.Error -> {
result.exception.let { message ->
Toast.makeText(this, "An error occurred On Updating App: $message", Toast.LENGTH_LONG)
.show()
}
}
var apk = it
val file = File(getExternalFilesDir("Downloads"), "update.apk")
file.setReadable(true, false)
is Result.Loading -> {
}
else -> {
// Write APK to file
apk.byteStream().use { input ->
file.outputStream().use { output ->
input.copyTo(output)
}
}
}
hemocubeViewModel.deviceUpdateheader.observe(this){
val apkFile = File(getExternalFilesDir("Downloads"), "update.apk")
val expectedChecksum = it.get("Checksum") // Provide your expected checksum here
val algorithm = "SHA-256" // Choose the algorithm you want to use (e.g., MD5, SHA-1, SHA-256)
val isIntegrityVerified = verifyChecksum(apkFile, expectedChecksum!!, algorithm)
if (isIntegrityVerified) {
println("APK integrity verified: The file has not been tampered with.")
installApk(apkFile)
} else {
println("APK integrity check failed: The file may have been tampered with.")
}
}
val drawerLayout: DrawerLayout = binding.drawerLayout
val navView: NavigationView = binding.navView
@@ -150,7 +151,7 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
appBarConfiguration = AppBarConfiguration(
setOf(
R.id.nav_home, R.id.nav_profile, R.id.nav_activity,R.id.nav_settings
R.id.nav_home, R.id.nav_profile, R.id.nav_activity,R.id.nav_settings,R.id.nav_about
), drawerLayout
)
setupActionBarWithNavController(navController, appBarConfiguration)
@@ -164,6 +165,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)
@@ -175,7 +182,24 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}
fun calculateChecksum(file: File, algorithm: String): String {
val digest = MessageDigest.getInstance(algorithm)
val inputStream = file.inputStream()
val buffer = ByteArray(8192)
var bytesRead = inputStream.read(buffer)
while (bytesRead != -1) {
digest.update(buffer, 0, bytesRead)
bytesRead = inputStream.read(buffer)
}
val checksumBytes = digest.digest()
return checksumBytes.joinToString("") { "%02x".format(it) }
}
// Function to verify checksum
fun verifyChecksum(file: File, expectedChecksum: String, algorithm: String): Boolean {
val actualChecksum = calculateChecksum(file, algorithm)
return actualChecksum.equals(expectedChecksum, ignoreCase = true)
}
private fun installApk(file: File) {
val pInfo = baseContext.packageManager.getPackageInfo(baseContext.packageName, 0)
val uri: Uri = FileProvider.getUriForFile(
@@ -212,41 +236,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) {
@@ -265,13 +289,14 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
private fun createDeviceUpdateRequestData(): DeviceUpdateRequest {
return DeviceUpdateRequest(
serial_no = sharedPreference.getString(Constants.DEVICE_ID, "")
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"
}
@@ -284,4 +309,6 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
"N/A"
}
}
}

View File

@@ -11,7 +11,7 @@
* // from ShanMukha Innovations Pvt. Ltd.
*/
package com.example.hpostesting.presentation.dashboard
package com.example.hpostesting.presentation.main_base
import android.annotation.SuppressLint
import android.content.ComponentName
@@ -25,17 +25,20 @@ import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.presentation.reportgen.ReportActivity
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.main_base.ui.PasswordResetActivity
import com.example.hpostesting.presentation.deviceinfo.DeviceActivity
import com.example.hpostesting.presentation.deviceprovision.DeviceProvisionActivity
import com.example.hpostesting.presentation.diagnostics.DiagnosticsActivity
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.example.hpostesting.presentation.trueheme_test.TrueHemeTestViewModel
import com.example.hpostesting.presentation.usb_teminal.UsbTerminalActivity
import `in`.sminnovations.hpostesting.databinding.FragmentGalleryBinding
class GalleryFragment : Fragment() {
class PanelFragment : Fragment() {
private var _binding: FragmentGalleryBinding? = null
private lateinit var sharedPreferences: SharedPreferences
@@ -47,7 +50,7 @@ class GalleryFragment : Fragment() {
private lateinit var sharedPreference: SharedPreferences
private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels()
private val trueHemeTestViewModel: TrueHemeTestViewModel by activityViewModels()
@SuppressLint("SetTextI18n")
override fun onCreateView(
@@ -71,13 +74,51 @@ class GalleryFragment : Fragment() {
) {
binding.btnDeviceProvision.visibility = View.VISIBLE
} else {
binding.btnDeviceProvision.visibility = View.VISIBLE
binding.btnDeviceProvision.visibility = View.GONE
}
if (sharedPreference.getString(Constants.USER_ID, "").toString() == "ADMIN") {
binding.btnDeviceProvision.visibility = View.VISIBLE
binding.btnAutoDac.visibility = View.VISIBLE
binding.btnDeviceProvision.visibility = View.VISIBLE
binding.btnDiagnostics.visibility = View.VISIBLE
binding.btnFiles.visibility = View.VISIBLE
binding.btnFirefox.visibility = View.VISIBLE
binding.btnCalibration.visibility = View.VISIBLE
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
binding.btnPrintReport.visibility = View.VISIBLE
}else{
binding.btnResetPassword.visibility = View.GONE
binding.btnDeviceProvision.visibility = View.GONE
binding.btnAutoDac.visibility = View.VISIBLE
binding.btnDeviceProvision.visibility = View.GONE
binding.btnDiagnostics.visibility = View.VISIBLE
binding.btnFiles.visibility = View.GONE
binding.btnFirefox.visibility = View.GONE
binding.btnCalibration.visibility = View.GONE
binding.btnUsbTerminal.visibility = View.GONE
binding.btnSubmit.visibility = View.GONE
binding.btnDeviceInfo.visibility = View.VISIBLE
binding.btnUpdateValues.visibility = View.GONE
binding.btnPrintReport.visibility = View.VISIBLE
}
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))
}
@@ -98,12 +139,17 @@ class GalleryFragment : Fragment() {
startActivity(Intent(requireContext(), DeviceActivity::class.java))
}
binding.btnPrintReport.setOnClickListener{
startActivity(Intent(requireContext(), ReportActivity::class.java))
}
binding.btnFirefox.setOnClickListener {
val intent = Intent(Intent.ACTION_VIEW)
intent.component = ComponentName("org.mozilla.firefox", "org.mozilla.gecko.BrowserApp")
startActivity(intent)
}
binding.btnFiles.setOnClickListener {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "file/*"

View File

@@ -0,0 +1,430 @@
/*
* // 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.main_base
import android.content.Context
import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.os.Bundle
import android.text.InputFilter
import android.text.InputType
import android.view.Gravity
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.core.content.ContextCompat
import androidx.core.content.edit
import androidx.fragment.app.Fragment
import androidx.preference.EditTextPreference
import androidx.preference.ListPreference
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreferenceCompat
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.data.repository.DatabaseRepository
import com.example.hpostesting.firebase.FirebaseConfig
import com.example.hpostesting.firebase.FirebaseManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentSlideshowBinding
private var isLanguageChanged = false
private val DEFAULT_DISCLAIMER = """
DISCLAIMER: This report is generated by HemoCube automated system.
Results should be interpreted by qualified medical professionals.
This report is for diagnostic purposes only and should not be used as the sole basis for medical decisions.
Please consult with your healthcare provider for proper interpretation and treatment recommendations.
""".trimIndent()
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)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.nameEditText.setText(sharedPreferences.getString(Constants.LABNAME, ""))
selectedItem = sharedPreferences.getString(Constants.CUVETTE_SIZE, "10mm").toString()
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
).show()
}
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() {
private lateinit var tapManager: AppVersionTapManager
private lateinit var serverPreference: Preference
private lateinit var currentServerPreference: Preference
lateinit var firebaseManager: FirebaseManager
var autoSmbtValue = false
var reportDisclaimerText = DEFAULT_DISCLAIMER
private var topDevMode = false
lateinit var databaseRepository: DatabaseRepository
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
firebaseManager = FirebaseManager(requireContext())
databaseRepository = (activity as DashboardActivity).databaseRepository
tapManager = AppVersionTapManager()
topDevMode = firebaseManager.getDevMode()
val sharedPreference =
requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
autoSmbtValue = sharedPreference.getBoolean("AutSmbt", false)
reportDisclaimerText = sharedPreference.getString("report_dis_txt", DEFAULT_DISCLAIMER).toString()
val preferenceScreen = preferenceManager.createPreferenceScreen(requireContext())
val currentServer = firebaseManager.getLastSelectedServer().serverName
val arWeAdmin =sharedPreference.getString(Constants.USER_ID, "").toString() == "ADMIN"
val MAX_CHARS = 10_000
// 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)
onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->
val languageCode = newValue as String
updateLanguage(requireContext(), languageCode)
true
}
}
val servers = firebaseManager.getAvailableServers()
val serverNames = servers.map { it.serverName }.toTypedArray()
val serverSelectorPreference = CustomDialogPreference(requireContext()).apply {
key = "server_preference"
title = "Select the Server"
summary = "Current server: $currentServer"
setEntries(serverNames)
setEntryValues(serverNames)
setValue(currentServer)
icon = ContextCompat.getDrawable(requireContext(), R.drawable.baseline_cloud_sync_24)
setOnPreferenceChangeListener { newValue ->
val preferenceConfig = servers.find { it.serverName == newValue }
switchFirebaseServer(preferenceConfig!!)
true
}
}
// Add preferences to screen
preferenceScreen.addPreference(languagePreference)
preferenceScreen.addPreference(languagePreference)
val developerToggle = SwitchPreferenceCompat(requireContext()).apply {
title = "Developer Options"
summary = "Enable or disable developer options"
icon =
ContextCompat.getDrawable(requireContext(), R.drawable.baseline_developer_mode_24)
key = "developer_options" // Unique key for SharedPreferences
// Load toggle state from SharedPreferences
isChecked = firebaseManager.getDevMode()
setOnPreferenceChangeListener { _, newValue ->
val isEnabled = newValue as Boolean
firebaseManager.setDevModeOn(isEnabled)
if (!isEnabled) {
preferenceScreen.removePreference(this)
preferenceScreen.removePreference(serverSelectorPreference)
}
if (!firebaseManager.getDevMode() && currentServer != "prod"){
val prodConfig = servers.find { it.serverName == "prod" }
switchFirebaseServer(prodConfig!!)
}
true
}
}
val disclaimerPreference = EditTextPreference(requireContext()).apply {
key = "Report_disclaimer"
title = "Report disclaimer Editor"
icon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_add)
summaryProvider = Preference.SummaryProvider<EditTextPreference> { preference ->
val value = preference.text
if (value.isNullOrBlank()) {
"Current disclaimer: (not set)"
} else {
"Current disclaimer: $value"
}
}
setOnBindEditTextListener { edit ->
edit.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_MULTI_LINE
edit.minLines = 4
edit.maxLines = 10
edit.gravity = Gravity.TOP or Gravity.START
edit.filters = arrayOf(InputFilter.LengthFilter(MAX_CHARS))
}
setOnPreferenceChangeListener { _, newValue ->
val text = (newValue as? String)?.trim().orEmpty()
if (text.length > MAX_CHARS) {
Toast.makeText(
requireContext(),
"Text too long (${text.length}/$MAX_CHARS).",
Toast.LENGTH_SHORT
).show()
return@setOnPreferenceChangeListener false
}else{
sharedPreference.edit().putString("report_dis_txt", text).apply()
}
true
}
}
val resetDisclaimerPreference = Preference(requireContext()).apply {
title = "Reset to default Disclaimer"
summary = "Replace the current text with the apps default disclaimer"
icon = ContextCompat.getDrawable(requireContext(), R.drawable.baseline_restore_24)
setOnPreferenceClickListener {
sharedPreference.edit().putString("report_dis_txt", DEFAULT_DISCLAIMER).apply()
disclaimerPreference.text = DEFAULT_DISCLAIMER
Toast.makeText(requireContext(), "Disclaimer reset to default", Toast.LENGTH_SHORT).show()
true
}
}
val autosmbt = SwitchPreferenceCompat(requireContext()).apply {
title = "Auto submit"
summary = "Enable or disable Auto submit"
icon =
ContextCompat.getDrawable(requireContext(), R.drawable.baseline_motion_auto_24)
key = "auto_submit_key" // Unique key for SharedPreferences
// Load toggle state from SharedPreferences
isChecked = autoSmbtValue
setOnPreferenceChangeListener { _, newValue ->
val isEnabled = newValue as Boolean
sharedPreference.edit {
putBoolean("AutSmbt",isEnabled)
}
true
}
}
val appVersionPreference = Preference(requireContext()).apply {
title = "App Version"
summary =
getAppVersion(requireContext()) + " [ " + getAppEnvironment(requireContext()) + "->" + currentServer + "]"
icon = ContextCompat.getDrawable(requireContext(), R.drawable.baseline_info_24)
setOnPreferenceClickListener {
tapManager.registerTap {
if (arWeAdmin) {
firebaseManager.setDevModeOn(true)
if (firebaseManager.getDevMode() && currentServer != "dev") {
Toast.makeText(requireContext(), "Now you are a Developer", Toast.LENGTH_SHORT).show()
Toast.makeText(requireContext(), "Setting Up developer Environment", Toast.LENGTH_SHORT).show()
}
if (preferenceScreen.findPreference<SwitchPreferenceCompat>("developer_options") == null) {
preferenceScreen.addPreference(developerToggle)
preferenceScreen.addPreference(autosmbt)
preferenceScreen.addPreference(disclaimerPreference)
preferenceScreen.addPreference(resetDisclaimerPreference)
}
if (preferenceScreen.findPreference<ListPreference>("server_preference") == null) {
preferenceScreen.addPreference(serverSelectorPreference)
}
developerToggle.isChecked = true
updateServerPreference(currentServer)
}else{
Toast.makeText(requireContext(), "Works Only On Admin Mode", Toast.LENGTH_SHORT).show()
}
}
true
}
}
preferenceScreen.addPreference(appVersionPreference)
if (firebaseManager.getDevMode() && arWeAdmin) {
developerToggle.isChecked = true // Ensure it's checked
preferenceScreen.addPreference(developerToggle)
preferenceScreen.addPreference(serverSelectorPreference)
preferenceScreen.addPreference(autosmbt)
preferenceScreen.addPreference(resetDisclaimerPreference)
preferenceScreen.addPreference(disclaimerPreference)
}
setPreferenceScreen(preferenceScreen)
if (isLanguageChanged) {
Toast.makeText(requireContext(), R.string.language_update, Toast.LENGTH_SHORT).show()
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
listView.setPadding(0, 0, 0, 300) // Add bottom padding
listView.clipToPadding = false
}
private fun updateServerPreference(newServer: String) {
(findPreference<CustomDialogPreference>("server_preference"))?.let { pref ->
pref.setValue(newServer)
pref.summary = "Current server: $newServer"
}
}
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()
}
private fun updateLanguage(context: Context, languageCode: String) {
LanguageManager.persistLanguagePreference(context, languageCode)
LanguageManager.setLocale(context, languageCode)
requireActivity().recreate()
isLanguageChanged = true
}
private fun getAppVersion(context: Context): String {
return try {
val pInfo = context.packageManager.getPackageInfo(context.packageName, 0)
pInfo.versionName
} catch (e: PackageManager.NameNotFoundException) {
"N/A"
}
}
private fun getAppEnvironment(context: Context): String {
return try {
val pInfo = context.packageManager.getPackageInfo(context.packageName, 0)
pInfo.packageName.substringAfterLast('.')
} catch (e: PackageManager.NameNotFoundException) {
"N/A"
}
}
}
// CustomDialogPreference.kt
class CustomDialogPreference(context: Context) : Preference(context) {
private var entries: Array<String> = arrayOf()
private var entryValues: Array<String> = arrayOf()
private var currentValue: String = ""
private var onValueChangeListener: ((String) -> Boolean)? = null
fun setEntries(entries: Array<String>) {
this.entries = entries
}
fun setEntryValues(values: Array<String>) {
this.entryValues = values
}
fun setValue(value: String) {
currentValue = value
persistString(value)
}
fun setOnPreferenceChangeListener(listener: (String) -> Boolean) {
onValueChangeListener = listener
}
override fun onClick() {
val builder = MaterialAlertDialogBuilder(context)
builder.setTitle(title)
builder.setSingleChoiceItems(entries, entries.indexOf(currentValue)) { dialog, which ->
val newValue = entryValues[which]
if (onValueChangeListener?.invoke(newValue) == true) {
setValue(newValue)
dialog.dismiss()
}
}
builder.setNegativeButton("Cancel") { dialog, _ ->
dialog.dismiss()
}
builder.show()
}
}

View File

@@ -0,0 +1,45 @@
/*
* // 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.main_base
import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.example.hpostesting.data.constant.Constants
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

@@ -0,0 +1,371 @@
/*
* // 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.main_base.ui
import com.example.hpostesting.util.SecureStorage
import android.accounts.Account
import android.accounts.AccountManager
import android.annotation.SuppressLint
import android.content.Context
import android.content.SharedPreferences
import android.location.Location
import android.location.LocationListener
import android.location.LocationManager
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.navigation.fragment.findNavController
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.util.AppInitializer
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() {
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
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
_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
}
@RequiresApi(Build.VERSION_CODES.M)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
init()
// 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)
// 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().trim()
val password = binding.password.text.toString().trim()
if (loginId.isNotBlank() && password.isNotBlank()) {
performLogin(loginId, 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 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) {
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()
}
// 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() {
super.onDestroyView()
_binding = null
}
/** Check if we can get our location */
@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.GPS_PROVIDER
val locationListenerNetwork: LocationListener
val locationListenerGPS: LocationListener
var gps_enabled = false
var network_enabled = false
//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
try {
gps_enabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
} catch (ex: Exception) {
}
try {
network_enabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
} catch (ex: Exception) {
}
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 */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
)
}
override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {
Log.d(TAG, "GP location found 1")
}
override fun onProviderEnabled(provider: String) {
Log.d(TAG, "GP location found 2")
}
override fun onProviderDisabled(provider: String) {
Log.d(TAG, "GP location found 3")
}
}
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 {
override fun onLocationChanged(location: Location) {
Log.d(
TAG,
"NW: Latitude: " + location.latitude + ", Longitude = " + location.longitude
)
}
override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {
Log.d(TAG, "location found 1")
}
override fun onProviderEnabled(provider: String) {
Log.d(TAG, "location found 2")
}
override fun onProviderDisabled(provider: String) {
Log.d(TAG, "location found 3")
}
}
locationManager.requestLocationUpdates(
locationProviderWifi,
0,
0f,
locationListenerNetwork
)
} catch (e: Exception) {
Log.e(TAG, "NW Location Exception: " + e.message)
}
}
// 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 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.main_base.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

@@ -0,0 +1,21 @@
package com.example.hpostesting.presentation.reportgen
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.hpostesting.presentation.reportgen.ui.report.ReportFragment
import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.R
@AndroidEntryPoint
class ReportActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.report_gen)
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction()
.replace(R.id.container, ReportFragment()) //Direct constructor
.commitNow()
}
}
}

View File

@@ -0,0 +1,70 @@
package com.example.hpostesting.presentation.reportgen.ui.report
import android.graphics.Color
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.cardview.widget.CardView
import androidx.recyclerview.widget.RecyclerView
import com.example.hpostesting.data.dao.HemoCubeBufferDao
import com.example.hpostesting.data.model.patient.BufferCheckData
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import `in`.sminnovations.hpostesting.R
class BufferAdapter(
private var dataList: List<HemoCubeTestData>,
private val onItemClick: (HemoCubeTestData) -> Unit
) : RecyclerView.Adapter<BufferAdapter.ViewHolder>() {
private var selectedItems: List<HemoCubeTestData> = emptyList()
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val cardView: CardView = view.findViewById(R.id.cardView)
val sampleId: TextView = view.findViewById(R.id.sampleId)
val testTime: TextView = view.findViewById(R.id.testTime)
val result: TextView = view.findViewById(R.id.result)
val selectionIndicator: View = view.findViewById(R.id.selectionIndicator)
init {
cardView.setOnClickListener {
if (adapterPosition != RecyclerView.NO_POSITION) {
onItemClick(dataList[adapterPosition])
}
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.item_buffer_card, parent, false)
)
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = dataList[position]
val isSelected = selectedItems.contains(item)
holder.sampleId.text = "Sample ID: ${item._id}"
holder.testTime.text = "Time: ${item.testTime}"
holder.result.text = "Result: ${item.classificationResult}"
// Update selection appearance
if (isSelected) {
holder.cardView.setCardBackgroundColor(Color.parseColor("#E3F2FD"))
holder.selectionIndicator.visibility = View.VISIBLE
} else {
holder.cardView.setCardBackgroundColor(Color.WHITE)
holder.selectionIndicator.visibility = View.GONE
}
}
override fun getItemCount() = dataList.size
fun updateList(newList: List<HemoCubeTestData>) {
dataList = newList
notifyDataSetChanged()
}
fun updateSelectedItems(newSelectedItems: List<HemoCubeTestData>) {
selectedItems = newSelectedItems
notifyDataSetChanged()
}
}

View File

@@ -0,0 +1,326 @@
package com.example.hpostesting.presentation.reportgen.ui.report
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Typeface
import android.graphics.pdf.PdfDocument
import android.util.Log
import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import `in`.sminnovations.hpostesting.R
import java.io.File
import java.io.FileOutputStream
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
object ReportGen {
private const val PAGE_WIDTH = 595 // A4 width in points
private const val PAGE_HEIGHT = 842 // A4 height in points
private const val MARGIN_LEFT = 50f
private const val MARGIN_RIGHT = 50f
private const val MARGIN_TOP = 80f
private const val MARGIN_BOTTOM = 80f
fun generate(context: Context, dataList: List<HemoCubeTestData>,disclaimerText: String) {
if (dataList.isEmpty()) {
Toast.makeText(context, "No items selected for report generation", Toast.LENGTH_SHORT).show()
return
}
Log.d("ReportGen", "Generating report for ${dataList.size} items")
val message = if (dataList.size == 1) {
"Report for kit ${dataList.first()._id} started."
} else {
"Report for ${dataList.size} kits started."
}
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
val pdfFile = createProfessionalPdfReport(context, dataList, disclaimerText)
previewPdf(context, pdfFile)
}
private fun createProfessionalPdfReport(context: Context, dataList: List<HemoCubeTestData>,disclaimerText : String): File {
val timestamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
val file = File(context.getExternalFilesDir(null), "HemoCube_Report_$timestamp.pdf")
val pdfDocument = PdfDocument()
// Paint styles
val headerPaint = Paint().apply {
typeface = Typeface.create(Typeface.DEFAULT_BOLD, Typeface.BOLD)
textSize = 20f
color = Color.rgb(0, 102, 153) // Professional blue
}
val titlePaint = Paint().apply {
typeface = Typeface.create(Typeface.DEFAULT_BOLD, Typeface.BOLD)
textSize = 18f
color = Color.BLACK
}
val sectionHeaderPaint = Paint().apply {
typeface = Typeface.create(Typeface.DEFAULT_BOLD, Typeface.BOLD)
textSize = 14f
color = Color.rgb(0, 102, 153)
}
val contentPaint = Paint().apply {
textSize = 11f
color = Color.DKGRAY
}
val boldContentPaint = Paint().apply {
typeface = Typeface.create(Typeface.DEFAULT_BOLD, Typeface.BOLD)
textSize = 11f
color = Color.BLACK
}
val disclaimerPaint = Paint().apply {
textSize = 9f
color = Color.GRAY
typeface = Typeface.create(Typeface.DEFAULT, Typeface.ITALIC)
}
// Create one page per test data
dataList.forEachIndexed { index, testData ->
val pageInfo = PdfDocument.PageInfo.Builder(PAGE_WIDTH, PAGE_HEIGHT, index + 1).create()
val page = pdfDocument.startPage(pageInfo)
val canvas = page.canvas
drawPage(canvas, testData, index + 1, dataList.size,
headerPaint, titlePaint, sectionHeaderPaint,
contentPaint, boldContentPaint, disclaimerPaint,disclaimerText,context)
pdfDocument.finishPage(page)
}
pdfDocument.writeTo(FileOutputStream(file))
pdfDocument.close()
return file
}
private fun drawPage(
canvas: Canvas,
testData: HemoCubeTestData,
pageNumber: Int,
totalPages: Int,
headerPaint: Paint,
titlePaint: Paint,
sectionHeaderPaint: Paint,
contentPaint: Paint,
boldContentPaint: Paint,
disclaimerPaint: Paint,
disclaimerText: String,
context: Context
) {
var currentY = MARGIN_TOP
// Header with logo placeholder and title
drawHeader(canvas, headerPaint, titlePaint, currentY, context)
currentY += 100f
// Sample Information Section
currentY = drawSection(canvas, "SAMPLE INFORMATION", sectionHeaderPaint, currentY)
currentY = drawKeyValuePair(canvas, "Sample ID:", testData.sampleid.toString(), boldContentPaint, contentPaint, currentY)
currentY = drawKeyValuePair(canvas, "Blood Group:", testData.bloodGroup, boldContentPaint, contentPaint, currentY)
currentY += 15f
// Test Information Section
currentY = drawSection(canvas, "TEST INFORMATION", sectionHeaderPaint, currentY)
currentY = drawKeyValuePair(canvas, "Test ID:", testData._id, boldContentPaint, contentPaint, currentY)
currentY = drawKeyValuePair(canvas, "Test Type:", testData.testType ?: "TrueHeme", boldContentPaint, contentPaint, currentY)
currentY = drawKeyValuePair(canvas, "Test Time:", testData.testTime ?: "N/A", boldContentPaint, contentPaint, currentY)
currentY = drawKeyValuePair(canvas, "Incubation Time:", testData.incubationTime, boldContentPaint, contentPaint, currentY)
currentY = drawKeyValuePair(canvas, "Kit Serial:", testData.kitSerial, boldContentPaint, contentPaint, currentY)
currentY = drawKeyValuePair(canvas, "Device Serial:", testData.deviceSerialNumber, boldContentPaint, contentPaint, currentY)
currentY += 15f
// Test Results Section
currentY = drawSection(canvas, "TEST RESULTS", sectionHeaderPaint, currentY)
currentY = drawKeyValuePair(canvas, "Classification Result:", testData.classificationResult, boldContentPaint, contentPaint, currentY)
currentY = drawKeyValuePair(canvas, "Device Ratio:", testData.deviceRatio?.toString() ?: "N/A", boldContentPaint, contentPaint, currentY)
currentY = drawKeyValuePair(canvas, "Calculated Ratio:", testData.calculatedRatio?.toString() ?: "N/A", boldContentPaint, contentPaint, currentY)
currentY = drawKeyValuePair(canvas, "Slope Ratio:", testData.slopeRatio?.toString() ?: "N/A", boldContentPaint, contentPaint, currentY)
currentY += 15f
// LED Measurements Section
currentY = drawSection(canvas, "LED MEASUREMENTS", sectionHeaderPaint, currentY)
currentY = drawLEDData(canvas, testData, boldContentPaint, contentPaint, currentY)
currentY += 15f
// Laboratory Information Section
currentY = drawSection(canvas, "LABORATORY INFORMATION", sectionHeaderPaint, currentY)
currentY = drawKeyValuePair(canvas, "Lab Name:", testData.labName ?: "N/A", boldContentPaint, contentPaint, currentY)
currentY = drawKeyValuePair(canvas, "Center Name:", testData.centerName ?: "N/A", boldContentPaint, contentPaint, currentY)
currentY = drawKeyValuePair(canvas, "District:", testData.district ?: "N/A", boldContentPaint, contentPaint, currentY)
currentY += 15f
// Footer with page number and disclaimer
drawFooter(canvas, pageNumber, totalPages, contentPaint, disclaimerPaint,disclaimerText)
}
private fun drawHeader(canvas: Canvas, headerPaint: Paint, titlePaint: Paint, startY: Float, context: Context) {
// Load and draw actual logo
try {
// Method 1: Load from drawable resources
val logoDrawable = ContextCompat.getDrawable(context, R.mipmap.hpos_icon) // Replace with your logo resource
logoDrawable?.let { drawable ->
val logoWidth = 70
val logoHeight = 60
drawable.setBounds(
MARGIN_LEFT.toInt(),
(startY - 20f).toInt(),
(MARGIN_LEFT + logoWidth).toInt(),
(startY + logoHeight - 20f).toInt()
)
drawable.draw(canvas)
}
} catch (e: Exception) {
// Fallback to placeholder if logo loading fails
val logoPaint = Paint().apply {
color = Color.rgb(0, 102, 153)
style = Paint.Style.FILL
}
canvas.drawRect(MARGIN_LEFT, startY - 20f, MARGIN_LEFT + 60f, startY + 20f, logoPaint)
// Draw "LOGO" text as placeholder
val placeholderPaint = Paint().apply {
color = Color.WHITE
textSize = 12f
typeface = Typeface.create(Typeface.DEFAULT_BOLD, Typeface.BOLD)
textAlign = Paint.Align.CENTER
}
canvas.drawText("LOGO", MARGIN_LEFT + 30f, startY, placeholderPaint)
}
// Company name and title
canvas.drawText("HemoCube", MARGIN_LEFT + 80f, startY + 10f, headerPaint)
canvas.drawText("Medical Test Report", MARGIN_LEFT, startY + 40f, titlePaint)
// Report generation date
val currentDate = SimpleDateFormat("dd MMM yyyy, HH:mm", Locale.getDefault()).format(Date())
canvas.drawText("Generated: $currentDate", PAGE_WIDTH - MARGIN_RIGHT - 150f, startY + 10f, Paint().apply {
textSize = 10f
color = Color.GRAY
})
// Line under header
val linePaint = Paint().apply {
color = Color.rgb(0, 102, 153)
strokeWidth = 2f
}
canvas.drawLine(MARGIN_LEFT, startY + 60f, PAGE_WIDTH - MARGIN_RIGHT, startY + 60f, linePaint)
}
private fun drawSection(canvas: Canvas, title: String, paint: Paint, y: Float): Float {
canvas.drawText(title, MARGIN_LEFT, y, paint)
// Underline for section
val linePaint = Paint().apply {
color = Color.rgb(0, 102, 153)
strokeWidth = 1f
}
canvas.drawLine(MARGIN_LEFT, y + 5f, MARGIN_LEFT + paint.measureText(title), y + 5f, linePaint)
return y + 25f
}
private fun drawKeyValuePair(canvas: Canvas, key: String, value: String, keyPaint: Paint, valuePaint: Paint, y: Float): Float {
canvas.drawText(key, MARGIN_LEFT + 10f, y, keyPaint)
canvas.drawText(value, MARGIN_LEFT + 150f, y, valuePaint)
return y + 18f
}
private fun drawLEDData(canvas: Canvas, testData: HemoCubeTestData, keyPaint: Paint, valuePaint: Paint, startY: Float): Float {
var currentY = startY
currentY = drawKeyValuePair(canvas, "LED1 Sample:", testData.led1Sample?.toString() ?: "N/A", keyPaint, valuePaint, currentY)
currentY = drawKeyValuePair(canvas, "LED2 Sample:", testData.led2Sample?.toString() ?: "N/A", keyPaint, valuePaint, currentY)
currentY = drawKeyValuePair(canvas, "LED3 Sample:", testData.led3Sample?.toString() ?: "N/A", keyPaint, valuePaint, currentY)
currentY = drawKeyValuePair(canvas, "LED4 Sample:", testData.led4Sample?.toString() ?: "N/A", keyPaint, valuePaint, currentY)
currentY = drawKeyValuePair(canvas, "ABS1:", testData.abs1?.toString() ?: "N/A", keyPaint, valuePaint, currentY)
currentY = drawKeyValuePair(canvas, "ABS2:", testData.abs2?.toString() ?: "N/A", keyPaint, valuePaint, currentY)
currentY = drawKeyValuePair(canvas, "ABS3:", testData.abs3?.toString() ?: "N/A", keyPaint, valuePaint, currentY)
currentY = drawKeyValuePair(canvas, "ABS4:", testData.abs4?.toString() ?: "N/A", keyPaint, valuePaint, currentY)
return currentY
}
private fun drawFooter(canvas: Canvas, pageNumber: Int, totalPages: Int, contentPaint: Paint, disclaimerPaint: Paint,disclaimerText: String) {
val footerY = PAGE_HEIGHT - MARGIN_BOTTOM + 20f
// Page number
canvas.drawText("Page $pageNumber of $totalPages", PAGE_WIDTH - MARGIN_RIGHT - 80f, footerY, contentPaint)
// Disclaimer
val disclaimerLines = wrapText(disclaimerText, disclaimerPaint, PAGE_WIDTH - MARGIN_LEFT - MARGIN_RIGHT)
var disclaimerY = footerY + 20f
disclaimerLines.forEach { line ->
canvas.drawText(line, MARGIN_LEFT, disclaimerY, disclaimerPaint)
disclaimerY += 12f
}
// Footer line
val linePaint = Paint().apply {
color = Color.rgb(0, 102, 153)
strokeWidth = 1f
}
canvas.drawLine(MARGIN_LEFT, footerY - 10f, PAGE_WIDTH - MARGIN_RIGHT, footerY - 10f, linePaint)
}
private fun wrapText(text: String, paint: Paint, maxWidth: Float): List<String> {
val words = text.split(" ")
val lines = mutableListOf<String>()
var currentLine = ""
for (word in words) {
val testLine = if (currentLine.isEmpty()) word else "$currentLine $word"
if (paint.measureText(testLine) <= maxWidth) {
currentLine = testLine
} else {
if (currentLine.isNotEmpty()) {
lines.add(currentLine)
}
currentLine = word
}
}
if (currentLine.isNotEmpty()) {
lines.add(currentLine)
}
return lines
}
private fun previewPdf(context: Context, file: File) {
val uri = FileProvider.getUriForFile(
context,
"${context.packageName}.fileprovider",
file
)
val intent = Intent(Intent.ACTION_VIEW).apply {
setDataAndType(uri, "application/pdf")
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_ACTIVITY_NO_HISTORY
}
try {
context.startActivity(intent)
} catch (e: ActivityNotFoundException) {
Toast.makeText(context, "No PDF viewer found", Toast.LENGTH_SHORT).show()
}
}
}

View File

@@ -0,0 +1,219 @@
package com.example.hpostesting.presentation.reportgen.ui.report
import android.app.DatePickerDialog
import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.Button
import android.widget.EditText
import android.widget.Spinner
import android.widget.TextView
import android.widget.Toast
import androidx.core.widget.addTextChangedListener
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.R
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import java.util.Locale
private val DEFAULT_DISCLAIMER = """
DISCLAIMER: This report is generated by HemoCube automated system.
Results should be interpreted by qualified medical professionals.
This report is for diagnostic purposes only and should not be used as the sole basis for medical decisions.
Please consult with your healthcare provider for proper interpretation and treatment recommendations.
""".trimIndent()
@AndroidEntryPoint
class ReportFragment : Fragment() {
companion object {
fun newInstance() = ReportFragment()
}
private lateinit var sharedPreferences: SharedPreferences
private val viewModel: ReportViewModel by viewModels()
private lateinit var recyclerView: RecyclerView
private lateinit var searchBar: EditText
private lateinit var filterSpinner: Spinner
private lateinit var generateBtn: Button
private lateinit var selectedCountText: TextView
private lateinit var calendarButton: Button
private lateinit var adapter: BufferAdapter
private var selectedItems: MutableList<HemoCubeTestData> = mutableListOf()
private var allData: List<HemoCubeTestData> = emptyList()
private var currentFilter = "Today"
private var customDate: String? = null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View = inflater.inflate(R.layout.fragment_report, container, false)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
sharedPreferences = requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
initViews(view)
setupRecyclerView()
setupFilterSpinner()
setupObservers()
setupListeners()
// Set default filter to Today
setDefaultFilter()
}
private fun initViews(view: View) {
recyclerView = view.findViewById(R.id.bufferRecyclerView)
searchBar = view.findViewById(R.id.searchBar)
filterSpinner = view.findViewById(R.id.filterSpinner)
generateBtn = view.findViewById(R.id.generateReportButton)
selectedCountText = view.findViewById(R.id.selectedCountText)
calendarButton = view.findViewById(R.id.calendarButton)
}
private fun setupRecyclerView() {
recyclerView.layoutManager = LinearLayoutManager(requireContext())
adapter = BufferAdapter(emptyList()) { item ->
toggleItemSelection(item)
updateUI()
}
recyclerView.adapter = adapter
}
private fun setupFilterSpinner() {
val filterOptions = arrayOf("Today", "Yesterday", "All", "Custom Date")
val spinnerAdapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, filterOptions)
spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
filterSpinner.adapter = spinnerAdapter
}
private fun setDefaultFilter() {
filterSpinner.setSelection(0) // Today
currentFilter = "Today"
calendarButton.visibility = View.GONE
}
private fun setupObservers() {
viewModel.allKitTestData.observe(viewLifecycleOwner) { list ->
allData = list
filterList(searchBar.text.toString(), currentFilter)
}
}
private fun setupListeners() {
searchBar.addTextChangedListener { editable ->
filterList(editable.toString(), currentFilter)
}
filterSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>, view: View?, pos: Int, id: Long) {
currentFilter = parent.getItemAtPosition(pos).toString()
if (currentFilter == "Custom Date") {
calendarButton.visibility = View.VISIBLE
if (customDate == null) {
showDatePicker()
} else {
filterList(searchBar.text.toString(), currentFilter)
}
} else {
calendarButton.visibility = View.GONE
customDate = null
filterList(searchBar.text.toString(), currentFilter)
}
}
override fun onNothingSelected(p0: AdapterView<*>?) {}
}
calendarButton.setOnClickListener {
showDatePicker()
}
generateBtn.setOnClickListener {
if (selectedItems.isNotEmpty()) {
ReportGen.generate(requireContext(), selectedItems, disclaimerText = sharedPreferences.getString("report_dis_txt",
DEFAULT_DISCLAIMER).toString())
}
}
}
private fun showDatePicker() {
val calendar = Calendar.getInstance()
val year = calendar.get(Calendar.YEAR)
val month = calendar.get(Calendar.MONTH)
val day = calendar.get(Calendar.DAY_OF_MONTH)
DatePickerDialog(requireContext(), { _, selectedYear, selectedMonth, selectedDay ->
val sdf = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
val selectedCalendar = Calendar.getInstance()
selectedCalendar.set(selectedYear, selectedMonth, selectedDay)
customDate = sdf.format(selectedCalendar.time)
// Update calendar button text
val displayFormat = SimpleDateFormat("MMM dd, yyyy", Locale.getDefault())
calendarButton.text = displayFormat.format(selectedCalendar.time)
filterList(searchBar.text.toString(), currentFilter)
}, year, month, day).show()
}
private fun toggleItemSelection(item: HemoCubeTestData) {
if (selectedItems.contains(item)) {
selectedItems.remove(item)
} else {
selectedItems.add(item)
}
adapter.updateSelectedItems(selectedItems)
}
private fun updateUI() {
selectedCountText.text = "Selected: ${selectedItems.size}"
generateBtn.visibility = if (selectedItems.isNotEmpty()) View.VISIBLE else View.GONE
}
private fun filterList(query: String, filter: String) {
val sdf = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
val today = sdf.format(Date())
val calendar = Calendar.getInstance()
calendar.add(Calendar.DAY_OF_MONTH, -1)
val yesterday = sdf.format(calendar.time)
val filtered = allData.filter { item ->
val matchesSearch = item._id.contains(query, true) ||
item.classificationResult.contains(query, true)
val matchesDate = when (filter) {
"Today" -> item.testTime?.contains(today)
"Yesterday" -> item.testTime?.contains(yesterday)
"Custom Date" -> customDate?.let { item.testTime?.contains(it) } ?: true
"All" -> true
else -> true
}
matchesSearch && matchesDate ?: true
}
adapter.updateList(filtered)
// Clear selections if items are no longer visible
selectedItems.removeAll { selectedItem ->
!filtered.contains(selectedItem)
}
adapter.updateSelectedItems(selectedItems)
updateUI()
}
}

View File

@@ -0,0 +1,19 @@
package com.example.hpostesting.presentation.reportgen.ui.report
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import com.example.hpostesting.data.dao.HemoCubeBufferDao
import com.example.hpostesting.data.dao.HemoCubeDao
import com.example.hpostesting.data.model.patient.BufferCheckData
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
@HiltViewModel
class ReportViewModel @Inject constructor(
private val hemoCubeDao: HemoCubeDao,
) : ViewModel() {
val allKitTestData: LiveData<List<HemoCubeTestData>> = hemoCubeDao.getAll()
}

View File

@@ -13,7 +13,7 @@
package com.example.hpostesting.presentation.testRight
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.example.hpostesting.presentation.main_base.DashboardActivity
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
@@ -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

@@ -19,7 +19,6 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.util.NetworkStatusLiveData
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.dao.UserDao
import com.example.hpostesting.data.model.CalculationVariableForTest
@@ -36,6 +35,7 @@ import com.example.hpostesting.domain.SaveRawDataTest
import com.example.hpostesting.domain.SickleFindResultCaluculationWithMaxImpl
import com.example.hpostesting.domain.TestRightResultCalculation
import com.example.hpostesting.util.MyUtils
import com.example.hpostesting.util.NetworkMonitor
import com.google.firebase.storage.FirebaseStorage
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
@@ -55,10 +55,10 @@ class TestRightViewModel @Inject constructor(
private val saveRawDataTest: SaveRawDataTest,
private val repository: DatabaseRepository,
private val userDao: UserDao,
networkMonitor: NetworkMonitor,
context: Context?
) : ViewModel() {
var isServiceConnected = false
val progressBar = MutableLiveData(false)
@@ -69,9 +69,8 @@ class TestRightViewModel @Inject constructor(
var testDetails = DataHolder.selectedTest
private val _networkStatusLiveData = context?.let { NetworkStatusLiveData(it) }
val networkStatusLiveData: NetworkStatusLiveData?
get() = _networkStatusLiveData
private var _networkStatusLiveData = networkMonitor.isConnected
val networkStatusLiveData = _networkStatusLiveData
val allUserData = userDao.getAll()
@@ -82,6 +81,11 @@ class TestRightViewModel @Inject constructor(
val calculationVariableList = ArrayList<CalculationVariableForTest>()
init {
networkMonitor.startMonitoring()
_networkStatusLiveData = networkMonitor.isConnected
}
fun mapDeviceConstants(string: String) {
if (string.isNotEmpty()) {
val listOfStrings = string.split(",")
@@ -485,7 +489,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

@@ -36,8 +36,8 @@ 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.LanguageManager
import com.example.hpostesting.presentation.hemocube.HemoCubeFragment
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.example.hpostesting.presentation.trueheme_test.TrueHemeTestFragment
import com.example.hpostesting.presentation.trueheme_test.TrueHemeTestViewModel
import com.example.hpostesting.util.UsbService
import com.hoho.android.usbserial.driver.UsbSerialDriver
import com.hoho.android.usbserial.driver.UsbSerialProber
@@ -48,7 +48,7 @@ import `in`.sminnovations.hpostesting.databinding.ActivityHemocubeBinding
@AndroidEntryPoint
class TrueHemeActivity : AppCompatActivity() {
private lateinit var binding: ActivityHemocubeBinding
private val viewModel by viewModels<HemoCubeViewModel>()
private val viewModel by viewModels<TrueHemeTestViewModel>()
private var myMenu: Menu? = null
private lateinit var mDriver: UsbSerialDriver
@@ -177,14 +177,14 @@ class TrueHemeActivity : AppCompatActivity() {
private fun moveToNext() {
if (supportFragmentManager.isDestroyed) return
supportFragmentManager.beginTransaction().replace(binding.fghemocube.id, HemoCubeFragment())
supportFragmentManager.beginTransaction().replace(binding.fghemocube.id, TrueHemeTestFragment())
.commit()
}
override fun onBackPressed() {
val fragment = supportFragmentManager.findFragmentById(R.id.fghemocube)
if (fragment is HemoCubeFragment) {
if (fragment is TrueHemeTestFragment) {
fragment.handleBackButtonPress()
} else {
super.onBackPressed()

View File

@@ -36,8 +36,8 @@ import com.example.hpostesting.data.model.TestState
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.toHemoCubeTestData
import com.example.hpostesting.presentation.utils.UsbServiceListener
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.example.hpostesting.presentation.hemocube.HemocubeActivity
import com.example.hpostesting.presentation.main_base.DashboardActivity
import com.example.hpostesting.presentation.trueheme_test.TrueHemeTestActivity
import com.example.hpostesting.presentation.utils.MyDialogListener
import com.example.hpostesting.presentation.utils.UIUtils
import com.google.firebase.crashlytics.ktx.crashlytics
@@ -336,7 +336,7 @@ class TrueHemeFragment : Fragment() {
startListening.postValue(true)
try {
(activity as HemocubeActivity).mService.listenToHemoCube(object : UsbServiceListener {
(activity as TrueHemeTestActivity).mService.listenToHemoCube(object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
data?.let {
val stringData = String(it)
@@ -357,7 +357,7 @@ class TrueHemeFragment : Fragment() {
private fun getDeviceInfo() {
hemoCubeViewModel.progressBar.postValue(true)
(activity as HemocubeActivity).mService.sendAndListenToHemoCube(
(activity as TrueHemeTestActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.DEVICE_CONFIGURATION_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
@@ -593,7 +593,7 @@ class TrueHemeFragment : Fragment() {
binding.btnSubmit.visibility = View.VISIBLE
binding.btnSubmit.isEnabled = true
binding.btnSubmit.isClickable = true
// binding.clParent.setBackgroundColor(Color.parseColor("#edfffd"))
// binding.clParent.setBackgroundColor(Color.parseColor("#edfffd"))
binding.ivCheck.visibility = View.VISIBLE
}
} else {
@@ -736,7 +736,7 @@ class TrueHemeFragment : Fragment() {
}
}
private fun processResult() {
private fun processResult(){
try {
hemoCubeViewModel.messages.postValue(getString(R.string.processing_result))
val deviceLog = resultData
@@ -1067,7 +1067,7 @@ class TrueHemeFragment : Fragment() {
binding.btnPlacebuffer.visibility = View.GONE
}
(activity as HemocubeActivity).mService.sendAndListenToHemoCube(
(activity as TrueHemeTestActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.START_BUFFER_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {}
@@ -1081,7 +1081,7 @@ class TrueHemeFragment : Fragment() {
private fun startSampleProcess() {
hemoCubeViewModel.progressBar.postValue(true)
(activity as HemocubeActivity).mService.sendAndListenToHemoCube(
(activity as TrueHemeTestActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.START_SAMPLE,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {}
@@ -1095,7 +1095,7 @@ class TrueHemeFragment : Fragment() {
private fun sendFirstGainCommand() {
hemoCubeViewModel.progressBar.postValue(true)
(activity as HemocubeActivity).mService.sendAndListenToHemoCube(
(activity as TrueHemeTestActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.FIRST_GAIN_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {}
@@ -1109,7 +1109,7 @@ class TrueHemeFragment : Fragment() {
private fun sendSecondGainCommand() {
hemoCubeViewModel.progressBar.postValue(true)
(activity as HemocubeActivity).mService.sendAndListenToHemoCube(
(activity as TrueHemeTestActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.SECOND_GAIN_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {}
@@ -1123,7 +1123,7 @@ class TrueHemeFragment : Fragment() {
private fun sendThirdGainCommand() {
hemoCubeViewModel.progressBar.postValue(true)
(activity as HemocubeActivity).mService.sendAndListenToHemoCube(
(activity as TrueHemeTestActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.THIRD_GAIN_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {}
@@ -1137,7 +1137,7 @@ class TrueHemeFragment : Fragment() {
private fun sendForthGainCommand() {
hemoCubeViewModel.progressBar.postValue(true)
(activity as HemocubeActivity).mService.sendAndListenToHemoCube(
(activity as TrueHemeTestActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.FORTH_GAIN_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {}
@@ -1151,7 +1151,7 @@ class TrueHemeFragment : Fragment() {
private fun fetchResult() {
hemoCubeViewModel.progressBar.postValue(true)
(activity as HemocubeActivity).mService.sendAndListenToHemoCube(
(activity as TrueHemeTestActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.PRINT_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {}
@@ -1170,7 +1170,7 @@ class TrueHemeFragment : Fragment() {
private fun reconnect() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
(activity as HemocubeActivity).reconnectDevice()
(activity as TrueHemeTestActivity).reconnectDevice()
}
}
}

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
@@ -46,10 +43,12 @@ import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.toHemoCubeTestData
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.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.NetworkMonitor
import com.example.hpostesting.util.Result
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import okhttp3.MediaType.Companion.toMediaTypeOrNull
@@ -70,20 +69,22 @@ class TrueHemeViewModel @Inject constructor(
private val repository: Repository,
private val logFileManager: LogFileManager,
private val localFileDataSource: LocalFileDataSource,
networkMonitor: NetworkMonitor,
context: Context,
) : ViewModel() {
var isServiceConnected = false
val progressBar = MutableLiveData(false)
private val testDetails = DataHolder.selectedTest?.toHemoCubeTestData()
val messages = MutableLiveData<String>()
private val sharedPreference =
context.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
private val sharedPreference = context.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
private val workManager = WorkManager.getInstance(context)
// init {
// startPeriodicCheckUpdate()
// }
// init {
// startPeriodicCheckUpdate()
// }
init {
networkMonitor.startMonitoring()
}
val loginResponse = MutableLiveData<Result<LoginResponse>>()
@@ -97,7 +98,7 @@ class TrueHemeViewModel @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 = networkMonitor.isConnected
val allUserData = hemoCubeDao.getAll()
val allKitTestData = hemoCubeBufferDao.getAll()
val deviceData = MutableLiveData<DeviceData?>()
@@ -159,12 +160,12 @@ class TrueHemeViewModel @Inject constructor(
}
}
fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest) = viewModelScope.launch {
deviceUpdate.postValue(Result.Loading())
repository.deviceUpdate(deviceUpdateRequest).let {
deviceUpdate.postValue(it)
}
}
// fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest) = viewModelScope.launch {
// deviceUpdate.postValue(Result.Loading())
// repository.deviceUpdate(deviceUpdateRequest).let {
// deviceUpdate.postValue(it)
// }
// }
fun startPeriodicCheckUpdate() {
val periodicRequest = PeriodicWorkRequestBuilder<CheckUpdateWorker>(
@@ -181,7 +182,7 @@ class TrueHemeViewModel @Inject constructor(
val logFile = logFileManager.createLogFile().let { file ->
val requestBody = file?.asRequestBody("multipart/form-data".toMediaTypeOrNull())
val multipartFile =
requestBody?.let { MultipartBody.Part.createFormData("logFile", file?.name, it) }
requestBody?.let { MultipartBody.Part.createFormData("logFile", file.name, it) }
multipartFile?.let { partFile ->
repository.uploadLogs(partFile).let { result ->
uploadLogs.postValue(result)
@@ -193,37 +194,35 @@ class TrueHemeViewModel @Inject constructor(
fun uploadHemoCubeResultToDatabaseForBufferCheck(
isOnline: Boolean,
bufferCheckData: BufferCheckData,
) =
viewModelScope.launch {
if (isOnline) {
try {
when (val response =
repository.addTestToDatabaseforBufferCheck(bufferCheckData)) {
is Response.Success -> {
Log.i("Testdb", "Data uploaded to Firestore successfully")
fireBaseUpload.postValue("Success")
bufferCheckData.localFlag = true
hemoCubeBufferDao.insertAll(bufferCheckData)
}
is Response.Error -> {
Log.e("Testdb", "Error uploading data to Firestore: $response")
fireBaseUpload.postValue("Error")
bufferCheckData.localFlag = true
hemoCubeBufferDao.insertAll(bufferCheckData)
}
else -> {}
) = viewModelScope.launch {
if (isOnline) {
try {
when (val response = repository.addTestToDatabaseforBufferCheck(bufferCheckData)) {
is Response.Success -> {
Log.i("Testdb", "Data uploaded to Firestore successfully")
fireBaseUpload.postValue("Success")
bufferCheckData.localFlag = true
hemoCubeBufferDao.insertAll(bufferCheckData)
}
} catch (e: Exception) {
Log.e("Testdb", "Exception during data upload: ${e.message}")
fireBaseUpload.postValue("Error")
is Response.Error -> {
Log.e("Testdb", "Error uploading data to Firestore: $response")
fireBaseUpload.postValue("Error")
bufferCheckData.localFlag = true
hemoCubeBufferDao.insertAll(bufferCheckData)
}
else -> {}
}
} else {
hemoCubeBufferDao.insertAll(bufferCheckData)
fireBaseUpload.postValue("Local")
} catch (e: Exception) {
Log.e("Testdb", "Exception during data upload: ${e.message}")
fireBaseUpload.postValue("Error")
}
} else {
hemoCubeBufferDao.insertAll(bufferCheckData)
fireBaseUpload.postValue("Local")
}
}
fun bulkAddResultKitTestToDb(bufferCheckData: BufferCheckData) {
viewModelScope.launch {
@@ -287,7 +286,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()
@@ -396,8 +395,7 @@ class TrueHemeViewModel @Inject constructor(
viewModelScope.launch {
try {
when (val response =
repository.addTestToDatabaseforBufferCheck(bufferCheckData)) {
when (val response = repository.addTestToDatabaseforBufferCheck(bufferCheckData)) {
is Response.Success -> {
Log.i("Testdb", "Data uploaded to Firestore successfully")
fireBaseUpload.postValue("Success")
@@ -415,10 +413,9 @@ class TrueHemeViewModel @Inject constructor(
}
}
private fun updateBufferLocalFlag(bufferId: String) =
viewModelScope.launch {
hemoCubeBufferDao.updateFieldById(id = bufferId, true)
}
private fun updateBufferLocalFlag(bufferId: String) = viewModelScope.launch {
hemoCubeBufferDao.updateFieldById(id = bufferId, true)
}
fun getLocalUserDataForCsv(context: Context): Boolean {
val localUserDataLiveData: LiveData<List<HemoCubeTestData>> = hemoCubeDao.getAll()
@@ -434,7 +431,7 @@ class TrueHemeViewModel @Inject constructor(
userData._id,
userData.name,
userData.bloodGroup,
userData.birthYear,
userData.age,
userData.classificationResult,
userData.testTime.toString(),
userData.userImageURL
@@ -455,16 +452,12 @@ class TrueHemeViewModel @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
)
val level: Int = intent.getIntExtra(
BatteryManager.EXTRA_LEVEL, -1
)
val scale: Int = intent.getIntExtra(
BatteryManager.EXTRA_SCALE, -1
)
level * 100 / scale.toFloat()
}
@@ -474,8 +467,7 @@ class TrueHemeViewModel @Inject constructor(
fun getBatteryTemperature(): Float? {
val batteryTemp: Float? = batteryStatus?.let { intent ->
val temperature = intent.getIntExtra(
BatteryManager.EXTRA_TEMPERATURE,
0
BatteryManager.EXTRA_TEMPERATURE, 0
)
temperature.toFloat() / 10
}
@@ -484,14 +476,11 @@ class TrueHemeViewModel @Inject constructor(
}
fun getBatteryVoltage(context: Context): Float {
val batteryIntent =
context.registerReceiver(
null,
IntentFilter(Intent.ACTION_BATTERY_CHANGED)
)
val batteryIntent = context.registerReceiver(
null, IntentFilter(Intent.ACTION_BATTERY_CHANGED)
)
val voltage = batteryIntent?.getIntExtra(
BatteryManager.EXTRA_VOLTAGE,
0
BatteryManager.EXTRA_VOLTAGE, 0
) ?: 0
// milli-volts to volts
@@ -500,8 +489,7 @@ class TrueHemeViewModel @Inject constructor(
fun getBatteryCapacity(context: Context): Int {
val batteryManager =
context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
val batteryManager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
val currentCapacity =
batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER)
@@ -510,8 +498,7 @@ class TrueHemeViewModel @Inject constructor(
fun getBatteryMaxCapacity(context: Context): Float {
val batteryManager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
val designCapacity =
batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
val designCapacity = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
val currentCapacity =
batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER)
@@ -528,8 +515,7 @@ class TrueHemeViewModel @Inject constructor(
hemoCubeTestData.forEach { data ->
data.localFlag = true
hemoCubeDao.updateCSVFieldById(
data._id,
true
data._id, true
)
}
}

View File

@@ -11,7 +11,7 @@
* // from ShanMukha Innovations Pvt. Ltd.
*/
package com.example.hpostesting.presentation.hemocube
package com.example.hpostesting.presentation.trueheme_test
import android.content.Context
import android.os.Bundle

View File

@@ -11,7 +11,7 @@
* // from ShanMukha Innovations Pvt. Ltd.
*/
package com.example.hpostesting.presentation.hemocube
package com.example.hpostesting.presentation.trueheme_test
import android.annotation.SuppressLint
import android.content.Context
@@ -33,7 +33,7 @@ import java.util.Locale
class DigitalCardFragment : Fragment() {
private lateinit var binding: FragmentDigitalCardBinding
private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels()
private val trueHemeTestViewModel: TrueHemeTestViewModel by activityViewModels()
private lateinit var sharedPreferences: SharedPreferences
private val testDetails = DataHolder.selectedTest?.toHemoCubeTestData()
@@ -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

@@ -11,7 +11,7 @@
* // from ShanMukha Innovations Pvt. Ltd.
*/
package com.example.hpostesting.presentation.hemocube
package com.example.hpostesting.presentation.trueheme_test
import android.annotation.SuppressLint
import android.app.PendingIntent
@@ -21,6 +21,7 @@ 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
@@ -35,8 +36,8 @@ import androidx.annotation.RequiresApi
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.LanguageManager
import com.example.hpostesting.util.UsbService
import com.hoho.android.usbserial.driver.UsbSerialDriver
@@ -46,11 +47,11 @@ import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityHemocubeBinding
@AndroidEntryPoint
open class HemocubeActivity : AppCompatActivity() {
open class TrueHemeTestActivity : AppCompatActivity() {
private lateinit var binding: ActivityHemocubeBinding
private val viewModel by viewModels<HemoCubeViewModel>()
private val viewModel by viewModels<TrueHemeTestViewModel>()
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 +71,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)
}
@@ -115,10 +117,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 +134,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)
@@ -186,19 +192,30 @@ open class HemocubeActivity : AppCompatActivity() {
private fun moveToNext() {
if (supportFragmentManager.isDestroyed) return
supportFragmentManager.beginTransaction().replace(binding.fghemocube.id, HemoCubeFragment())
supportFragmentManager.beginTransaction().replace(binding.fghemocube.id, TrueHemeTestFragment())
.commit()
}
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 TrueHemeTestFragment) {
if (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

@@ -11,7 +11,7 @@
* // from ShanMukha Innovations Pvt. Ltd.
*/
package com.example.hpostesting.presentation.hemocube
package com.example.hpostesting.presentation.trueheme_test
import android.content.Context
import android.content.Intent
@@ -27,7 +27,6 @@ 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.dao.HemoCubeBufferDao
@@ -50,9 +49,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.NetworkMonitor
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import okhttp3.Headers
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.RequestBody.Companion.asRequestBody
@@ -65,14 +66,16 @@ import javax.inject.Inject
@Suppress("MemberVisibilityCanBePrivate")
@HiltViewModel
class HemoCubeViewModel @Inject constructor(
private val hemoCubeDao: HemoCubeDao,
class TrueHemeTestViewModel @Inject constructor(
val hemoCubeDao: HemoCubeDao,
private val hemoCubeBufferDao: HemoCubeBufferDao,
private val repository: Repository,
private val logFileManager: LogFileManager,
private val localFileDataSource: LocalFileDataSource,
networkMonitor: NetworkMonitor,
context: Context,
) : ViewModel() {
private var testUpload: Boolean = false
var isServiceConnected = false
val progressBar = MutableLiveData(false)
private val testDetails = DataHolder.selectedTest?.toHemoCubeTestData()
@@ -85,6 +88,9 @@ class HemoCubeViewModel @Inject constructor(
// init {
// startPeriodicCheckUpdate()
// }
init {
networkMonitor.startMonitoring()
}
val loginResponse = MutableLiveData<Result<LoginResponse>>()
@@ -92,7 +98,8 @@ class HemoCubeViewModel @Inject constructor(
val checkUpdate = MutableLiveData<Result<CheckUpdateResponse>>()
val deviceUpdate = MutableLiveData<Result<ResponseBody>>()
val deviceUpdate = MutableLiveData<ResponseBody>()
val deviceUpdateheader = MutableLiveData<Headers>()
val downloadcertificate = MutableLiveData<Result<ResponseBody>>()
val uploadLogs = MutableLiveData<Result<UploadLogsResponse>?>()
@@ -100,7 +107,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 =networkMonitor.isConnected
val allUserData = hemoCubeDao.getAll()
val allLocalData = hemoCubeDao.getAll()
val allPendingUserToUpload = hemoCubeDao.getPendingUser()
@@ -120,7 +127,7 @@ class HemoCubeViewModel @Inject constructor(
}
fun uploadHemoCubeResultToDatabase(
isOnline: Boolean, testStatus: Boolean, kitSerial: String?,
isOnline: Boolean, testStatus: Boolean, kitSerial: String?,quickCapture:Boolean
) = viewModelScope.launch {
if (kitSerial != null) {
testDetails?.kitSerial = kitSerial
@@ -130,19 +137,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()
).format(Calendar.getInstance().time)
hemoCubeDao.insertAll(testDetails!!)
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(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
val currentTimeFormatted = SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ssZZZZZ",
Locale.getDefault()
).format(Calendar.getInstance().time)
// Sanitize testDetails before using it in the API call
val sanitizedTestDetails = sanitizeDoubleValues(testDetails)
// Now, use sanitizedTestDetails for the API call
uploadResult(
MolbioV2ResultRequest(
mutableListOf(
MolbioV2Result(
rawData = sanitizedTestDetails,
analysisId = sanitizedTestDetails._id,
analysisDate = currentTimeFormatted,
analysisStatus = sanitizedTestDetails.classificationResult,
thresholds = Constants.BUFFER_INTENSITY_THRESHOLDS[sanitizedTestDetails.deviceId]?.toString(),
interpretation = sanitizedTestDetails.classificationResult,
testId = sanitizedTestDetails._id,
testTime = currentTimeFormatted,
collectionTime = currentTimeFormatted,
expiryTime = currentTimeFormatted,
)
)
)
)
viewModelScope.launch {
hemoCubeDao.updateTest(testDetails)
}
}
}
fun login(loginRequest: LoginRequest) = viewModelScope.launch {
loginResponse.postValue(Result.Loading())
@@ -218,16 +290,20 @@ 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")
}
}
@@ -245,7 +321,12 @@ class HemoCubeViewModel @Inject constructor(
}
}
}
if(testUpload){
fireBaseBulkUpload.postValue("Success")
}
// else{
// fireBaseBulkUpload.postValue("Error")
// }
}
@@ -258,9 +339,10 @@ class HemoCubeViewModel @Inject constructor(
}
fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest) = viewModelScope.launch {
deviceUpdate.postValue(Result.Loading())
//deviceUpdate.postValue(Result.Loading())
repository.deviceUpdate(deviceUpdateRequest).let {
deviceUpdate.postValue(it)
deviceUpdate.postValue(it.body())
deviceUpdateheader.postValue(it.headers())
}
}
@@ -395,7 +477,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()
@@ -413,61 +495,96 @@ class HemoCubeViewModel @Inject constructor(
testDetails?.concentration = DataHolder.hemoCubeTestData?.concentration
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()
}
private fun addResultTestToDb() {
private fun addResultTestToDb(quickCapture: Boolean) {
viewModelScope.launch {
try {
testDetails!!.reportUploadTime = SimpleDateFormat(
testDetails!!.quickCapture = quickCapture
testDetails.testStatus = true
testDetails.reportUploadTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
when (val response = repository.addTestToDatabase(testDetails)) {
is Response.Success -> {
val kitCount = sharedPreference.getInt(Constants.KIT_COUNT, 0)
with(sharedPreference.edit()) {
putInt(Constants.KIT_COUNT, kitCount.plus(1))
apply()
val currentTimeFormatted = SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ssZZZZZ",
Locale.getDefault()
).format(Calendar.getInstance().time)
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", "Data uploaded to Firestore successfully")
fireBaseUpload.postValue("Success")
testDetails.localFlag = true
hemoCubeDao.updateTest(testDetails)
}
Log.i("Testdb", "Data uploaded to Firestore successfully")
fireBaseUpload.postValue("Success")
testDetails.localFlag = true
if (Constants.MOLBIO_INTEGRATION) {
// 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 = sanitizedTestDetails.testTime,
analysisStatus = sanitizedTestDetails.classificationResult,
thresholds = Constants.BUFFER_INTENSITY_THRESHOLDS[sanitizedTestDetails.deviceId]?.toString(),
interpretation = sanitizedTestDetails.classificationResult,
testId = sanitizedTestDetails._id,
testTime = sanitizedTestDetails.testTime,
collectionTime = sanitizedTestDetails.testTime,
expiryTime = sanitizedTestDetails.testTime,
is Response.Error -> {
Log.e("Testdb", "Error uploading data to Firestore: $response")
fireBaseUpload.postValue("Error")
hemoCubeDao.updateTest(testDetails)
}
else -> {}
}
}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", "Data uploaded to Firestore successfully")
fireBaseUpload.postValue("Success")
if (Constants.MOLBIO_INTEGRATION) {
// 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,
)
)
)
)
)
}
hemoCubeDao.updateTest(testDetails)
}
hemoCubeDao.insertAll(testDetails)
}
is Response.Error -> {
Log.e("Testdb", "Error uploading data to Firestore: $response")
fireBaseUpload.postValue("Error")
hemoCubeDao.insertAll(testDetails)
}
is Response.Error -> {
Log.e("Testdb", "Error uploading data to Firestore: $response")
fireBaseUpload.postValue("Error")
hemoCubeDao.updateTest(testDetails)
}
else -> {}
else -> {}
}
}
} catch (e: Exception) {
Log.e("Testdb", "Exception during data upload: ${e.message}")
fireBaseUpload.postValue("Error")
@@ -482,12 +599,13 @@ 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
}
}
}
@@ -552,6 +670,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()
@@ -567,7 +689,7 @@ class HemoCubeViewModel @Inject constructor(
userData._id,
userData.name,
userData.bloodGroup,
userData.birthYear,
userData.age,
userData.classificationResult,
userData.testTime.toString(),
userData.userImageURL
@@ -673,4 +795,11 @@ class HemoCubeViewModel @Inject constructor(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
}
fun updateLocalData() {
viewModelScope.launch {
parseData()
hemoCubeDao.updateTest(testDetails!!)
}
}
}

View File

@@ -0,0 +1,198 @@
/*
* // 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.usb_teminal
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.content.SharedPreferences
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.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
import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityUsbTerminalBinding
@Suppress("MemberVisibilityCanBePrivate")
@AndroidEntryPoint
class UsbTerminalActivity : AppCompatActivity() {
private lateinit var binding: ActivityUsbTerminalBinding
private val usbTerminalViewModel by viewModels<UsbTerminalViewModel>()
private var myMenu: Menu? = null
private lateinit var sharedPreferences: SharedPreferences
private lateinit var mDriver: UsbSerialDriver
private var mConnection: UsbDeviceConnection? = null
lateinit var mService: UsbService
private var deviceId = ""
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 {
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()
usbTerminalViewModel.isServiceConnected = true
mConnection.let { mService.connect(mDriver, mConnection!!) }
moveToNext()
}
override fun onServiceDisconnected(arg0: ComponentName) {
usbTerminalViewModel.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)
binding = ActivityUsbTerminalBinding.inflate(layoutInflater)
setContentView(binding.root)
// setSupportActionBar(binding.myToolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
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)
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.fgDevice.id, UsbTerminalFragment())
.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 (usbTerminalViewModel.isServiceConnected) {
mService.disconnect()
unbindService(connection)
usbTerminalViewModel.isServiceConnected = false
}
}
}

View File

@@ -0,0 +1,105 @@
/*
* // 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.usb_teminal
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 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 = ""
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
): View {
binding = FragmentUsbTerminalBinding.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()
}
private fun initViews() {
binding.messageCommand.movementMethod = ScrollingMovementMethod()
usbTerminalViewModel.messages.observe(viewLifecycleOwner) {
binding.messageCommand.text = it
}
binding.sendCommand.setOnClickListener {
callCommand(binding.etCommands.text.trim().toString())
}
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?) {
}
override fun onUsbError(e: Exception?) {
usbTerminalViewModel.progressBar.postValue(false)
}
})
}
private fun listenToHemoCube() {
val fullReadOutput = StringBuilder()
startListening.postValue(true)
try {
(activity as UsbTerminalActivity).mService.listenToHemoCube(object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
data?.let {
val stringData = String(it)
fullReadOutput.append(stringData)
resultData += stringData
usbTerminalViewModel.messages.postValue(resultData)
}
}
override fun onUsbError(e: Exception?) {
usbTerminalViewModel.messages.postValue(e!!.localizedMessage)
usbTerminalViewModel.progressBar.postValue(false)
}
})
} catch (e: Exception) {
usbTerminalViewModel.messages.postValue(e.localizedMessage)
Firebase.crashlytics.recordException(e)
}
}
}

View File

@@ -11,16 +11,24 @@
* // from ShanMukha Innovations Pvt. Ltd.
*/
package com.example.hpostesting.presentation.dashboard.ui.gallery
package com.example.hpostesting.presentation.usb_teminal
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.example.hpostesting.data.dao.HemoCubeDao
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.repository.Repository
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
class mGalleryViewModel : ViewModel() {
private val _text = MutableLiveData<String>().apply {
value = "This is gallery Fragment"
}
val text: LiveData<String> = _text
@HiltViewModel
class UsbTerminalViewModel @Inject constructor(
private val hemoCubeDao: HemoCubeDao,
private val repository: Repository,
) : ViewModel() {
var isServiceConnected = false
val progressBar = MutableLiveData(false)
val messages = MutableLiveData<String>()
val deviceData = MutableLiveData<DeviceData?>()
val fireBaseUpload = MutableLiveData<String>()
}

View File

@@ -18,7 +18,7 @@ import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.example.hpostesting.presentation.main_base.DashboardActivity
import io.nats.client.AuthHandler
import io.nats.client.Connection
import io.nats.client.Message
@@ -139,7 +139,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,117 @@
package com.example.hpostesting.util
import android.annotation.SuppressLint
import android.content.Context
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import java.net.HttpURLConnection
import java.net.URL
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class NetworkMonitor @Inject constructor(
@ApplicationContext private val context: Context
) {
private var isMonitoringStarted = false
private val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
private val _isConnected = MutableLiveData(false)
val isConnected: LiveData<Boolean> get() = _isConnected
private val networkScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
performPingCheck()
}
override fun onLost(network: Network) {
_isConnected.postValue(false)
}
override fun onCapabilitiesChanged(
network: Network, networkCapabilities: NetworkCapabilities
) {
// Recheck connectivity when capabilities change (e.g., network becomes validated)
performPingCheck()
}
}
@SuppressLint("NewApi")
fun startMonitoring() {
if (isMonitoringStarted) return // Already started, do nothing.
isMonitoringStarted = true
// Check initial connectivity status
val network = connectivityManager.activeNetwork
val capabilities = connectivityManager.getNetworkCapabilities(network)
val isInitiallyConnected = capabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) == true
if (isInitiallyConnected) {
performPingCheck()
} else {
_isConnected.postValue(false)
}
val networkRequest =
NetworkRequest.Builder().addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build()
connectivityManager.registerNetworkCallback(networkRequest, networkCallback)
// Start periodic checks:
startPeriodicPingCheck()
}
fun stopMonitoring() { // never needed to call
try {
connectivityManager.unregisterNetworkCallback(networkCallback)
} catch (_: IllegalArgumentException) {
// Ignore if callback was not registered
}
networkScope.cancel()
}
private fun performPingCheck() {
networkScope.launch {
try {
val url = URL("https://www.google.com")
val connection = url.openConnection() as HttpURLConnection
connection.connectTimeout = 2000
connection.readTimeout = 2000
connection.setRequestProperty("Connection", "close")
connection.connect()
// Consider any 2xx response as successful
val isReachable = connection.responseCode in 200..299
_isConnected.postValue(isReachable)
connection.disconnect()
} catch (e: Exception) {
_isConnected.postValue(false)
}
}
}
private fun startPeriodicPingCheck(intervalMillis: Long = 1 * 60_000L) {
networkScope.launch {
while (isActive) {
performPingCheck()
delay(intervalMillis)
}
}
}
}

View File

@@ -1,75 +0,0 @@
/*
* // 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.util
import android.content.Context
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.lifecycle.LiveData
class NetworkStatusLiveData(context: Context) : LiveData<Boolean>() {
private val connectivityManager: ConnectivityManager =
context.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
postValue(true)
}
override fun onLost(network: Network) {
postValue(false)
}
}
@RequiresApi(Build.VERSION_CODES.M)
override fun onActive() {
super.onActive()
postValue(isNetworkAvailable())
registerNetworkCallback()
}
override fun onInactive() {
super.onInactive()
unregisterNetworkCallback()
}
private fun registerNetworkCallback() {
val networkRequest = NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
.build()
connectivityManager.registerNetworkCallback(networkRequest, networkCallback)
}
private fun unregisterNetworkCallback() {
connectivityManager.unregisterNetworkCallback(networkCallback)
}
@RequiresApi(Build.VERSION_CODES.M)
private fun isNetworkAvailable(): Boolean {
val network = connectivityManager.activeNetwork
val networkCapabilities = connectivityManager.getNetworkCapabilities(network)
return networkCapabilities != null &&
networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
}
}

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)
}
}

View File

@@ -122,4 +122,12 @@ class UsbService : Service() {
listener.onUsbError(e)
}
}
fun sendAndListenToHemoCubeTxt(command: String, listener: UsbServiceListener) {
try {
this.bus = listener
mPort.write(command.toByteArray(), Constants.WRITE_TIMEOUT_MILLIS)
} catch (e: IOException) {
listener.onUsbError(e)
}
}
}

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="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM17,13h-4v4h-2v-4L7,13v-2h4L11,7h2v4h4v2z"/>
</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.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: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="M11.5,2C6.81,2 3,5.81 3,10.5S6.81,19 11.5,19h0.5v3c4.86,-2.34 8,-7 8,-11.5C20,5.81 16.19,2 11.5,2zM12.5,16.5h-2v-2h2v2zM12.5,13h-2c0,-3.25 3,-3 3,-5 0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2h-2c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,2.5 -3,2.75 -3,5z"/>
</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="M7,5h10v2h2L19,3c0,-1.1 -0.9,-1.99 -2,-1.99L7,1c-1.1,0 -2,0.9 -2,2v4h2L7,5zM15.41,16.59L20,12l-4.59,-4.59L14,8.83 17.17,12 14,15.17l1.41,1.42zM10,15.17L6.83,12 10,8.83 8.59,7.41 4,12l4.59,4.59L10,15.17zM17,19L7,19v-2L5,17v4c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2v-4h-2v2z"/>
</vector>

View File

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

View File

@@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M2.88,7.88l1.54,1.54C4.15,10.23 4,11.1 4,12c0,4.41 3.59,8 8,8s8,-3.59 8,-8s-3.59,-8 -8,-8c-0.9,0 -1.77,0.15 -2.58,0.42L7.89,2.89C9.15,2.32 10.54,2 12,2c5.52,0 10,4.48 10,10s-4.48,10 -10,10S2,17.52 2,12C2,10.53 2.32,9.14 2.88,7.88zM7,5.5C7,6.33 6.33,7 5.5,7S4,6.33 4,5.5S4.67,4 5.5,4S7,4.67 7,5.5zM12.03,8.99h-0.07l-1.16,3.31h2.39L12.03,8.99zM12,18c3.31,0 6,-2.69 6,-6s-2.69,-6 -6,-6s-6,2.69 -6,6S8.69,18 12,18zM11.29,7.5h1.43l3.01,8h-1.39l-0.72,-2.04h-3.23L9.66,15.5H8.28L11.29,7.5z"/>
</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="M13,3c-4.97,0 -9,4.03 -9,9L1,12l3.89,3.89 0.07,0.14L9,12L6,12c0,-3.87 3.13,-7 7,-7s7,3.13 7,7 -3.13,7 -7,7c-1.93,0 -3.68,-0.79 -4.94,-2.06l-1.42,1.42C8.27,19.99 10.51,21 13,21c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9zM12,8v5l4.28,2.54 0.72,-1.21 -3.5,-2.08L13.5,8L12,8z"/>
</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"

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