Compare commits

...

127 Commits

Author SHA1 Message Date
smileomi18@gmail.com
5966af95eb added separate buttons for place buffer and sample in new branch, and also buffer made compulsory for every test 2023-09-21 11:02:36 +05:30
Pritimay Sarkar
095f9fb027 sorting user list in decending order
- create index
2023-09-18 14:40:58 +05:30
Pritimay Sarkar
1fb938bd0d release 2.1.10 2023-09-18 11:11:05 +05:30
Pritimay Sarkar
865922e90e disable app distribution for stoping its alert 2023-09-18 11:08:06 +05:30
Pritimay Sarkar
e71496e423 remove start buffer and sample button from prod build
- add firebase exception log
2023-09-18 10:57:02 +05:30
Pritimay Sarkar
472b50562b ignore keys 2023-09-18 02:33:27 +05:30
Pritimay Sarkar
81e8567b49 remove BuildConfig 2023-09-18 02:26:22 +05:30
Pritimay Sarkar
3f8b931684 Merge branch 'classification' into Homocube 2023-09-18 02:19:47 +05:30
Pritimay Sarkar
270cee7a9c show classification in screen message before db save 2023-09-18 02:01:23 +05:30
Pritimay Sarkar
515ab24ce6 add result classification
- add result classification
	- add sample start command for positive confirmation
	- remove toast on result screen
2023-09-17 23:46:30 +05:30
Pritimay Sarkar
e455cacf69 Merge branch 'CrashIssues' into 'Homocube'
production errors

See merge request sminnovations/hpos!4
2023-09-16 05:43:27 +00:00
Mariya Varghese
45613b2709 production errors 2023-09-16 05:43:27 +00:00
smileomi18@gmail.com
34bed4e5fe app version -updation- notifying user 2023-09-15 17:26:38 +05:30
smileomi18@gmail.com
f019e1897d Added placebuffer and sample buttons for the new feature 2023-09-15 17:03:03 +05:30
Pritimay Sarkar
1d542f5562 Merge branch 'kitscan_fix' into Homocube 2023-09-11 09:22:06 +05:30
Pritimay Sarkar
4289d1c399 release version 2.1.3 2023-09-11 09:20:55 +05:30
Pritimay Sarkar
38f2122444 add version name in the settings 2023-09-10 23:59:54 +05:30
Pritimay Sarkar
d6bacd578c show users in ordered, latest first 2023-09-10 23:58:02 +05:30
Pritimay Sarkar
f8a7bff5b2 add new kit button
- device data processing error toast
2023-09-10 23:55:24 +05:30
smileomi18@gmail.com
882fdb7374 APP VERSION added 2023-09-05 17:20:21 +05:30
smileomi18@gmail.com
b6e086c407 APP VERSION added 2023-09-05 15:37:53 +05:30
mohamedkaif356
53c2fd5ad4 Blood group 2023-09-05 13:44:18 +05:30
smileomi18@gmail.com
4b733b3a96 FirebaseCrashAnalytics added 2023-08-23 12:07:25 +05:30
mohamedkaif356
dc4291eaa8 Offline storage 2023-08-18 12:21:21 +05:30
Mariya Varghese
5d2830d515 Merge branch 'blood-group' into 'Homocube'
Blood group

See merge request sminnovations/hpos!1
2023-08-16 10:22:40 +00:00
smileomi18@gmail.com
dfa9fe7672 deviceData function called 2023-08-14 21:12:14 +05:30
smileomi18@gmail.com
d51d46a9a1 Blood-Group is added 2023-08-09 14:54:59 +05:30
smileomi18@gmail.com
64209fd2f2 Blood-Group is added 2023-08-09 14:51:44 +05:30
Pritimay Sarkar
d4752a9491 Merge branch 'qc-testing' into Homocube 2023-08-09 11:46:38 +05:30
Pritimay Sarkar
484790e721 Added device login 2023-08-09 11:43:29 +05:30
Pritimay Sarkar
954795030c Added device login 2023-08-09 11:40:31 +05:30
mohamedkaif356
53695d9240 Made some corrections 2023-08-09 11:13:48 +05:30
mohamedkaif356
bac0baf53c Made some corrections 2023-08-09 11:07:58 +05:30
mohamedkaif356
f3c292b268 Done with error handling 2023-08-08 15:30:46 +05:30
mohamedkaif356
2bb87c7780 Optimized HemoCube data parsing and changed user card 2023-08-07 17:43:24 +05:30
mohamedkaif356
85d9c6306d Fixed Navigation, Location, and updated user card and gitignore file 2023-08-07 15:02:16 +05:30
Pritimay Sarkar
e5390df0f4 add resultData 2023-08-07 12:43:39 +05:30
Pritimay Sarkar
afdaac7f1d Merge branch 'Homocube' of https://gitlab.com/sminnovations/hpos into Homocube 2023-08-05 15:28:35 +05:30
Pritimay Sarkar
60cd1aef1a add popup for sample reading 2023-08-05 15:28:11 +05:30
smileomi18@gmail.com
22f080ff9f dialogue box is done 2023-08-05 14:07:22 +05:30
Pritimay Sarkar
013dc569a1 take message as frames 2023-08-05 12:50:50 +05:30
Pritimay Sarkar
7ca2d78325 Merge branch 'Homocube' of https://gitlab.com/sminnovations/hpos into Homocube 2023-08-04 22:41:49 +05:30
Pritimay Sarkar
a43e29a03e disable button 2023-08-04 22:41:34 +05:30
mohamedkaif356
c1c6c7cce4 Buffer error resolved 2023-08-04 19:54:10 +05:30
Pritimay Sarkar
e049e6ede3 Merge 2023-08-04 15:51:04 +05:30
Pritimay Sarkar
4d366cbf02 set buffer and new kit logic 2023-08-04 15:49:26 +05:30
smileomi18@gmail.com
a491343a43 navigation is done 2023-08-04 13:41:51 +05:30
Pritimay Sarkar
1b893c5730 Merge 2023-08-03 23:04:59 +05:30
Pritimay Sarkar
547b5d8663 add device data parsing and saving calcualtion data 2023-08-03 23:01:49 +05:30
Pritimay Sarkar
4c7c24449b show text and disable button 2023-08-03 17:42:06 +05:30
smileomi18@gmail.com
3daba2fbb1 Added Kit and Buffer Button 2023-08-03 17:39:29 +05:30
Pritimay Sarkar
23ef8bc74f save calculateRatio 2023-08-03 17:33:53 +05:30
mohamedkaif356
9f79d32cbf Flushed Kit number, Kit count and Buffer value for new kit 2023-08-03 17:06:36 +05:30
mohamedkaif356
1a87344f44 Flushed Kit number, Kit count and Buffer value for new kit 2023-08-03 17:03:04 +05:30
Pritimay Sarkar
7c1100fc39 Merge branch 'Homocube' of https://gitlab.com/sminnovations/hpos into Homocube 2023-08-03 16:46:01 +05:30
Pritimay Sarkar
82b3944d94 add alert on check buffer 2023-08-03 16:45:27 +05:30
smileomi18@gmail.com
340b656990 Added 2 Buffer values 2023-08-03 16:44:04 +05:30
smileomi18@gmail.com
567fe237da calibration calculation done 2023-08-03 16:15:57 +05:30
Pritimay Sarkar
281d206492 Merge branch 'tmp' into Homocube 2023-08-03 15:45:39 +05:30
smileomi18@gmail.com
750fb67ff9 calibration calculation done 2023-08-03 15:41:57 +05:30
Pritimay Sarkar
d0c309801d add commands to set and read buffer sample
- add commands
2023-08-03 15:34:49 +05:30
smileomi18@gmail.com
36799ea81e Merge remote-tracking branch 'origin/Homocube' into Homocube 2023-08-03 13:43:31 +05:30
smileomi18@gmail.com
e0937d9f03 Fetching caliberation value done 2023-08-03 13:41:51 +05:30
smileomi18@gmail.com
47633267f7 Fetching caliberation value done 2023-08-03 13:40:35 +05:30
mohamedkaif356
0dd77027e9 Flushed Kit number, Kit count and Buffer value for new kit 2023-08-03 13:12:28 +05:30
mohamedkaif356
8237e753c0 Added Buffer Value Logic 2023-08-03 13:01:03 +05:30
mohamedkaif356
4c847fb132 Added KitNumber and KitCount 2023-08-03 12:46:45 +05:30
Pritimay Sarkar
4488e5e16e merge 2023-08-02 23:28:35 +05:30
Pritimay Sarkar
c8199b9044 merge 2023-08-02 23:23:47 +05:30
Pritimay Sarkar
3292a0e382 merge 2023-08-02 23:14:57 +05:30
smileomi18@gmail.com
1ba919c956 Fetching caliberation value done 2023-08-02 20:03:26 +05:30
smileomi18@gmail.com
6e2729a075 Fetching caliberation value done 2023-08-02 20:02:45 +05:30
smileomi18@gmail.com
0b44ce47b9 Added Device Data and HemoCube Schema 2023-08-02 19:32:58 +05:30
smileomi18@gmail.com
8506d3da6d Added Device Data and HemoCube Schema 2023-08-02 19:07:08 +05:30
smileomi18@gmail.com
ece2cec4c0 hemocube alert Dialogue 2023-08-02 16:33:46 +05:30
Pritimay Sarkar
f6613b3b69 fix hemocube db save error
- add mapper to hemocube data
	- save test details correctly on dataholder
	- add result data from device on test details
2023-08-02 11:32:23 +05:30
smileomi18@gmail.com
9382708140 hemocube test uploading data 2023-08-01 18:45:49 +05:30
smileomi18@gmail.com
f8f8f140a9 Removed 2023-07-31 17:05:36 +05:30
smileomi18@gmail.com
e0a4008966 HemoCube new Changes 2023-07-27 17:26:44 +05:30
smileomi18@gmail.com
90b92897bd HemoCube new Changes 2023-07-27 17:16:28 +05:30
smileomi18@gmail.com
106aa496fc HemoCube new Changes 2023-07-27 17:12:14 +05:30
smileomi18@gmail.com
97b66acda3 HemoCube new Changes 2023-07-27 16:44:12 +05:30
smileomi18@gmail.com
a5db2e759c HemoCube new Changes 2023-07-26 18:11:46 +05:30
mohamedkaif356
ebf212d33a Improved logic 2023-07-25 13:42:29 +05:30
mohamedkaif356
e2e9c28efb Improved Code 2023-07-25 12:22:57 +05:30
smileomi18@gmail.com
46ee7b55be HemoCube new Changes 2023-07-25 12:12:34 +05:30
smileomi18@gmail.com
c0d706f2a3 Merge remote-tracking branch 'origin/Homocube' into Homocube 2023-07-25 12:03:06 +05:30
prisar
4b8a380541 read data from dev 2023-07-25 11:47:29 +05:30
prisar
3cd6bd1bc8 read data from device homocube 2023-07-25 11:47:27 +05:30
prisar
dbdcd647af usb permission 2023-07-25 11:47:15 +05:30
smileomi18@gmail.com
a28e4634e0 usb 2023-07-25 11:47:14 +05:30
mohamedkaif356
ed567f6545 Displaying message when user list is empty and update blood group 2023-07-25 11:46:24 +05:30
smileomi18@gmail.com
af5c3c3bde Test pending list filter 2023-07-25 11:46:24 +05:30
mohamedkaif356
21e9b9b7b2 Blood group selection 2023-07-25 11:46:23 +05:30
smileomi18@gmail.com
9067240c4f HemoCube new Changes 2023-07-25 11:40:10 +05:30
smileomi18@gmail.com
0d2027381c HemoCube new Changes 2023-07-24 15:45:33 +05:30
smileomi18@gmail.com
ca403ab862 HemoCube new Changes 2023-07-24 14:49:51 +05:30
smileomi18@gmail.com
3b042c6587 HemoCube new Changes 2023-07-24 14:33:06 +05:30
prisar
ff5cc154e6 refactor code 2023-07-21 11:12:50 +05:30
smileomi18@gmail.com
51b49a010c read data from device homocube 2023-07-20 16:08:59 +05:30
smileomi18@gmail.com
a8e7d7d60b Merge remote-tracking branch 'origin/Homocube' into Homocube
# Conflicts:
#	app/src/main/java/com/example/hpostesting/presentation/testRight/UsbService.kt
2023-07-20 15:44:43 +05:30
prisar
a34d101fbf read data from device homocube 2023-07-20 15:44:01 +05:30
prisar
fd8fbb863f read data from dev 2023-07-19 18:18:39 +05:30
prisar
b64c3fb471 usb permission 2023-07-19 17:27:57 +05:30
smileomi18@gmail.com
8151d6da61 usb 2023-07-19 16:28:31 +05:30
smileomi18@gmail.com
ab9392cd59 Login Feature -completed 2023-07-11 16:59:59 +05:30
smileomi18@gmail.com
9a1fc15902 Login Feature - 1 2023-07-07 17:01:02 +05:30
mohamedkaif356
e1e8e4ebb2 Login Feature 2023-07-07 16:07:58 +05:30
mohamedkaif356
0c063583ca Change the project into Testing app 2023-06-28 12:41:18 +05:30
vsuryakumar
69df710006 WORKING COMMIT 2023-06-08 19:27:34 +05:30
vsuryakumar
7d744819f8 Uploading files to storage and adding to pending queue. 2023-06-04 00:50:01 +05:30
vsuryakumar
eb89cf5842 Remove unused imports 2023-06-03 19:12:32 +05:30
vsuryakumar
a1f41db68b Integrated testing with patient registration. [Test Mode - USBSerial] 2023-06-03 19:10:48 +05:30
vsuryakumar
0e5046d521 Added new dashboard, scanning, registration UI & functionality. 2023-05-30 08:48:59 +05:30
vsuryakumar
30665be147 Added new UI to dashboard. 2023-05-26 01:22:38 +05:30
vsuryakumar
685d56acca Used data layer to save csv to disk. 2023-05-19 18:01:09 +05:30
vsuryakumar
5d1c7f6e48 Changed compile sdk to 33 to 32. 2023-05-19 18:00:22 +05:30
vsuryakumar
d914c86076 merged data models into one. 2023-05-19 13:13:17 +05:30
vsuryakumar
645c3b6a02 Added new data models 2023-05-19 13:08:40 +05:30
vsuryakumar
0ec3c65298 1. Added demo camera scanner page.
2. Added new checkboxes for patient data collection
2023-05-19 13:08:02 +05:30
vsuryakumar
b1b7a31f74 Updated ratios. 2023-02-23 14:29:46 +05:30
vsuryakumar
f7137ec7d3 removing testing lines 2023-02-20 11:20:32 +05:30
vsuryakumar
6ef1fc291f Added 2 more result category in sicklecert with recommendation message for borderline. 2023-02-16 15:06:53 +05:30
vsuryakumar
538e186d02 updated .gitignore 2023-02-16 13:12:58 +05:30
vsuryakumar
3b7f24c47c Validating the patient name, so as to work with filenaming also. i.e, showing error on using restricted characters. 2023-02-13 13:06:45 +05:30
vsuryakumar
724920fe6f Merge branch 'main' of https://github.com/surya-x/sickle-cell-updated 2023-02-13 12:29:10 +05:30
vsuryakumar
a0936391c6 Update in no. of tests in a run + Updates in ratio. (App build) 2023-02-13 12:28:44 +05:30
167 changed files with 14033 additions and 1751 deletions

7
.gitignore vendored
View File

@@ -1,12 +1,7 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
/.idea
.DS_Store
/build
/captures

2
.idea/compiler.xml generated
View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="11" />
<bytecodeTargetLevel target="17" />
</component>
</project>

1
.idea/gradle.xml generated
View File

@@ -7,6 +7,7 @@
<option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="jbr-17" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />

6
.idea/kotlinc.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="1.8.21" />
</component>
</project>

9
.idea/misc.xml generated
View File

@@ -3,6 +3,7 @@
<component name="DesignSurface">
<option name="filePathToZoomLevelMap">
<map>
<entry key="app/src/main/res/drawable/ic_baseline_auto_graph_24.xml" value="0.1555" />
<entry key="app/src/main/res/drawable/ic_baseline_cancel_24.xml" value="0.1965" />
<entry key="app/src/main/res/drawable/ic_baseline_check_circle_24.xml" value="0.243" />
<entry key="app/src/main/res/drawable/ic_baseline_dot_24.xml" value="0.1785" />
@@ -19,10 +20,12 @@
<entry key="app/src/main/res/layout/activity_main.xml" value="0.165" />
<entry key="app/src/main/res/layout/activity_splash.xml" value="0.24375" />
<entry key="app/src/main/res/layout/activity_test_right.xml" value="0.24375" />
<entry key="app/src/main/res/layout/fragment_graph.xml" value="0.19791666666666666" />
<entry key="app/src/main/res/layout/fragment_test_right_exp_reference.xml" value="0.25" />
<entry key="app/src/main/res/layout/fragment_test_right_exp_sample.xml" value="0.25" />
<entry key="app/src/main/res/layout/fragment_test_right_exp_sample.xml" value="0.24583333333333332" />
<entry key="app/src/main/res/layout/fragment_test_right_exp_scanner.xml" value="0.24583333333333332" />
<entry key="app/src/main/res/layout/fragment_test_right_process.xml" value="0.24375" />
<entry key="app/src/main/res/layout/fragment_test_right_results.xml" value="0.25" />
<entry key="app/src/main/res/layout/fragment_test_right_results.xml" value="0.30512820512820515" />
<entry key="app/src/main/res/layout/table_item.xml" value="0.22407407407407406" />
<entry key="app/src/main/res/menu/menu.xml" value="0.25" />
<entry key="app/src/main/res/menu/my_menu.xml" value="0.25" />
@@ -31,7 +34,7 @@
</map>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="Android Studio default JDK" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">

2
app/.gitignore vendored
View File

@@ -1,3 +1,3 @@
/build
/google-services.json
/google-services*
/idea

View File

@@ -2,19 +2,24 @@ plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'com.google.firebase.appdistribution'
id 'dagger.hilt.android.plugin'
id 'com.google.gms.google-services'
id 'androidx.navigation.safeargs.kotlin'
id 'kotlin-kapt'
id 'com.google.firebase.crashlytics'
}
//apply plugin: 'kotlin-android'
android {
compileSdk 32
compileSdk 34
namespace 'in.sminnovations.hpostesting'
defaultConfig {
applicationId "com.example.hpos"
applicationId "in.sminnovations.hpostesting"
minSdk 21
targetSdk 32
versionCode 1
versionName "1.0"
targetSdk 34
versionCode 10
versionName "2.1.10"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@@ -26,41 +31,90 @@ android {
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = '1.8'
jvmTarget = '17'
}
dataBinding {
enabled = true
}
buildFeatures {
viewBinding true
buildConfig = true
}
lint {
abortOnError false
checkReleaseBuilds false
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'com.google.android.material:material:1.7.0'
implementation 'androidx.core:core-ktx:1.12.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.9.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.2'
//firebase
implementation platform('com.google.firebase:firebase-bom:32.1.0')
implementation("com.google.firebase:firebase-crashlytics-ktx")
implementation("com.google.firebase:firebase-analytics-ktx")
implementation 'com.google.firebase:firebase-firestore-ktx'
implementation 'com.google.firebase:firebase-auth-ktx'
implementation 'com.google.firebase:firebase-storage-ktx'
implementation 'com.firebaseui:firebase-ui-firestore:8.0.2'
implementation 'com.google.android.gms:play-services-auth:20.7.0'
implementation 'com.google.android.gms:play-services-location:21.0.1'
implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1'
implementation 'com.google.android.things:androidthings:1.0'
implementation 'com.google.firebase:firebase-appdistribution:16.0.0-beta10'
implementation("com.google.firebase:firebase-appdistribution-api-ktx:16.0.0-beta10")
// Testing
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2"
implementation 'com.opencsv:opencsv:4.6'
implementation 'com.github.mik3y:usb-serial-for-android:3.4.6'
implementation 'com.github.mik3y:usb-serial-for-android:3.5.1'
implementation "androidx.fragment:fragment-ktx:1.5.5"
implementation "androidx.fragment:fragment-ktx:1.6.1"
// CSV read, write
implementation 'com.opencsv:opencsv:4.6'
// implementation 'androidx.appcompat:appcompat:1.1.0'
// implementation "androidx.core:core-ktx:+"
// implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
// Barcode scanner
implementation 'com.journeyapps:zxing-android-embedded:4.3.0'
}
//repositories {
// mavenCentral()
//}
// Google ML Kit usign play services
implementation 'com.google.android.gms:play-services-code-scanner:16.1.0'
//Room
implementation "androidx.room:room-ktx:2.6.0-beta01"
implementation "androidx.room:room-runtime:2.6.0-beta01"
kapt ("androidx.room:room-compiler:2.6.0-beta01")
//image
implementation 'com.github.bumptech.glide:glide:4.13.2'
annotationProcessor 'com.github.bumptech.glide:compiler:4.13.2'
// Navigation Component
implementation "androidx.navigation:navigation-fragment-ktx:2.7.2"
implementation "androidx.navigation:navigation-ui-ktx:2.7.2"
//Dagger - Hilt
implementation "com.google.dagger:hilt-android:2.46"
kapt "com.google.dagger:hilt-android-compiler:2.46"
kapt "androidx.hilt:hilt-compiler:1.0.0"
// Retrofit + GSON
implementation "com.squareup.retrofit2:retrofit:2.9.0"
implementation "com.squareup.retrofit2:converter-gson:2.9.0"
}

BIN
app/release/hpos-app.apk Normal file

Binary file not shown.

View File

@@ -0,0 +1,20 @@
{
"version": 3,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "com.example.hpos",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 1,
"versionName": "1.0",
"outputFile": "app-release.apk"
}
],
"elementType": "File"
}

View File

@@ -1,13 +1,11 @@
package com.example.hpos
package com.example.hpostesting
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Assert.*
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*

View File

@@ -1,13 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.hpos">
xmlns:tools="http://schemas.android.com/tools">
<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-feature android:name="android.hardware.camera" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-feature android:name="android.hardware.usb.host" />
<uses-permission android:name="android.permission.USB_PERMISSION" />
<application
android:name="com.example.hpostesting.HPOSTestingApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
@@ -15,43 +24,63 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/hpos_icon_round"
android:supportsRtl="true"
android:theme="@style/Theme.HPOS"
android:theme="@style/Theme.HPOSTesting"
tools:targetApi="31">
<activity
android:name="com.example.hpostesting.presentation.hemocube.HemocubeActivity"
android:exported="false"
android:noHistory="true"
android:parentActivityName="com.example.hpostesting.presentation.MainActivity"
android:theme="@style/Theme.HPOS.NoActionBar"
android:windowSoftInputMode="adjustPan" />
<activity
android:name="com.example.hpostesting.presentation.KitScanActivity"
android:exported="false"
android:noHistory="true"
android:theme="@style/Theme.HPOS.NoActionBar" />
<activity
android:name="com.example.hpostesting.presentation.dashboard.DashboardActivity"
android:exported="false"
android:label="@string/title_activity_dashboard"
android:theme="@style/Theme.HPOS.NoActionBar" />
<service
android:name="com.example.hpos.presentation.testRight.UsbService"
android:name="com.example.hpostesting.presentation.testRight.UsbService"
android:enabled="true"
android:exported="false" />
<activity
android:name="com.example.hpos.presentation.SplashActivity"
android:name="com.example.hpostesting.presentation.SplashActivity"
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>
</activity>
<activity
android:name="com.example.hpos.presentation.testRight.TestRightActivity"
android:name="com.example.hpostesting.presentation.testRight.TestRightActivity"
android:exported="false"
android:windowSoftInputMode="adjustPan"
android:parentActivityName="com.example.hpos.presentation.MainActivity">
<!-- <intent-filter>-->
<!-- <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />-->
<!-- </intent-filter>-->
android:noHistory="true"
android:parentActivityName="com.example.hpostesting.presentation.MainActivity"
android:theme="@style/Theme.HPOS.NoActionBar"
android:windowSoftInputMode="adjustPan">
<!-- <meta-data-->
<!-- android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"-->
<!-- android:resource="@xml/device_filter" />-->
</activity>
<!-- <intent-filter> -->
<!-- <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /> -->
<!-- </intent-filter> -->
<!-- android:theme="@style/Theme.HPOS.ActionBar"-->
<!-- <meta-data -->
<!-- android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" -->
<!-- android:resource="@xml/device_filter" /> -->
</activity> <!-- android:theme="@style/Theme.HPOS.ActionBar" -->
<activity
android:name="com.example.hpos.presentation.MainActivity"
android:exported="true">
android:name="com.example.hpostesting.presentation.MainActivity"
android:exported="true"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
@@ -59,9 +88,12 @@
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter" />
</activity>
<activity
android:name="com.journeyapps.barcodescanner.CaptureActivity"
android:screenOrientation="portrait"
android:stateNotNeeded="true"
tools:replace="android:screenOrientation" />
</application>
</manifest>

View File

@@ -1,11 +0,0 @@
package com.example.hpos
import android.app.Application
class MyApplication : Application() {
// private val sampleDetails = PatientDetails("Change it later");
// fun getSampleDetails() : PatientDetails = sampleDetails
// fun setSampleDetails(sample: SampleDetails) {sampleDetails = sample}
}

View File

@@ -1,27 +0,0 @@
package com.example.hpos.data
import androidx.lifecycle.MutableLiveData
import com.example.hpos.data.model.TestRightDeviceConstants
import com.example.hpos.data.model.TestType
object DataHolder {
var selectedTestType: TestType = TestType.SICKLECERT
val usbConnected = MutableLiveData(true)
var isStoragePermissionGranted = false
var isAppFolderCreated = false
var appFolderPath = ""
var isReferenceTaken = false
var sampleReadCounter = 0
var deviceConstant: TestRightDeviceConstants? = null
var deviceSerialNumber: String = "ABCD"
/* Contains wavelength -> pixel no.*/
val wavelengthToPixelArray = ArrayList<Double>()
/* (For reference/baseline) Contains pixel no. -> Intensity of light falling on that pixel */
val intensityReferenceArray = ArrayList<Double>()
}

View File

@@ -1,7 +0,0 @@
package com.example.hpos.data
import com.example.hpos.data.model.TestInfo
interface Repository {
suspend fun saveToDatabase(info: TestInfo)
}

View File

@@ -1,12 +0,0 @@
package com.example.hpos.data
import com.example.hpos.data.model.TestInfo
class RepositoryImpl : Repository {
override suspend fun saveToDatabase(info: TestInfo) {
}
}

View File

@@ -1,29 +0,0 @@
package com.example.hpos.data.constant
object Constants {
const val ACTION_USB_PERMISSION = "shanmukha.in.sickle_cell.USB_PERMISSION"
const val WRITE_TIMEOUT_MILLIS = 30000 // 30 sec
const val READ_TIMEOUT_MILLIS = 60000 // 1 min
const val DELAY_BETWEEN_COMMANDS: Long = 1000
const val TEST_RIGHT_TOTAL_PIXEL = 3694
const val MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE = 9999
const val RANGE_IN_RESULT_CALCULATIONS = 10
const val WAVELENGTH_OF_INTEREST_ONE = 427
const val WAVELENGTH_OF_INTEREST_TWO = 555
const val MIN_WAVELENGTH_RANGE_TO_RECORD = 350
const val MAX_WAVELENGTH_RANGE_TO_RECORD = 750
const val DEVICE_PRODUCT_ID = 24597
const val DEVICE_VENDOR_ID = 1027
const val ERROR_NORMAL = 400
const val ERROR_CRITICAL = 401
const val NO_OF_TIMES_TO_RUN_SAMPLE = 1
}

View File

@@ -1,94 +0,0 @@
package com.example.hpos.domain
import com.example.hpos.data.constant.Constants
import com.example.hpos.data.model.TestRightCalculationData
import com.example.hpos.data.model.TestRightResultType
class ResultCalculationWithAvgImpl : TestRightResultCalculation {
private val testRightCalculationData = TestRightCalculationData()
override fun getResults(wavelengthToAbsorbance: ArrayList<ArrayList<Double>>): TestRightCalculationData {
val startWavelengthOne =
Constants.WAVELENGTH_OF_INTEREST_ONE - Constants.RANGE_IN_RESULT_CALCULATIONS
val endWavelengthOne =
Constants.WAVELENGTH_OF_INTEREST_ONE + Constants.RANGE_IN_RESULT_CALCULATIONS + 1
var sumOfAbsorbanceAtOne = 0.0
var noOfAbsorbanceRecordedOne = 0
val startWavelengthTwo =
Constants.WAVELENGTH_OF_INTEREST_TWO - Constants.RANGE_IN_RESULT_CALCULATIONS
val endWavelengthTwo =
Constants.WAVELENGTH_OF_INTEREST_TWO + Constants.RANGE_IN_RESULT_CALCULATIONS + 1
var sumOfAbsorbanceAtTwo = 0.0
var noOfAbsorbanceRecordedTwo = 0
for (each in wavelengthToAbsorbance) {
if (each[0] >= startWavelengthOne && each[0] < endWavelengthOne) {
sumOfAbsorbanceAtOne += each[1]
noOfAbsorbanceRecordedOne++
}
if (each[0] >= startWavelengthTwo && each[0] < endWavelengthTwo) {
sumOfAbsorbanceAtTwo += each[1]
noOfAbsorbanceRecordedTwo++
}
}
val avgAbsorbanceOne = (sumOfAbsorbanceAtOne / noOfAbsorbanceRecordedOne)
val avgAbsorbanceTwo = (sumOfAbsorbanceAtTwo / noOfAbsorbanceRecordedTwo)
testRightCalculationData.absorbanceOne = avgAbsorbanceOne
testRightCalculationData.absorbanceTwo = avgAbsorbanceTwo
testRightCalculationData.result = calculateResultsAndRatio(avgAbsorbanceOne, avgAbsorbanceTwo)
return testRightCalculationData
}
private fun calculateResultsAndRatio(
absorbanceAtWaveOne: Double,
absorbanceAtWaveTwo: Double
): TestRightResultType {
if (absorbanceAtWaveOne != Double.MIN_VALUE && absorbanceAtWaveTwo != Double.MIN_VALUE && absorbanceAtWaveOne != 0.0) {
val value = absorbanceAtWaveTwo / absorbanceAtWaveOne
testRightCalculationData.ratioValue = value
if (value < 0.24 || value == 0.0) {
testRightCalculationData.ratioMinRange = 0.0
testRightCalculationData.ratioMaxRange = 0.24
return TestRightResultType.NORMAL
} else if (value >= 0.24 && value < 0.30) {
testRightCalculationData.ratioMinRange = 0.24
testRightCalculationData.ratioMaxRange = 0.30
return TestRightResultType.SICKLECELLTRAIT
} else if (value >= 0.30) {
testRightCalculationData.ratioMinRange = 0.30
testRightCalculationData.ratioMaxRange = 999.0
return TestRightResultType.SICKLECELLDISEASE
}
}
return TestRightResultType.UNDEFINED
// if (absorbanceAtWaveOne != Double.MIN_VALUE && absorbanceAtWaveTwo != Double.MIN_VALUE && absorbanceAtWaveOne != 0.0) {
// val value = absorbanceAtWaveTwo / absorbanceAtWaveOne
//
// if (value < 0.24 || value == 0.0) {
// return TestRightResultType.NORMAL
// } else if (value >= 0.24 && value < 0.30) {
// return TestRightResultType.SICKLECELLTRAIT
// } else if (value >= 0.30) {
// return TestRightResultType.SICKLECELLDISEASE
// }
//
// }
// return TestRightResultType.UNDEFINED
// Log.d(TAG, "value = $value")
// println("value = $value")
}
}

View File

@@ -1,101 +0,0 @@
package com.example.hpos.domain
import android.util.Log
import com.example.hpos.data.constant.Constants
import com.example.hpos.data.model.TestRightResultType
import kotlin.math.log10
class ResultCalculationWithFirstImpl {
private val TAG = "Testright"
fun getResults(
wavelengthToPixelArray: ArrayList<ArrayList<Double>>,
intensityReferenceArray: ArrayList<ArrayList<Double>>,
intensitySampleArray: ArrayList<ArrayList<Double>>
) : TestRightResultType {
var pixelNoWithWave_427 = 0
var pixelNoWithWave_555 = 0
Log.d(TAG, "wavelengthToPixelArray size = ${wavelengthToPixelArray.size}")
// println("wavelengthToPixelArray size = ${wavelengthToPixelArray.size}")
for (each in wavelengthToPixelArray) {
var diff = each[0] - 427
if (pixelNoWithWave_427 == 0 && diff >= 0 && diff < 1) {
pixelNoWithWave_427 = each[1].toInt()
}
diff = each[0] - 555
if (pixelNoWithWave_555 == 0 && diff >= 0 && diff < 1) {
pixelNoWithWave_555 = each[1].toInt()
}
if (pixelNoWithWave_427 != 0 && pixelNoWithWave_555 != 0) {
break
}
}
Log.d(TAG, "pixelOfInterest_427 = ${pixelNoWithWave_427}")
Log.d(TAG, "pixelOfInterest_555 = ${pixelNoWithWave_555}")
// println("pixelOfInterest_427 = ${pixelNoWithWave_427}")
// println("pixelOfInterest_555 = ${pixelNoWithWave_555}")
val invertedPixel_427 = (Constants.TEST_RIGHT_TOTAL_PIXEL + 1) - pixelNoWithWave_427
val invertedPixel_555 = (Constants.TEST_RIGHT_TOTAL_PIXEL + 1) - pixelNoWithWave_555
var io_427 = 0.0
var io_555 = 0.0
for (each in intensityReferenceArray) {
if (each[0].toInt() == invertedPixel_427) {
io_427 = each[1]
}
if (each[0].toInt() == invertedPixel_555) {
io_555 = each[1]
}
}
Log.d(TAG, "I0 values are I0_427 = $io_427 , IO_555 = $io_555")
// println("I0 values are I0_427 = $io_427 , IO_555 = $io_555")
var i_427 = 0.0
var i_555 = 0.0
for (each in intensitySampleArray) {
if (each[0].toInt() == invertedPixel_427) {
i_427 = each[1]
}
if (each[0].toInt() == invertedPixel_555) {
i_555 = each[1]
}
}
Log.d(TAG, "I values are I_427 = $i_427 , I_555 = $i_555")
// println("I values are I_427 = $i_427 , I_555 = $i_555")
val absorbanceAtPixelWithWave_427 = log10(io_427 / i_427)
val absorbanceAtPixelWithWave_555 = log10(io_555 / i_555)
Log.d(
TAG,
"absorbance values are for 427 = $absorbanceAtPixelWithWave_427 , for 555 = $absorbanceAtPixelWithWave_555"
)
// println("absorbance values are for 427 = $absorbanceAtPixelWithWave_427 , for 555 = $absorbanceAtPixelWithWave_555")
var value = 0.0
if (absorbanceAtPixelWithWave_427 != 0.0 && absorbanceAtPixelWithWave_555 != 0.0) {
value = absorbanceAtPixelWithWave_555 / absorbanceAtPixelWithWave_427
}
Log.d(TAG, "value = $value")
// println("value = $value")
if (value < 0.24 || value == 0.0) {
return TestRightResultType.NORMAL
} else if (value >= 0.24 && value < 0.30) {
return TestRightResultType.SICKLECELLTRAIT
} else if (value >= 0.30) {
return TestRightResultType.SICKLECELLDISEASE
}
return TestRightResultType.UNDEFINED
}
}

View File

@@ -1,119 +0,0 @@
package com.example.hpos.presentation
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbManager
import android.os.Bundle
import android.util.Log
import android.view.Gravity
import android.view.Menu
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.get
import androidx.lifecycle.ViewModelProvider
import com.example.hpos.R
import com.example.hpos.data.DataHolder
import com.example.hpos.data.constant.Constants
import com.example.hpos.data.model.TestType
import com.example.hpos.databinding.ActivityMainBinding
import com.example.hpos.presentation.testRight.TestRightActivity
import com.example.hpos.util.MyViewModelFactory
import com.hoho.android.usbserial.driver.UsbSerialProber
class MainActivity : AppCompatActivity()
// , SerialInputOutputManager.Listener
{
private lateinit var binding: ActivityMainBinding
private lateinit var viewModel: MainViewModel
private var myMenu: Menu? = null
private val TAG = "MainActivity"
private var mUsbReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent) {
val action = intent.action
if (UsbManager.ACTION_USB_DEVICE_DETACHED == action) {
DataHolder.usbConnected.value = false
// Toast.makeText(context, "Detached", Toast.LENGTH_SHORT).show()
} else if (UsbManager.ACTION_USB_DEVICE_ATTACHED == action) {
DataHolder.usbConnected.value = true
// Toast.makeText(context, "Attached", Toast.LENGTH_SHORT).show()
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
viewModel = ViewModelProvider(
this,
MyViewModelFactory(applicationContext)
)[MainViewModel::class.java]
setSupportActionBar(binding.myToolbar)
// supportActionBar?.setDisplayHomeAsUpEnabled(true)
setupListeners()
val filter = IntentFilter()
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED)
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED)
registerReceiver(mUsbReceiver, filter)
}
private fun checkAndUpdateUsbConnection() {
val availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(getSystemService(Context.USB_SERVICE) as UsbManager)
if (availableDrivers.isNotEmpty() && availableDrivers[0].device.productId == Constants.DEVICE_PRODUCT_ID && availableDrivers[0].device.vendorId == Constants.DEVICE_VENDOR_ID){
Log.d(TAG, "Device matched -> product = ${availableDrivers[0].device.productId}, vendor = ${availableDrivers[0].device.vendorId}")
DataHolder.usbConnected.value = true
} else if (availableDrivers.isNotEmpty()) {
Log.d(TAG, "Device NOT matched -> product = ${availableDrivers[0].device.productId}, vendor = ${availableDrivers[0].device.vendorId}")
Toast.makeText(this, "Device Not Compatible", Toast.LENGTH_SHORT).show()
DataHolder.usbConnected.value = false
} else {
Log.d(TAG, "Device NOT Connected")
DataHolder.usbConnected.value = false
}
}
private fun setupListeners() {
binding.cvItem1.setOnClickListener {
DataHolder.selectedTestType = TestType.SICKLECERT
val i = Intent(applicationContext, TestRightActivity::class.java)
startActivity(i)
}
binding.cvItem2.setOnClickListener {
DataHolder.selectedTestType = TestType.SICKLEFIND
val i = Intent(applicationContext, TestRightActivity::class.java)
startActivity(i)
}
DataHolder.usbConnected.observe(this){
// Log.d(TAG, "usbConnected observer called with value -> $it")
if (it){
myMenu?.get(0)?.icon = ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_24)
} else {
// Log.d(TAG, "into no block -> $it")
myMenu?.get(0)?.icon = ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_off_24)
}
}
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.my_menu, menu)
myMenu = menu
checkAndUpdateUsbConnection()
return true
}
}

View File

@@ -1,39 +0,0 @@
package com.example.hpos.presentation
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.hpos.R
import com.example.hpos.data.model.PatientData
class RVAdapter : RecyclerView.Adapter<RVAdapter.ViewHolder>() {
private val dataset = ArrayList<PatientData>()
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(
LayoutInflater.from(parent.context)
.inflate(R.layout.table_item, parent, false)
)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
}
override fun getItemCount(): Int {
return dataset.size
}
fun updateDataSet(newDataSet: ArrayList<PatientData>) {
dataset.clear()
dataset.addAll(newDataSet)
notifyDataSetChanged()
}
}

View File

@@ -1,118 +0,0 @@
package com.example.hpos.presentation
import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.provider.Settings
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import com.example.hpos.data.DataHolder
import com.example.hpos.databinding.ActivitySplashBinding
import com.example.hpos.util.MyUtils
/**
* Splash Activity
* Used for preprocessing of data, permissions
*/
class SplashActivity : AppCompatActivity() {
private lateinit var binding: ActivitySplashBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivitySplashBinding.inflate(layoutInflater)
setContentView(binding.root)
checkForPermissions()
}
private fun checkForPermissions() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
getPermissionsAboveAndroidR()
} else {
getPermissionsBelowAndroidR()
}
}
@RequiresApi(Build.VERSION_CODES.R)
private fun getPermissionsAboveAndroidR() {
// Checking if permission is already granted or not.
if (!Environment.isExternalStorageManager()) {
val storagePermissionResultLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (Environment.isExternalStorageManager()) {
DataHolder.isStoragePermissionGranted = true
moveToLandingPage()
} else {
DataHolder.isStoragePermissionGranted = false
Toast.makeText(
this,
"You must grant permission to storage to use the app",
Toast.LENGTH_SHORT
).show()
}
}
val intent = Intent()
intent.action = Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION
intent.data = Uri.fromParts("package", this.packageName, null)
storagePermissionResultLauncher.launch(intent)
} else {
DataHolder.isStoragePermissionGranted = true
moveToLandingPage()
}
}
private fun getPermissionsBelowAndroidR() {
val requestPermissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted: Boolean ->
if (isGranted) {
DataHolder.isStoragePermissionGranted = true
moveToLandingPage()
} else {
DataHolder.isStoragePermissionGranted = false
Toast.makeText(
this,
"You must grant permission to storage to use the app",
Toast.LENGTH_SHORT
).show()
}
}
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.READ_EXTERNAL_STORAGE
) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(
this,
Manifest.permission.WRITE_EXTERNAL_STORAGE
) != PackageManager.PERMISSION_GRANTED
) {
requestPermissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
} else {
DataHolder.isStoragePermissionGranted = true
moveToLandingPage()
}
}
private fun moveToLandingPage() {
createAppFolder()
val i = Intent(applicationContext, MainActivity::class.java)
startActivity(i)
}
private fun createAppFolder() {
val folderPath = MyUtils.createAppFolder(applicationContext)
if (folderPath != null){
DataHolder.isAppFolderCreated = true
DataHolder.appFolderPath = folderPath
}
}
}

View File

@@ -1,203 +0,0 @@
package com.example.hpos.presentation.testRight
import android.content.Intent
import android.os.Bundle
import android.util.Log
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 com.example.hpos.R
import com.example.hpos.data.DataHolder
import com.example.hpos.data.PreferenceUtility
import com.example.hpos.data.constant.Constants
import com.example.hpos.data.model.TestRightResultType
import com.example.hpos.data.model.TestType
import com.example.hpos.databinding.FragmentTestRightResultsBinding
import com.example.hpos.presentation.MainActivity
import com.example.hpos.util.MyUtils
import java.text.SimpleDateFormat
import java.util.*
class TestRightResults : Fragment() {
private lateinit var binding: FragmentTestRightResultsBinding
private val viewModel: TestRightViewModel by activityViewModels()
private val TAG = "TestRightResults"
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
// Inflate the layout for this fragment
binding = FragmentTestRightResultsBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupListeners()
updateResults()
// saveCsv()
// saveLog()
}
private fun setupListeners() {
binding.ivHome.setOnClickListener {
val i = Intent(requireContext().applicationContext, MainActivity::class.java)
startActivity(i)
}
binding.ivNext.setOnClickListener {
moveToSamplePage()
}
}
fun moveToSamplePage() {
if (DataHolder.sampleReadCounter > Constants.MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE) {
DataHolder.sampleReadCounter = 0
DataHolder.isReferenceTaken = false
parentFragmentManager.beginTransaction()
.replace(R.id.fl_main, TestRightExpReference())
.commit()
} else {
parentFragmentManager.beginTransaction().replace(R.id.fl_main, TestRightExpSample())
.commit()
}
}
private fun saveLog() {
Log.d(TAG, "saveLog() called")
val sdfDate = SimpleDateFormat("ddMMyyyy HHmmss")
val fileName: String = "log_" + sdfDate.format(Date()) + ".txt"
viewModel.saveLog(requireContext().applicationContext, fileName)
// if (!DataHolder.isAppFolderCreated) {
// val folderPath = MyUtils.createAppFolder(requireContext().applicationContext)
// if (folderPath != null) {
// DataHolder.isAppFolderCreated = true
// DataHolder.appFolderPath = folderPath
// viewModel.saveLog(DataHolder.appFolderPath, fileName)
// }
// } else {
// viewModel.saveLog(DataHolder.appFolderPath, fileName)
// }
}
// private fun saveCsv() {
// Log.d(TAG, "saveCsv() called")
//
// val sdfDate = SimpleDateFormat("ddMMyyyy HHmmss")
// val fileName: String = sdfDate.format(Date()) + ".csv"
//
// if (!DataHolder.isAppFolderCreated) {
// val folderPath = MyUtils.createAppFolder(requireContext().applicationContext)
// if (folderPath != null) {
// DataHolder.isAppFolderCreated = true
// DataHolder.appFolderPath = folderPath
// viewModel.saveCsv(DataHolder.appFolderPath, fileName)
//
// viewModel.saveCsvForTesting(DataHolder.appFolderPath, "testing$fileName")
// }
// } else {
// viewModel.saveCsv(DataHolder.appFolderPath, fileName)
//
// viewModel.saveCsvForTesting(DataHolder.appFolderPath, "testing$fileName")
// }
//
// }
private fun saveCsv() {
Log.d(TAG, "saveCsv() called")
// val sdfDate = SimpleDateFormat("ddMMyyyy HHmmss")
// val fileName: String = sdfDate.format(Date()) + ".csv"
val prefix = "HPOSSC_${DataHolder.deviceSerialNumber}_"
val fileExtension = ".csv"
val fileName = PreferenceUtility.generateId(requireContext(), prefix) + fileExtension
viewModel.saveCsv(requireContext().applicationContext, fileName)
viewModel.saveCsvForTesting(requireContext().applicationContext, "testing$fileName")
}
private fun updateResults() {
binding.tvName.text = getString(R.string.name_in_textview, viewModel.patientDetails.name)
binding.tvAge.text =
getString(R.string.age_in_textview, viewModel.patientDetails.age.toString())
binding.tvGender.text =
getString(R.string.gender_in_textview, viewModel.patientDetails.gender)
if (DataHolder.selectedTestType == TestType.SICKLECERT){
when (viewModel.patientDetails.results) {
TestRightResultType.NORMAL -> {
binding.resultNormal.visibility = View.VISIBLE
}
TestRightResultType.SICKLECELLDISEASE -> {
binding.resultDisease.visibility = View.VISIBLE
}
TestRightResultType.SICKLECELLTRAIT -> {
binding.resultTrait.visibility = View.VISIBLE
}
else -> {
// binding.resultUndefined.visibility = View.VISIBLE
Toast.makeText(requireContext().applicationContext, "Please Test Again", Toast.LENGTH_LONG).show()
moveToSamplePage()
// val i = Intent(requireContext().applicationContext, MainActivity::class.java)
// startActivity(i)
}
}
} else {
when (viewModel.patientDetails.results) {
TestRightResultType.SICKLECELLDISEASE -> {
binding.resultDisease.visibility = View.VISIBLE
binding.resultDisease.text = "Positive"
}
TestRightResultType.NORMAL -> {
binding.resultNormal.visibility = View.VISIBLE
binding.resultNormal.text = "Negative"
}
else -> {
Toast.makeText(requireContext().applicationContext, "Please Test Again", Toast.LENGTH_LONG).show()
moveToSamplePage()
// val i = Intent(requireContext().applicationContext, MainActivity::class.java)
// startActivity(i)
}
}
}
// when (viewModel.patientDetails.results) {
// TestRightResultType.NORMAL -> {
// binding.resultNormal.visibility = View.VISIBLE
// }
// TestRightResultType.SICKLECELLDISEASE -> {
// binding.resultDisease.visibility = View.VISIBLE
// }
// TestRightResultType.SICKLECELLTRAIT -> {
// binding.resultTrait.visibility = View.VISIBLE
// }
// else -> {
// binding.resultUndefined.visibility = View.VISIBLE
// }
// }
// Log.d(TAG, "\n\n\n\nFor intensity Reference array size = ${DataHolder.intensityReferenceArray.size}")
// for (each in DataHolder.intensityReferenceArray){
// Log.d(TAG, "${each}")
// }
//
// Log.d(TAG, "\n\n\n\nFor intensity Reference array size = ${viewModel.intensitySampleArray.size}")
// for (each in viewModel.intensitySampleArray){
// Log.d(TAG, "${each}")
// }
// Log.d(TAG,"")
}
}

View File

@@ -1,123 +0,0 @@
package com.example.hpos.presentation.testRight
import android.app.Service
import android.content.Intent
import android.hardware.usb.UsbDeviceConnection
import android.os.Binder
import android.os.IBinder
import android.util.Log
import com.example.hpos.data.constant.Constants
import com.example.hpos.data.constant.TestRightCommands
import com.example.hpos.presentation.UsbServiceListener
import com.hoho.android.usbserial.driver.UsbSerialDriver
import com.hoho.android.usbserial.driver.UsbSerialPort
import com.hoho.android.usbserial.util.SerialInputOutputManager
import java.io.IOException
class UsbService : Service() {
// Binder to be given to clients
private val binder = UsbServiceBinder()
private lateinit var mPort: UsbSerialPort
private var isUsbConnected = false
private val TAG = "UsbService"
inner class UsbServiceBinder : Binder() {
// Return this instance of UsbService so clients can call public methods
fun getService(): UsbService = this@UsbService
}
override fun onBind(intent: Intent): IBinder {
Log.d("surya", "onBind() called")
return binder
}
// fun connect(driver: UsbSerialDriver, connection: UsbDeviceConnection) {
// mPort = driver.ports[0] // Most devices have just one port (port 0)
// mPort.open(connection)
// mPort.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE)
//
// isUsbConnected = true
// Log.d(TAG, "My Usb Connected ${mPort.driver}")
// }
var listener: UsbServiceListener? = null
fun connect(driver: UsbSerialDriver, connection: UsbDeviceConnection) {
mPort = driver.ports[0] // Most devices have just one port (port 0)
mPort.open(connection)
mPort.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE)
isUsbConnected = true
Log.d(TAG, "My Usb Connected ${mPort.driver}")
val usbIoManager = SerialInputOutputManager(mPort,
object : SerialInputOutputManager.Listener{
override fun onNewData(data: ByteArray?) {
// Log.e(TAG, "onNewData() called inside eventDrivenWrite()")
listener?.onUsbRead(data)
}
override fun onRunError(e: Exception?) {
Log.e(TAG, "onRunError() called inside eventDrivenWrite()")
listener?.onUsbError(e)
}
})
usbIoManager.start();
}
fun disconnect() {
if(isUsbConnected){
mPort.close()
isUsbConnected = false;
Log.d(TAG, "My Usb disconnected:: ${mPort.driver}")
}
}
// fun eventDrivenWrite(command: TestRightCommands, listener: UsbServiceListener) {
// val usbIoManager = SerialInputOutputManager(mPort,
// object : SerialInputOutputManager.Listener{
// override fun onNewData(data: ByteArray?) {
// Log.e(TAG, "onNewData() called inside eventDrivenWrite() :: command = ${command.command}")
// listener.onUsbRead(data)
// }
// override fun onRunError(e: Exception?) {
// Log.e(TAG, "onRunError() called inside eventDrivenWrite()")
// listener.onUsbError(e)
// }
//
// })
// usbIoManager.start();
//
// try {
// mPort.write(command.command.toByteArray(), Constants.WRITE_TIMEOUT_MILLIS)
// } catch (e: IOException) {
// listener.onUsbError(e)
// }
// }
fun eventDrivenWrite(command: TestRightCommands, listener: UsbServiceListener) {
this.listener = listener
try {
mPort.write(command.command.toByteArray(), Constants.WRITE_TIMEOUT_MILLIS)
} catch (e: IOException) {
listener.onUsbError(e)
}
}
// fun write(command: TestRightCommands){
// mPort.write(command.command.toByteArray(), Constants.WRITE_TIMEOUT_MILLIS)
// }
// fun read(){
// val byteArray = ByteArray(3700)
// val len = mPort.read(byteArray, Constants.READ_TIMEOUT_MILLIS)
//
// Log.d(TAG, "length is $len")
// val byteArrayCropped = ByteArray(len)
// System.arraycopy(byteArray, 0, byteArrayCropped, 0, len)
//
// listener?.onUsbRead(byteArrayCropped)
// }
}

View File

@@ -1,25 +0,0 @@
package com.example.hpos.util
import android.content.Context
import android.os.Environment
import com.example.hpos.R
import java.io.File
object MyUtils {
fun createAppFolder(context: Context) : String? {
val folderPath = Environment.getExternalStorageDirectory().absolutePath + "/" + context.resources.getString(R.string.app_name) + "/"
val file = File(folderPath)
return if (!file.exists()) {
if (!file.mkdirs()) {
null
} else {
folderPath
}
} else {
folderPath
}
}
}

View File

@@ -1,19 +0,0 @@
package com.example.hpos.util
import android.content.Context
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.example.hpos.presentation.MainViewModel
import com.example.hpos.presentation.testRight.TestRightViewModel
class MyViewModelFactory(private val context: Context) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(MainViewModel::class.java))
return MainViewModel() as T
else if (modelClass.isAssignableFrom(TestRightViewModel::class.java))
return TestRightViewModel() as T
else
throw IllegalArgumentException("Unknown ViewModel class");
}
}

View File

@@ -0,0 +1,30 @@
package com.example.hpostesting
import android.app.Application
import android.content.Context
import androidx.room.Room
import com.example.hpostesting.data.dao.MyDatabase
import com.google.android.datatransport.runtime.dagger.Provides
import com.google.firebase.firestore.FirebaseFirestore
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.Singleton
@HiltAndroidApp
class HPOSTestingApplication: Application() {
val applicationScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
override fun onCreate() {
super.onCreate()
val applicationScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
val firestoreSettings = FirebaseFirestoreSettings.Builder()
.setPersistenceEnabled(true) // Enable offline persistence if needed
.build()
val firestore = FirebaseFirestore.getInstance()
firestore.firestoreSettings = firestoreSettings
}
}

View File

@@ -0,0 +1,30 @@
package com.example.hpostesting.data
import androidx.lifecycle.MutableLiveData
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.data.model.test.TestRightDeviceConstants
import com.example.hpostesting.data.model.test.TestType
object DataHolder {
var selectedTestType: TestType = TestType.SICKLECERT
val usbConnected = MutableLiveData(true)
var mobileUniqueId: String? = null
var isAppFolderCreated = false
var appFolderPath = ""
var isReferenceTaken = false
var sampleReadCounter = 0
var deviceConstant: TestRightDeviceConstants? = null
var deviceSerialNumber: String = "ABCD"
val deviceType = MutableLiveData<String>()
val wavelengthToPixelArray = ArrayList<Double>()
val intensityReferenceArray = ArrayList<Double>()
var selectedTest: UserData? = null
var hemoCubeTestData: HemoCubeTestData? = null
var kitSerial: String = ""
var location: UserData.Location? = null
var testExp: Boolean = true
var hemocubeResult: Double? = null
}

View File

@@ -0,0 +1,46 @@
package com.example.hpostesting.data
import android.util.Log
import com.example.hpostesting.data.model.Response
import com.example.hpostesting.data.repository.DatabaseRepository
import com.example.hpostesting.util.MyUtils
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
class FileUploader {
private val TAG = "FileUploader"
val repository = DatabaseRepository()
suspend fun start() {
val listOfFiles = repository.getAllFromPendingQueue()
for (each in listOfFiles){
// Checking internet connectivity & mobile as same or not
if (MyUtils.isInternetConnected() && each.mobileId == DataHolder.mobileUniqueId) {
Log.d(TAG, "uploading file ${each.pendingId}")
GlobalScope.launch {
val response = repository.uploadFileToStorage(each.patientId, each.filePath)
when (response) {
is Response.Success -> {
Log.d(TAG, "File Uploaded ${each.pendingId}")
repository.removeFromPendingQueue(each.pendingId)
}
is Response.Error -> {
Log.d(TAG, response.exception.toString())
}
}
}.join()
} else {
return
}
}
return
}
}

View File

@@ -0,0 +1,62 @@
package com.example.hpostesting.data
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

@@ -1,4 +1,4 @@
package com.example.hpos.data
package com.example.hpostesting.data
import android.content.Context
import android.content.SharedPreferences

View File

@@ -0,0 +1,58 @@
package com.example.hpostesting.data.constant
object Constants {
const val ACTION_USB_PERMISSION = "shanmukha.in.sickle_cell.USB_PERMISSION"
const val HOMOCUBE_USB_PERMISSION = "shanmukha.in.sickle_cell_homocube.USB_PERMISSION"
const val ABHA_APP_PACKAGE = "in.ndhm.phr"
const val WRITE_TIMEOUT_MILLIS = 30000 // 30 sec
const val READ_TIMEOUT_MILLIS = 60000 // 1 min
const val DELAY_BETWEEN_COMMANDS: Long = 1000
const val TEST_RIGHT_TOTAL_PIXEL = 3694
const val MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE = 40
const val RANGE_IN_RESULT_CALCULATIONS = 10
const val WAVELENGTH_OF_INTEREST_ONE = 427
const val WAVELENGTH_OF_INTEREST_TWO = 555
const val MIN_WAVELENGTH_RANGE_TO_RECORD = 350
const val MAX_WAVELENGTH_RANGE_TO_RECORD = 750
const val DEVICE_PRODUCT_ID = 24597
const val DEVICE_TYPE_HOMOCUBE = "HOMOCUBE"
const val DEVICE_TYPE_TEST_RIGHT = "TEST_RIGHT"
const val DEVICE_VENDOR_ID = 1027
const val HOMO_CUBE_ID = 29987
const val VENDOR_ID = 6790
const val ERROR_NORMAL = 400
const val ERROR_CRITICAL = 401
const val NO_OF_TIMES_TO_RUN_SAMPLE = 1
const val USER_ID = "usernameId"
val STATICID = listOf(
"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",
)
const val password = "SMI@12345"
const val KIT_NUMBER = "KitNumber"
const val KIT_COUNT = "KitCount"
const val BUFFER_VALUE_1 = "BufferValue1"
const val BUFFER_VALUE_2 = "BufferValue2"
}

View File

@@ -0,0 +1,8 @@
package com.example.hpostesting.data.constant
enum class HemoCubeCommands(val command: String) {
startBuffer("B\r"),
getBuffer("Q\r"),
startSample("S\r"),
getSample("P\r"),
}

View File

@@ -1,4 +1,4 @@
package com.example.hpos.data.constant
package com.example.hpostesting.data.constant
enum class TestRightCommands(val command: String) {
led2Set50("led2 50\r"),

View File

@@ -0,0 +1,38 @@
package com.example.hpostesting.data.dao
import androidx.room.TypeConverter
import com.example.hpostesting.data.model.patient.UserData
import com.google.common.reflect.TypeToken
import com.google.gson.Gson
class Converters {
private val gson = Gson()
@TypeConverter
fun fromString(value: String?): UserData.Location? {
return if (value != null) {
gson.fromJson(value, UserData.Location::class.java)
} else {
null
}
}
@TypeConverter
fun toString(location: UserData.Location?): String? {
return if (location != null) {
gson.toJson(location)
} else {
null
}
}
@TypeConverter
fun fromList(list: List<Double>): String {
return Gson().toJson(list)
}
@TypeConverter
fun toList(json: String): List<Double> {
val type = object : TypeToken<List<Double>>() {}.type
return Gson().fromJson(json, type)
}
}

View File

@@ -0,0 +1,24 @@
package com.example.hpostesting.data.dao
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.UserData
@Dao
interface DeviceDao {
@Query("SELECT * from device_table")
fun getAll(): LiveData<List<HemoCubeTestData>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAll(deviceData: DeviceData)
@Query("SELECT * FROM device_table WHERE deviceId = :id")
suspend fun getUserByID(id: String): HemoCubeTestData
@Query("DELETE FROM device_table WHERE deviceId = :id")
suspend fun deleteById(id: String)
}

View File

@@ -0,0 +1,23 @@
package com.example.hpostesting.data.dao
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.UserData
@Dao
interface HemoCubeDao {
@Query("SELECT * from hemo_cube_test_table")
fun getAll(): LiveData<List<HemoCubeTestData>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAll(hemoCubeTestData: HemoCubeTestData)
@Query("SELECT * FROM hemo_cube_test_table WHERE _id = :id")
suspend fun getUserByID(id: String): HemoCubeTestData
@Query("DELETE FROM hemo_cube_test_table WHERE _id = :id")
suspend fun deleteById(id: String)
}

View File

@@ -0,0 +1,19 @@
package com.example.hpostesting.data.dao
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.google.android.datatransport.runtime.dagger.Provides
import javax.inject.Singleton
@Database(entities = [UserData::class, HemoCubeTestData::class, DeviceData::class], version = 3, exportSchema = false)
@TypeConverters(Converters::class)
abstract class MyDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
abstract fun hemoCubeDao(): HemoCubeDao
}

View File

@@ -0,0 +1,23 @@
package com.example.hpostesting.data.dao
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.example.hpostesting.data.model.patient.UserData
@Dao
interface UserDao {
@Query("SELECT * from user_table")
fun getAll(): LiveData<List<UserData>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAll(userData: UserData)
@Query("SELECT * FROM user_table WHERE _id = :id")
suspend fun getUserByID(id: String): UserData
@Query("DELETE FROM user_table WHERE _id = :id")
suspend fun deleteById(id: String)
}

View File

@@ -0,0 +1,23 @@
package com.example.hpostesting.data.datasource
import com.opencsv.CSVWriter
import java.io.File
import java.io.FileWriter
class LocalFileDataSource {
fun saveCsvToDisk(filepath: String, contents: ArrayList<Array<String>>){
val writer = CSVWriter(FileWriter(filepath))
writer.writeAll(contents) // data is adding to csv
writer.close()
}
fun saveTextToDisk(filepath: String, contents: String){
val writer = FileWriter(File(filepath))
writer.append(contents)
writer.flush()
writer.close()
}
}

View File

@@ -0,0 +1,21 @@
package com.example.hpostesting.data.model
class AadharCard {
var name = ""
var dateOfBirth = ""
var gender = ""
var careOf = ""
var district = ""
var landmark = ""
var house = ""
var location = ""
var pinCode = ""
var postOffice = ""
var state = ""
var street = ""
var subDistrict = ""
var vtc = ""
var mobile = ""
}

View File

@@ -1,4 +1,4 @@
package com.example.hpos.data.model
package com.example.hpostesting.data.model
data class CalculationVariableForTest(
var pixelNo: Int,

View File

@@ -1,4 +1,4 @@
package com.example.hpos.data.model
package com.example.hpostesting.data.model
data class ErrorMessage (
val message: String,

View File

@@ -0,0 +1,8 @@
package com.example.hpostesting.data.model
data class Location(
var latitude: Double?,
var longitude: Double?
) {
constructor() : this(null, null)
}

View File

@@ -1,4 +1,6 @@
package com.example.hpos.data.model
package com.example.hpostesting.data.model
import com.example.hpostesting.data.model.test.TestRightResultType
data class PatientData(
val name: String,

View File

@@ -0,0 +1,15 @@
package com.example.hpostesting.data.model
import java.util.Calendar
import java.util.Date
data class PendingUploads(
// Filename
val pendingId: String,
val mobileId: String,
val patientId: String,
val filePath: String,
val timeAdded: Date
) {
constructor(): this("", "", "", "", Calendar.getInstance().time)
}

View File

@@ -0,0 +1,7 @@
package com.example.hpostesting.data.model
sealed class Response<out R> {
data class Success<out T>(val data: T) : Response<T>()
data class Error(val exception: Exception) : Response<Nothing>()
// object Loading : Response<Nothing>()
}

View File

@@ -0,0 +1,19 @@
package com.example.hpostesting.data.model.patient
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.google.firebase.firestore.PropertyName
@Entity(tableName = "device_table")
data class DeviceData(
@PrimaryKey
var _id: String = "",
@get:PropertyName("deviceId") @set:PropertyName("deviceId")
var deviceId: String = "",
@get:PropertyName("deviceType") @set:PropertyName("deviceType")
var deviceType: String = "",
@get:PropertyName("coefficients") @set:PropertyName("coefficients")
var coefficients: List<Double> = emptyList(),
@get:PropertyName("calibratedAt") @set:PropertyName("calibratedAt")
var calibratedAt: String = ""
)

View File

@@ -0,0 +1,34 @@
package com.example.hpostesting.data.model.patient
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "hemo_cube_test_table")
data class HemoCubeTestData(
@PrimaryKey
var _id: String = "",
var name: String = "",
var birthYear: String = "",
var userImageURL: String = "",
var location: UserData.Location? = null,
var reportUploadTime: String? = "",
var testType: String? = "HEMOCUBE",
var testTime: String? = "",
var testStatus: Boolean? = false,
var localFlag: Boolean = false,
var deviceId: String? = "",
var appVersion:String? = "",
var deviceSerialNumber: String = "",
var deviceType: String = "HEMOCUBE",
var kitSerial: String = "",
var resultData: String = "",
var led1Buffer: Double? = null,
var led2Buffer: Double? = null,
var led1Sample: Double? = null,
var led2Sample: Double? = null,
var led1Average: Double? = null,
var led2Average: Double? = null,
var deviceRatio: Double? = null,
var calculatedRatio: Double? = null,
var classificationResult: String = ""
)

View File

@@ -0,0 +1,70 @@
package com.example.hpostesting.data.model.patient
import java.util.Date
data class PatientDetails(
var id: String,
var isIdABHA: Boolean,
var name: String?,
var yob: Int?,
var gender: Gender?,
var mobile: String?,
var isUnderMedication: Boolean?,
var isUnderTransfusion: Boolean?,
val photoUrl: String?,
var careOf: String?,
var isMarried: Boolean?,
var bloodGroup: String?,
var address: Address?,
var category: Category?,
var registerDate: Date?,
var uploadDate: Date?
) {
constructor() : this(
"",
false,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null
)
enum class Gender {
MALE,
FEMALE,
OTHER
}
data class Address(
var house: String?,
val street: String?,
var city: String?,
val landMark: String?,
var postOffice: String?,
var district: String?,
val subDistrict: String?,
var state: String?,
val vtc: String?,
var pinCode: Int?,
) {
constructor() : this(null, null, null, null, null, null, null, null, null, null)
}
enum class Category {
GENERAL,
OBC,
SC,
ST,
}
}

View File

@@ -0,0 +1,47 @@
package com.example.hpostesting.data.model.patient
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.example.hpostesting.data.model.test.TestRightResultType
@Entity(tableName = "user_table")
data class UserData(
@PrimaryKey
var _id: String = "",
var name: String = "",
var birthYear: String = "",
var userImageURL: String = "",
var location: Location? = null,
var createdBy: String? = "",
var reportUploadTime: String? = "",
var testTime: String? = "",
var testStatus: Boolean? = false,
var mobileId: String = "",
var deviceId: String = "",
var deviceSerialNumber: String = "",
var kitSerial: String = "",
var csvPath: String = "",
var reportPath: String = "",
var result: TestRightResultType? = null,
var resultRatio: Double? = null
) {
enum class Gender {
MALE,
FEMALE,
OTHER
}
data class Location(
var latitude: Double? = null,
var longitude: Double? = null
)
}
fun UserData.toHemoCubeTestData() = HemoCubeTestData(
_id = _id,
name = name,
birthYear = birthYear,
userImageURL = userImageURL,
testStatus = testStatus,
location = location
)

View File

@@ -0,0 +1,55 @@
package com.example.hpostesting.data.model.test
import com.example.hpostesting.data.model.Location
import java.util.Date
data class TestDetails(
val testID: String,
var testStatus: Status,
val patientID: String,
val patientName: String,
val patientAge: Int?,
var resultRatio: Double?,
var result: TestRightResultType?,
val reportPath: String?,
val csvPath: String?,
val logPath: String?,
// Meta Data
var deviceId: String?,
val mobileId: String,
var kitSerial: String?,
val location: Location?,
val appVersion: String,
val registeredTime: Date?,
var uploadTime: Date?
) {
constructor() : this(
"",
Status.PENDING,
"",
"",
null,
null,
null,
null,
null,
null,
null,
"",
null,
null,
"",
null,
null
)
}
enum class Status {
COMPLETED,
PENDING,
INPROGRESS
}

View File

@@ -1,4 +1,4 @@
package com.example.hpos.data.model
package com.example.hpostesting.data.model.test
data class TestInfo(
val value: String,

View File

@@ -1,4 +1,4 @@
package com.example.hpos.data.model
package com.example.hpostesting.data.model.test
data class TestRightCalculationData(
var absorbanceOne: Double?,

View File

@@ -1,4 +1,4 @@
package com.example.hpos.data.model
package com.example.hpostesting.data.model.test
data class TestRightDeviceConstants(
var a: String,

View File

@@ -1,8 +1,10 @@
package com.example.hpos.data.model
package com.example.hpostesting.data.model.test
enum class TestRightResultType {
NORMAL,
SICKLECELLTRAIT,
SICKLECELLDISEASE,
POSITIVEBORDERLINE,
NEGATIVEBORDERLINE,
UNDEFINED
}

View File

@@ -1,4 +1,4 @@
package com.example.hpos.data.model
package com.example.hpostesting.data.model.test
enum class TestType {
SICKLECERT,

View File

@@ -0,0 +1,134 @@
package com.example.hpostesting.data.repository
import android.content.Context
import android.net.Uri
import androidx.room.Room
import com.example.hpostesting.data.dao.MyDatabase
import com.example.hpostesting.data.model.PendingUploads
import com.example.hpostesting.data.model.Response
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.UserData
import com.google.android.datatransport.runtime.dagger.Provides
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 kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.tasks.await
import kotlinx.coroutines.withContext
import java.io.File
import javax.inject.Singleton
class DatabaseRepository : Repository {
private val db: FirebaseFirestore = Firebase.firestore
private val storage = Firebase.storage
suspend fun addTestToDatabase(data: HemoCubeTestData?): Response<String> {
return try {
val userdata = db.collection("patientData").whereEqualTo("_id", data!!._id).get().await()
if (userdata.documents.isNotEmpty()) {
userdata.documents.forEach {
db.collection("patientData").document(it.id).update("testStatus", true)
}
}
db.collection("testData").add(data!!).await()
Response.Success(data!!._id)
} catch (e: Exception) {
Response.Error(e)
}
}
suspend fun addTestToDatabase(data: UserData?): Response<String> {
return try {
val userdata = db.collection("patientData").whereEqualTo("_id", data!!._id).get().await()
if (userdata.documents.isNotEmpty()) {
userdata.documents.forEach {
db.collection("patientData").document(it.id).update("testStatus", true)
}
}
db.collection("testData").add(data!!).await()
Response.Success(data!!._id)
} catch (e: Exception) {
Response.Error(e)
}
}
suspend fun uploadFileToStorage(patientID: String, filePath: String): Response<Boolean> {
try {
val file = Uri.fromFile(File(filePath))
val riversRef = storage.reference.child("$patientID/${file.lastPathSegment}")
riversRef.putFile(file).await()
return Response.Success(true)
} catch (e: Exception) {
e.printStackTrace()
return Response.Error(e)
}
}
suspend fun addToPendingQueue(pendingUploads: PendingUploads): Response<Boolean> {
return try {
db.collection("pendingUploads").document(pendingUploads.pendingId).set(pendingUploads)
.await()
Response.Success(true)
} catch (e: Exception) {
e.printStackTrace()
Response.Error(e)
}
}
suspend fun getAllFromPendingQueue(): List<PendingUploads> {
val pendingList = mutableListOf<PendingUploads>()
return try {
val querySnapshot = db.collection("pendingUploads").orderBy("timeAdded").get().await()
for (doc in querySnapshot.documents) {
val pendingFile = doc.toObject(PendingUploads::class.java)
pendingFile?.let {
pendingList.add(it)
}
}
pendingList
} catch (e: Exception) {
e.printStackTrace()
pendingList
}
}
suspend fun removeFromPendingQueue(fileName: String): Response<Boolean> {
return try {
db.collection("pendingUploads").document(fileName).delete().await()
Response.Success(true)
} catch (e: Exception) {
e.printStackTrace()
Response.Error(e)
}
}
suspend fun getDeviceData(): List<DeviceData> {
return db.collection("devices").get().await().toObjects(DeviceData::class.java)
}
suspend fun getDeviceDataById(deviceId: String): DeviceData? {
val querySnapshot = db.collection("devices").get().await()
val allDeviceDataList = querySnapshot.toObjects(DeviceData::class.java)
// Find the DeviceData object with the specified deviceId
return allDeviceDataList.find { it.deviceId == deviceId }
}
}

View File

@@ -0,0 +1,11 @@
package com.example.hpostesting.data.repository
import com.example.hpostesting.data.datasource.LocalFileDataSource
class LocalFileRepository(private val localFileDataSource: LocalFileDataSource) {
fun saveCsvToDisk(filepath: String, contents: ArrayList<Array<String>>) =
localFileDataSource.saveCsvToDisk(filepath, contents)
fun saveTextToDisk(filepath: String, contents: String) =
localFileDataSource.saveTextToDisk(filepath, contents)
}

View File

@@ -0,0 +1,5 @@
package com.example.hpostesting.data.repository
interface Repository {
// suspend fun addToDatabase(data: PatientDetails)
}

View File

@@ -1,8 +1,8 @@
package com.example.hpos.domain
package com.example.hpostesting.domain
import com.example.hpos.data.constant.Constants
import com.example.hpos.data.model.TestRightCalculationData
import com.example.hpos.data.model.TestRightResultType
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.model.test.TestRightCalculationData
import com.example.hpostesting.data.model.test.TestRightResultType
class ResultCalculationWithMaxImpl : TestRightResultCalculation {
@@ -57,24 +57,24 @@ class ResultCalculationWithMaxImpl : TestRightResultCalculation {
val value = absorbanceAtWaveTwo / absorbanceAtWaveOne
testRightCalculationData.ratioValue = value
if (value < 0.28 || value == 0.0) {
if (value <= 0.29) {
testRightCalculationData.ratioMinRange = 0.0
testRightCalculationData.ratioMaxRange = 0.28
testRightCalculationData.ratioMaxRange = 0.29
return TestRightResultType.NORMAL
} else if (value >= 0.28 && value < 0.285) {
testRightCalculationData.ratioMinRange = 0.28
testRightCalculationData.ratioMaxRange = 0.285
return TestRightResultType.UNDEFINED
} else if (value >= 0.285 && value < 0.52) {
testRightCalculationData.ratioMinRange = 0.285
testRightCalculationData.ratioMaxRange = 0.52
} else if (value > 0.29 && value <= 0.32) {
testRightCalculationData.ratioMinRange = 0.29
testRightCalculationData.ratioMaxRange = 0.32
return TestRightResultType.NEGATIVEBORDERLINE
} else if (value > 0.32 && value <= 0.50) {
testRightCalculationData.ratioMinRange = 0.32
testRightCalculationData.ratioMaxRange = 0.50
return TestRightResultType.SICKLECELLTRAIT
} else if (value >= 0.52 && value < 0.525) {
testRightCalculationData.ratioMinRange = 0.52
testRightCalculationData.ratioMaxRange = 0.525
return TestRightResultType.UNDEFINED
}else if (value >= 0.525) {
testRightCalculationData.ratioMinRange = 0.525
} else if (value > 0.50 && value <= 0.55) {
testRightCalculationData.ratioMinRange = 0.50
testRightCalculationData.ratioMaxRange = 0.55
return TestRightResultType.POSITIVEBORDERLINE
}else if (value > 0.55) {
testRightCalculationData.ratioMinRange = 0.55
testRightCalculationData.ratioMaxRange = 999.0
return TestRightResultType.SICKLECELLDISEASE
}

View File

@@ -1,45 +1,44 @@
package com.example.hpos.domain
package com.example.hpostesting.domain
import android.util.Log
import com.example.hpos.data.constant.Constants
import com.example.hpos.data.model.PatientData
import com.example.hpos.data.model.TestRightCalculationData
import com.opencsv.CSVWriter
import java.io.File
import java.io.FileWriter
import com.example.hpostesting.data.repository.LocalFileRepository
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.data.model.test.TestRightCalculationData
import java.util.Collections.sort
class SaveRawData {
class SaveRawData(private val localFileRepository: LocalFileRepository) {
private val TAG = "saverawdata"
fun saveCsv(folderPath: String, fileName: String, matrix: ArrayList<ArrayList<Double>>) {
// try {
val fullPath = "$folderPath/$fileName"
val writer = CSVWriter(FileWriter(fullPath))
val fullPath = "$folderPath/$fileName"
// val writer = CSVWriter(FileWriter(fullPath))
sort(matrix) { one: ArrayList<Double>, two: ArrayList<Double> ->
one[0].compareTo(two[0])
}
sort(matrix) { one: ArrayList<Double>, two: ArrayList<Double> ->
one[0].compareTo(two[0])
}
val content = ArrayList<Array<String>>()
content.add(arrayOf("NM", "CA"))
val content = ArrayList<Array<String>>()
content.add(arrayOf("NM", "CA"))
for (eachRow in matrix) {
for (eachRow in matrix) {
if (eachRow[0] >= Constants.MIN_WAVELENGTH_RANGE_TO_RECORD && eachRow[0] < Constants.MAX_WAVELENGTH_RANGE_TO_RECORD + 1) {
if (eachRow[0] >= Constants.MIN_WAVELENGTH_RANGE_TO_RECORD && eachRow[0] < Constants.MAX_WAVELENGTH_RANGE_TO_RECORD + 1) {
// val rowContent = arrayOf(String.format("%.3f", eachRow[0]), String.format("%.3f", eachRow[1]))
val rowContent =
arrayOf(
String.format("%.10f", eachRow[0]),
String.format("%.10f", eachRow[1])
)
content.add(rowContent)
}
val rowContent =
arrayOf(
String.format("%.10f", eachRow[0]),
String.format("%.10f", eachRow[1])
)
content.add(rowContent)
}
}
writer.writeAll(content) // data is adding to csv
writer.close()
localFileRepository.saveCsvToDisk(fullPath, content)
// writer.writeAll(content) // data is adding to csv
// writer.close()
// } catch (e: Exception) {
// Log.e(TAG, e.toString())
@@ -47,15 +46,18 @@ class SaveRawData {
}
fun saveLog(folderPath: String, fileName: String, calculationData: TestRightCalculationData) {
val fileObj = File(folderPath, fileName)
val writer = FileWriter(fileObj)
// val fileObj = File(folderPath, fileName)
// val writer = FileWriter(fileObj)
writer.append(getLogStringFromObj(calculationData))
writer.flush()
writer.close()
// writer.append(getLogStringFromObj(calculationData))
// writer.flush()
// writer.close()
val fullPath = folderPath + fileName
localFileRepository.saveTextToDisk(fullPath, getLogStringFromObj(calculationData))
}
fun getLogStringFromObj(calculationData: TestRightCalculationData): String {
private fun getLogStringFromObj(calculationData: TestRightCalculationData): String {
var outputString = "Test calculation logs ==>\n"
outputString += "Absorbance one = ${
String.format(
@@ -96,24 +98,30 @@ class SaveRawData {
folderPath: String,
fileName: String,
calculationData: TestRightCalculationData,
patientData: PatientData
testDetails: UserData?
) {
val fileObj = File(folderPath, fileName)
val writer = FileWriter(fileObj)
// val fileObj = File(folderPath, fileName)
// val writer = FileWriter(fileObj)
writer.append(getLogStringFromObjWithPatientData(calculationData, patientData))
writer.flush()
writer.close()
// writer.append(getLogStringFromObjWithPatientData(calculationData, patientData))
// writer.flush()
// writer.close()
val fullPath = folderPath + fileName
localFileRepository.saveTextToDisk(
fullPath,
getLogStringFromObjWithPatientData(calculationData, testDetails)
)
}
private fun getLogStringFromObjWithPatientData(
calculationData: TestRightCalculationData,
patientData: PatientData
testDetails: UserData?
): String {
var outputString = "Test calculation logs ==>\n"
outputString += "Name = ${patientData.name}\n"
outputString += "Age = ${patientData.age}\n"
outputString += "Gender = ${patientData.gender}\n"
outputString += "Name = ${testDetails?.name}\n"
outputString += "ID = ${testDetails?._id}\n"
// outputString += "Gender = ${patientData.gender}\n"
outputString += "Absorbance one = ${
String.format(
"%.3f",

View File

@@ -1,13 +1,9 @@
package com.example.hpos.domain
package com.example.hpostesting.domain
import android.util.Log
import com.example.hpos.data.model.CalculationVariableForTest
import com.opencsv.CSVWriter
import java.io.File
import java.io.FileOutputStream
import java.io.FileWriter
import com.example.hpostesting.data.repository.LocalFileRepository
import com.example.hpostesting.data.model.CalculationVariableForTest
class SaveRawDataTest {
class SaveRawDataTest(private val localFileRepository: LocalFileRepository) {
private val TAG = "SaveRawDataTest"
@@ -15,7 +11,7 @@ class SaveRawDataTest {
// try {
val fullPath = "$folderPath/$fileName"
val writer = CSVWriter(FileWriter(fullPath))
// val writer = CSVWriter(FileWriter(fullPath))
val content = ArrayList<Array<String>>()
// Header
@@ -35,27 +31,40 @@ class SaveRawDataTest {
content.add(rowContent)
}
writer.writeAll(content) // data is adding to csv
writer.close()
localFileRepository.saveCsvToDisk(fullPath, content)
// writer.writeAll(content) // data is adding to csv
// writer.close()
// } catch (e: Exception){
// Log.e(TAG, e.toString())
// }
}
fun saveLog(folderPath: String, fileName: String, isReference: Boolean, fullString: String) {
val fileObj = File(folderPath, fileName)
// val fileObj = File(folderPath, fileName)
// Log.d(TAG, "$folderPath --- $fileName")
val writer = FileWriter(fileObj)
// val writer = FileWriter(fileObj)
if (isReference)
writer.append("\nREFERENCE OUTPUT\n")
// if (isReference)
// writer.append("\nREFERENCE OUTPUT\n")
// else
// writer.append("\nSAMPLE OUTPUT\n")
//
// writer.append(fullString)
// writer.flush()
// writer.close()
val filePath = folderPath + fileName
var stringToWrite = ""
stringToWrite += if (isReference)
"\nREFERENCE OUTPUT\n"
else
writer.append("\nSAMPLE OUTPUT\n")
"\nSAMPLE OUTPUT\n"
stringToWrite += fullString
localFileRepository.saveTextToDisk(filePath, stringToWrite)
writer.append(fullString)
writer.flush()
writer.close()
}

View File

@@ -1,8 +1,8 @@
package com.example.hpos.domain
package com.example.hpostesting.domain
import com.example.hpos.data.constant.Constants
import com.example.hpos.data.model.TestRightCalculationData
import com.example.hpos.data.model.TestRightResultType
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.model.test.TestRightCalculationData
import com.example.hpostesting.data.model.test.TestRightResultType
class SickleFindResultCaluculationWithMaxImpl : TestRightResultCalculation{

View File

@@ -1,6 +1,6 @@
package com.example.hpos.domain
package com.example.hpostesting.domain
import com.example.hpos.data.model.TestRightCalculationData
import com.example.hpostesting.data.model.test.TestRightCalculationData
interface TestRightResultCalculation {
fun getResults(

View File

@@ -0,0 +1,72 @@
package com.example.hpostesting.domain.di
import android.app.Application
import android.content.Context
import androidx.room.Room
import com.example.hpostesting.data.dao.HemoCubeDao
import com.example.hpostesting.data.dao.MyDatabase
import com.example.hpostesting.data.dao.UserDao
import com.example.hpostesting.data.datasource.LocalFileDataSource
import com.example.hpostesting.data.repository.DatabaseRepository
import com.example.hpostesting.data.repository.LocalFileRepository
import com.example.hpostesting.domain.SaveRawData
import com.example.hpostesting.domain.SaveRawDataTest
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
@Provides
@Singleton
fun provideMyDatabase(@ApplicationContext context: Context): MyDatabase {
return Room.databaseBuilder(
context, MyDatabase::class.java, "my_database"
)
.fallbackToDestructiveMigration()
.build()
}
@Provides
@Singleton
fun provideMyDao(myDatabase: MyDatabase): UserDao {
return myDatabase.userDao()
}
@Provides
@Singleton
fun provideMyHemo(myDatabase: MyDatabase): HemoCubeDao {
return myDatabase.hemoCubeDao()
}
@Provides
@Singleton
fun provideContext(application: Application): Context {
return application.applicationContext
}
@Provides
@Singleton
fun provideSaveRawData(): SaveRawData {
val repository = LocalFileRepository(LocalFileDataSource())
return SaveRawData(repository)
}
@Provides
@Singleton
fun provideSaveRawDataTest(): SaveRawDataTest {
val repository = LocalFileRepository(LocalFileDataSource())
return SaveRawDataTest(repository)
}
@Provides
@Singleton
fun provideDatabaseRepository(): DatabaseRepository {
return DatabaseRepository()
}
}

View File

@@ -0,0 +1,187 @@
package com.example.hpostesting.presentation
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.example.hpostesting.presentation.hemocube.HemocubeActivity
import com.example.hpostesting.presentation.testRight.TestRightActivity
import com.google.android.material.snackbar.Snackbar
import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.journeyapps.barcodescanner.ScanContract
import com.journeyapps.barcodescanner.ScanIntentResult
import com.journeyapps.barcodescanner.ScanOptions
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityKitScanBinding
class KitScanActivity : AppCompatActivity() {
private val TAG = "KitScanActivity"
private lateinit var binding: ActivityKitScanBinding
private lateinit var sharedPreference: SharedPreferences
private val barcodeLauncher = registerForActivityResult(
ScanContract()
) { result: ScanIntentResult ->
if (result.contents.isNullOrEmpty()) {
Toast.makeText(this, "Cancelled: Unable to scan, Try Again!!", Toast.LENGTH_LONG).show()
} else {
Log.d(TAG, result.contents)
processScannedData(result.contents)
}
}
private fun processScannedData(contents: String) {
binding.nameEditText.setText(contents)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityKitScanBinding.inflate(layoutInflater)
sharedPreference = this.getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE)
setContentView(binding.root)
if (DataHolder.sampleReadCounter <= Constants.MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE && DataHolder.isReferenceTaken) {
DataHolder.selectedTest!!.kitSerial = DataHolder.kitSerial
moveToNext()
}
// if (checkHemoCubeKitData()) {
// DataHolder.selectedTest!!.kitSerial =
// sharedPreference.getString(Constants.KIT_NUMBER, "").toString()
// moveToNext()
// } else {
// with(sharedPreference.edit()) {
// putString(Constants.KIT_NUMBER, "")
// putInt(Constants.KIT_COUNT, 0)
// putString(Constants.BUFFER_VALUE_1, "")
// putString(Constants.BUFFER_VALUE_2, "")
// apply()
// }
// }
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/")
setSupportActionBar(binding.toolbar)
binding.btnScanNow.setOnClickListener {
startScanningNow()
}
binding.btnGo.setOnClickListener {
val serialNumber = binding.nameEditText.text.toString().trim()
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, "Invalid KIT Number", Toast.LENGTH_LONG).show()
}
}
}
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) < 35
}
private fun isSerialValid(s: String): Boolean {
if (s.length != 17) {
binding.nameEditText.error = getString(R.string.invalid_kit)
return false
}
return true
}
private fun moveToNext() {
DataHolder.deviceType.observe(this) { deviceType ->
when (deviceType) {
Constants.DEVICE_TYPE_HOMOCUBE -> {
val i = Intent(applicationContext, HemocubeActivity::class.java)
startActivity(i)
}
Constants.DEVICE_TYPE_TEST_RIGHT -> {
val i = Intent(applicationContext, TestRightActivity::class.java)
startActivity(i)
}
}
}
}
private fun startScanningNow() {
val options = ScanOptions()
options.setDesiredBarcodeFormats(ScanOptions.QR_CODE)
options.setPrompt("Scan a barcode")
options.setCameraId(0) // Use a specific camera of the device
options.setBeepEnabled(true)
options.setBarcodeImageEnabled(true)
options.setPrompt("Start Scanning")
options.setOrientationLocked(false)
// options.setTimeout(10000) // in ms
barcodeLauncher.launch(options)
}
private fun checkDataNotNull(): Boolean {
return if (DataHolder.selectedTest?._id == null) {
Toast.makeText(
applicationContext, "Please Select patient before starting test", Toast.LENGTH_SHORT
).show()
val i = Intent(applicationContext, DashboardActivity::class.java)
startActivity(i)
false
} else {
true
}
}
}

View File

@@ -0,0 +1,345 @@
package com.example.hpostesting.presentation
import android.Manifest
import android.content.*
import android.content.pm.PackageManager
import android.hardware.usb.UsbManager
import android.location.Location
import android.os.Bundle
import android.util.Log
import android.view.Menu
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.view.get
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.data.model.test.TestType
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.google.android.gms.location.*
import com.google.android.material.snackbar.Snackbar
import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.hoho.android.usbserial.driver.UsbSerialProber
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 val usbReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent) {
when (intent.action) {
UsbManager.ACTION_USB_DEVICE_DETACHED -> DataHolder.usbConnected.value = false
UsbManager.ACTION_USB_DEVICE_ATTACHED -> DataHolder.usbConnected.value = true
}
checkAndUpdateUsbConnection()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
setSupportActionBar(binding.myToolbar)
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)
Log.i("Location", DataHolder.location.toString())
}
}
}
val usbFilter = IntentFilter().apply {
addAction(UsbManager.ACTION_USB_DEVICE_DETACHED)
addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED)
}
registerReceiver(usbReceiver, usbFilter)
DataHolder.deviceType.observe(this) { deviceType ->
with(binding) {
if (deviceType == Constants.DEVICE_TYPE_HOMOCUBE) {
cvItem1.visibility = View.VISIBLE
cvItem3.visibility = View.VISIBLE
cvItem2.visibility = View.GONE
cvItem4.visibility = View.GONE
}
DataHolder.usbConnected.value = true
}
}
if (DataHolder.selectedTest == null) {
startActivity(Intent(this, DashboardActivity::class.java))
finish()
}
// val crashButton = Button(this)
// crashButton.text = "Test Crash"
// crashButton.setOnClickListener {
// throw RuntimeException("Test Crash") // Force a crash
// }
//
// addContentView(crashButton, ViewGroup.LayoutParams(
// ViewGroup.LayoutParams.MATCH_PARENT,
// ViewGroup.LayoutParams.WRAP_CONTENT))
}
private fun checkAndUpdateUsbConnection() {
val availableDrivers = UsbSerialProber.getDefaultProber()
.findAllDrivers(getSystemService(Context.USB_SERVICE) as UsbManager)
val deviceType = when {
availableDrivers.isNotEmpty() -> {
val device = availableDrivers[0].device
when {
device.productId == Constants.HOMO_CUBE_ID && device.vendorId == Constants.VENDOR_ID -> {
binding.cvItem1.visibility = View.VISIBLE
binding.cvItem3.visibility = View.VISIBLE
binding.cvItem2.visibility = View.GONE
binding.cvItem4.visibility = View.GONE
DataHolder.deviceType.postValue(Constants.DEVICE_TYPE_HOMOCUBE)
Constants.DEVICE_TYPE_HOMOCUBE
}
device.productId == Constants.DEVICE_PRODUCT_ID && device.vendorId == Constants.DEVICE_VENDOR_ID -> {
Log.d(
TAG,
"Device matched -> product = ${device.productId}, vendor = ${device.vendorId}"
)
binding.cvItem1.visibility = View.VISIBLE
binding.cvItem3.visibility = View.VISIBLE
binding.cvItem2.visibility = View.VISIBLE
binding.cvItem4.visibility = View.VISIBLE
DataHolder.deviceType.postValue(Constants.DEVICE_TYPE_TEST_RIGHT)
Constants.DEVICE_TYPE_TEST_RIGHT
}
else -> {
Log.d(
TAG,
"Device NOT matched -> product = ${device.productId}, vendor = ${device.vendorId}"
)
val message =
if (device.productId == Constants.DEVICE_PRODUCT_ID) "Device Not Compatible" else "Device Not Connected"
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
DataHolder.usbConnected.value = false
null
}
}
}
else -> {
Log.d(TAG, "Device NOT Connected")
Toast.makeText(this, "Device Not Connected", Toast.LENGTH_SHORT).show()
DataHolder.usbConnected.value = false
null
}
}
deviceType?.let {
DataHolder.usbConnected.value = true
DataHolder.deviceType.postValue(it)
}
}
private fun setupListeners() {
binding.cvItem1.setOnClickListener {
DataHolder.selectedTestType = TestType.SICKLECERT
val i = Intent(applicationContext, KitScanActivity::class.java)
startActivity(i)
finish()
}
binding.cvItem2.setOnClickListener {
DataHolder.selectedTestType = TestType.SICKLEFIND
val i = Intent(applicationContext, KitScanActivity::class.java)
startActivity(i)
finish()
}
DataHolder.usbConnected.observe(this) {
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)
}
}
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.my_menu, menu)
myMenu = menu
checkAndUpdateUsbConnection()
return true
}
private fun requestCoarseLocationPermission() {
val coarseLocationPermission = Manifest.permission.ACCESS_COARSE_LOCATION
val coarseLocationPermissionRequestCode = 101
if (ContextCompat.checkSelfPermission(
this, coarseLocationPermission
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this, arrayOf(coarseLocationPermission), coarseLocationPermissionRequestCode
)
} else {
getLocation()
}
}
private fun requestFineLocationPermission() {
val fineLocationPermission = Manifest.permission.ACCESS_FINE_LOCATION
val fineLocationPermissionRequestCode = 102
if (ContextCompat.checkSelfPermission(
this, fineLocationPermission
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this, arrayOf(fineLocationPermission), fineLocationPermissionRequestCode
)
} else {
getLocation()
}
}
private fun getLocation() {
val coarseLocationPermission = Manifest.permission.ACCESS_COARSE_LOCATION
val fineLocationPermission = Manifest.permission.ACCESS_FINE_LOCATION
if (ActivityCompat.checkSelfPermission(
this, coarseLocationPermission
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
this, fineLocationPermission
) != PackageManager.PERMISSION_GRANTED
) {
// Handle location permission request if needed
Toast.makeText(this, "Please enable location services", Toast.LENGTH_SHORT).show()
requestCoarseLocationPermission()
requestFineLocationPermission()
return
}
// fusedLocationClient.lastLocation.addOnSuccessListener { location: Location? ->
// location?.let {
// DataHolder.selectedTest!!.location =
// UserData.Location(location.latitude, location.longitude)
// DataHolder.location =
// UserData.Location(location.latitude, location.longitude)
// } ?: run {
// requestLocationUpdates()
// }
// }.addOnFailureListener { exception: Exception ->
// exception.printStackTrace()
// }
fusedLocationClient.lastLocation.addOnSuccessListener { location: Location? ->
location?.let {
if (DataHolder.selectedTest != null) {
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)
} ?: run {
requestLocationUpdates()
}
}.addOnFailureListener { exception: Exception ->
// Handle the exception here
exception.printStackTrace()
FirebaseCrashlytics.getInstance().recordException(exception)
// Display an error message to the user using a Snackbar
val errorMessage = "An error occurred: ${exception.message}"
val rootView = findViewById<View>(android.R.id.content)
Snackbar.make(rootView, errorMessage, Snackbar.LENGTH_LONG).show()
}
}
private fun requestLocationUpdates() {
val locationRequest = LocationRequest.create().apply {
interval = 10000 // Interval for receiving location updates (in milliseconds)
fastestInterval = 5000 // Fastest interval for location updates (in milliseconds)
priority = LocationRequest.PRIORITY_HIGH_ACCURACY // Location accuracy priority
}
if (ActivityCompat.checkSelfPermission(
this, Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
this, Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
return
}
fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, null)
}
private fun stopLocationUpdates() {
fusedLocationClient.removeLocationUpdates(locationCallback)
}
override fun onPause() {
super.onPause()
stopLocationUpdates()
}
override fun onRequestPermissionsResult(
requestCode: Int, permissions: Array<String>, grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when (requestCode) {
101 -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Coarse location permission granted
requestFineLocationPermission()
} else {
// Coarse location permission denied
Toast.makeText(this, "Coarse location permission denied", Toast.LENGTH_SHORT)
.show()
}
}
102 -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Fine location permission granted
getLocation()
} else {
// Fine location permission denied
Toast.makeText(this, "Fine location permission denied", Toast.LENGTH_SHORT)
.show()
}
}
}
}
}

View File

@@ -1,4 +1,4 @@
package com.example.hpos.presentation
package com.example.hpostesting.presentation
import androidx.lifecycle.ViewModel

View File

@@ -0,0 +1,161 @@
package com.example.hpostesting.presentation
import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.provider.Settings
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.example.hpostesting.util.MyUtils
import com.google.firebase.firestore.FirebaseFirestoreSettings
import com.google.firebase.firestore.ktx.firestore
import com.google.firebase.ktx.Firebase
import `in`.sminnovations.hpostesting.databinding.ActivitySplashBinding
class SplashActivity : AppCompatActivity() {
private lateinit var binding: ActivitySplashBinding
private val requiredPermissions = listOf(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.CAMERA,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
)
private var allPermissionsGranted = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivitySplashBinding.inflate(layoutInflater)
setContentView(binding.root)
// setupFirestoreCache()
setupStaticConstants()
requestPermissions()
}
private fun setupStaticConstants() {
DataHolder.mobileUniqueId =
Settings.Secure.getString(applicationContext.contentResolver, Settings.Secure.ANDROID_ID)
}
// private fun setupFirestoreCache() {
// val settings = FirebaseFirestoreSettings.Builder()
// .setCacheSizeBytes(FirebaseFirestoreSettings.CACHE_SIZE_UNLIMITED)
// .build()
// Firebase.firestore.firestoreSettings = settings
// }
private fun requestPermissions() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
requestPermissionsAboveAndroidR()
} else {
requestPermissionsBelowAndroidR()
}
}
@RequiresApi(Build.VERSION_CODES.R)
private fun requestPermissionsAboveAndroidR() {
if (Environment.isExternalStorageManager()) {
handlePermissionsResult(true)
} else {
val requestPermissionLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (Environment.isExternalStorageManager()) {
handlePermissionsResult(true)
} else {
Toast.makeText(
this,
"You must grant permission to access all files to use the app",
Toast.LENGTH_SHORT
).show()
finish()
}
}
val intent = Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)
requestPermissionLauncher.launch(intent)
}
}
private fun requestPermissionsBelowAndroidR() {
val permissionsToRequest = requiredPermissions
.filterNot { permission ->
ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED
}
.toTypedArray()
if (permissionsToRequest.isNotEmpty()) {
requestPermissionLauncher.launch(permissionsToRequest)
} else {
checkLocationAndCameraPermissions()
}
}
private fun checkLocationAndCameraPermissions() {
val fineLocationPermission = Manifest.permission.ACCESS_FINE_LOCATION
val coarseLocationPermission = Manifest.permission.ACCESS_COARSE_LOCATION
val cameraPermission = Manifest.permission.CAMERA
val locationPermissionsGranted =
ContextCompat.checkSelfPermission(this, fineLocationPermission) == PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(this, coarseLocationPermission) == PackageManager.PERMISSION_GRANTED
val cameraPermissionGranted = ContextCompat.checkSelfPermission(this, cameraPermission) == PackageManager.PERMISSION_GRANTED
if (locationPermissionsGranted && cameraPermissionGranted) {
handlePermissionsResult(true)
} else {
val permissionsToRequest = mutableListOf<String>()
if (!locationPermissionsGranted) {
permissionsToRequest.add(fineLocationPermission)
permissionsToRequest.add(coarseLocationPermission)
}
if (!cameraPermissionGranted) {
permissionsToRequest.add(cameraPermission)
}
requestPermissionLauncher.launch(permissionsToRequest.toTypedArray())
}
}
private val requestPermissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
val grantedPermissions = permissions.entries.filter { it.value }.map { it.key }
handlePermissionsResult(grantedPermissions.size == requiredPermissions.size)
}
private fun handlePermissionsResult(allGranted: Boolean) {
allPermissionsGranted = allGranted
if (allGranted) {
moveToLandingPage()
} else {
Toast.makeText(this, "All permissions are required to use the app.", Toast.LENGTH_SHORT).show()
finish()
}
}
private fun moveToLandingPage() {
createAppFolder()
val intent = Intent(applicationContext, DashboardActivity::class.java)
startActivity(intent)
finish()
}
private fun createAppFolder() {
val folderPath = MyUtils.createAppFolder(applicationContext)
if (folderPath != null) {
DataHolder.isAppFolderCreated = true
DataHolder.appFolderPath = folderPath
}
}
}

View File

@@ -1,4 +1,4 @@
package com.example.hpos.presentation
package com.example.hpostesting.presentation
interface UsbServiceListener {
fun onUsbRead(data: ByteArray?)

View File

@@ -0,0 +1,62 @@
package com.example.hpostesting.presentation.adapter
import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.navigation.findNavController
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.presentation.testRight.TestRightViewModel
import com.firebase.ui.firestore.FirestoreRecyclerAdapter
import com.firebase.ui.firestore.FirestoreRecyclerOptions
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.UserItemViewBinding
class UserListAdapter(
options: FirestoreRecyclerOptions<UserData>,
private val view: View
) :
FirestoreRecyclerAdapter<UserData, UserListAdapter.OrderItemViewHolder>(options) {
class OrderItemViewHolder(val binding: UserItemViewBinding) :
RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OrderItemViewHolder {
return OrderItemViewHolder(
UserItemViewBinding.inflate(LayoutInflater.from(parent.context), parent, false)
)
}
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: OrderItemViewHolder, position: Int, model: UserData) {
holder.binding.apply {
userName.text = "Name: ${model.name}"
userId.text = "User ID:${model._id}"
Glide.with(view).load(model.userImageURL).into(userImage)
if (model.testStatus!!) {
teststatus.text = "Test concluded"
} else {
teststatus.text = "Test is Pending"
}
userCard.setOnClickListener {
if (model.testStatus != null) {
if (model.testStatus!!) {
Toast.makeText(
view.context,
"Test has been already conducted for this user",
Toast.LENGTH_SHORT
).show()
} else {
DataHolder.selectedTest = model
view.findNavController().navigate(R.id.action_nav_home_to_mainActivity)
}
}
}
}
}
}

View File

@@ -0,0 +1,85 @@
package com.example.hpostesting.presentation.dashboard
import android.os.Bundle
import android.view.Menu
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.drawerlayout.widget.DrawerLayout
import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.navigateUp
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import com.google.android.material.navigation.NavigationView
//import com.google.firebase.appdistribution.FirebaseAppDistribution
//import com.google.firebase.appdistribution.FirebaseAppDistributionException
import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityDashboardBinding
@AndroidEntryPoint
class DashboardActivity : AppCompatActivity() {
private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var binding: ActivityDashboardBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityDashboardBinding.inflate(layoutInflater)
setContentView(binding.root)
setSupportActionBar(binding.appBarDashboard.toolbar)
val drawerLayout: DrawerLayout = binding.drawerLayout
val navView: NavigationView = binding.navView
val navController = findNavController(R.id.nav_host_fragment_content_dashboard)
appBarConfiguration = AppBarConfiguration(
setOf(
R.id.nav_home, R.id.nav_profile, R.id.nav_settings
), drawerLayout
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
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)
return true
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_host_fragment_content_dashboard)
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}
override fun onResume() {
super.onResume()
// Copy and paste this into any part of your app - for example, in your main
// activity's onResume method.
// val firebaseAppDistribution = FirebaseAppDistribution.getInstance()
// firebaseAppDistribution.updateIfNewReleaseAvailable()
// .addOnProgressListener { updateProgress ->
// Toast.makeText(this, "Updating", 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.
// }
// }
// }
// }
}
}

View File

@@ -0,0 +1,42 @@
package com.example.hpostesting.presentation.dashboard
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
//import com.example.hpostesting.presentation.dashboard.ui.gallery.GalleryViewModel
import `in`.sminnovations.hpostesting.databinding.FragmentGalleryBinding
class GalleryFragment : Fragment() {
private var _binding: FragmentGalleryBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
// val galleryViewModel =
// ViewModelProvider(this).get(GalleryViewModel::class.java)
_binding = FragmentGalleryBinding.inflate(inflater, container, false)
val root: View = binding.root
// val textView: TextView = binding.textGallery
// galleryViewModel.text.observe(viewLifecycleOwner) {
//// textView.text = it
// }
return root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View File

@@ -0,0 +1,277 @@
package com.example.hpostesting.presentation.dashboard
import android.app.AlertDialog
import android.content.Context
import android.content.DialogInterface
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.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.presentation.adapter.UserListAdapter
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.example.hpostesting.presentation.testRight.TestRightViewModel
import com.firebase.ui.firestore.FirestoreRecyclerOptions
import com.google.firebase.firestore.Query
import com.google.firebase.firestore.ktx.firestore
import com.google.firebase.ktx.Firebase
import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentHomeBinding
import java.util.Locale
@AndroidEntryPoint
class HomeFragment : Fragment() {
private var _binding: FragmentHomeBinding? = null
private val binding get() = _binding!!
private val viewModel: TestRightViewModel by activityViewModels()
private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels()
private lateinit var rvAdapter: UserListAdapter
private lateinit var sharedPreference: SharedPreferences
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
_binding = FragmentHomeBinding.inflate(inflater, container, false)
// Check if _binding is null
if (_binding == null) {
// Handle the case where binding could not be initialized
// You may want to log an error or return a default view in this case
return super.onCreateView(inflater, container, savedInstanceState)
}
sharedPreference = requireContext().getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE)
DataHolder.selectedTest = null
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.allUserData.observe(viewLifecycleOwner) { userData ->
if (userData.isNotEmpty()) {
}
deleteIncompleteRegistrations(userData)
}
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userData ->
deleteHemoCubeIncompleteRegistrations(userData)
}
viewModel.networkStatusLiveData.observe(viewLifecycleOwner) { isConnected ->
if (isConnected) {
binding.internetAvailableCL.visibility = View.VISIBLE
binding.internetNotAvailableCL.visibility = View.GONE
loadUserData()
setSearch()
checkForLocalDBData()
} else {
binding.internetAvailableCL.visibility = View.GONE
binding.internetNotAvailableCL.visibility = View.VISIBLE
setUserId()
}
}
binding.btnLogout.setOnClickListener {
logoutUser(requireContext())
}
binding.uploadData.setOnClickListener {
showUploadDialog(requireContext())
}
}
private fun setUserId() {
binding.btnSubmit.setOnClickListener {
val userId = binding.userId.text.toString()
if (userId.length >= 18) {
val userData = UserData(_id = userId)
DataHolder.selectedTest = userData
findNavController().navigate(R.id.action_nav_home_to_mainActivity)
} else {
val errorMessage = getString(R.string.user_id_error_message)
Toast.makeText(requireContext(), errorMessage, Toast.LENGTH_SHORT).show()
binding.userId.error = errorMessage
}
}
}
private fun loadUserData() {
// val query = Firebase.firestore.collection("patientData").whereEqualTo("testStatus", false).orderBy("createdAt", Query.Direction.DESCENDING)
val query = Firebase.firestore.collection("patientData").whereEqualTo("testStatus", false)
query.get().addOnSuccessListener {
if (it.documents.isEmpty()) {
binding.pendingTest.visibility = View.VISIBLE
} else {
binding.pendingTest.visibility = View.GONE
}
}
val recyclerViewOptions =
FirestoreRecyclerOptions.Builder<UserData>().setQuery(query, UserData::class.java)
.build()
rvAdapter = UserListAdapter(recyclerViewOptions, binding.root)
binding.rvOrder.adapter = rvAdapter
rvAdapter.startListening()
}
private fun saveUserId(userId: String) {
with(sharedPreference.edit()) {
putString(Constants.USER_ID, userId)
apply()
}
}
private fun logoutUser(context: Context) {
val builder = AlertDialog.Builder(context)
builder.setTitle("Log Out")
builder.setMessage("Do you want to LogOut the Application?")
builder.setPositiveButton("Yes") { dialog, _ ->
saveUserId("")
findNavController().navigate(R.id.action_nav_home_to_loginFragment)
dialog.dismiss()
}
builder.setNegativeButton("No") { dialog, _ ->
dialog.dismiss()
}
val dialog = builder.create()
dialog.show()
}
private fun getData(search: String?, field: String) {
val capitalizedSearch = search?.replaceFirstChar {
if (search.lowercase()
.startsWith(it.lowercase())
) it.titlecase(Locale.getDefault()) else it.toString()
}
val query = Firebase.firestore.collection("patientData").orderBy(field).startAt(search)
.endAt(search + "\uf8ff")
val recyclerViewOptions =
FirestoreRecyclerOptions.Builder<UserData>().setQuery(query, UserData::class.java)
.build()
rvAdapter = UserListAdapter(recyclerViewOptions, binding.root)
binding.rvOrder.adapter = rvAdapter
rvAdapter.startListening()
}
private fun setSearch() {
binding.searchProduct.setOnQueryTextListener(object :
androidx.appcompat.widget.SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean {
return if (!query.isNullOrEmpty()) {
val field = when {
binding.userIdRadioButton.isChecked -> "_id"
binding.abhaIdRadioButton.isChecked -> "abhaId"
binding.aadharIdRadioButton.isChecked -> "aadharId"
else -> null
}
field?.let { getData(query, it) }
false
} else {
loadUserData()
false
}
}
override fun onQueryTextChange(query: String?): Boolean {
return if (!query.isNullOrEmpty()) {
val field = when {
binding.userIdRadioButton.isChecked -> "_id"
binding.abhaIdRadioButton.isChecked -> "abhaId"
binding.aadharIdRadioButton.isChecked -> "aadharId"
else -> null
}
field?.let { getData(query, it) }
false
} else {
loadUserData()
false
}
}
})
}
private fun checkForLocalDBData() {
viewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
val uploadDataVisibility = if (userDataList.isEmpty()) View.GONE else View.VISIBLE
binding.uploadData.visibility = uploadDataVisibility
}
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
val uploadDataVisibility = if (userDataList.isEmpty()) View.GONE else View.VISIBLE
binding.uploadData.visibility = uploadDataVisibility
}
}
private fun showUploadDialog(context: Context) {
val builder = AlertDialog.Builder(context)
builder.setTitle(R.string.upload_db_registration_title)
builder.setMessage(R.string.upload_db_registration_message)
builder.setPositiveButton(R.string.upload) { dialog, _ ->
uploadLocalDBData(dialog)
}
builder.setNegativeButton(R.string.cancel) { dialog, _ ->
dialog.dismiss()
}
val dialog = builder.create()
dialog.show()
}
private fun uploadLocalDBData(dialog: DialogInterface) {
viewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
if (userDataList.isEmpty()) {
dialog.dismiss()
} else {
userDataList.forEach { userData ->
viewModel.bulkUploadResultToDatabase(userData)
viewModel.deleteById(userData._id)
}
dialog.dismiss()
Toast.makeText(
requireContext(),
R.string.upload_success_message,
Toast.LENGTH_SHORT
).show()
}
}
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
if (userDataList.isEmpty()) {
dialog.dismiss()
} else {
userDataList.forEach { userData ->
userData.localFlag = true
hemoCubeViewModel.bulkAddResultTestToDb(userData)
}
dialog.dismiss()
Toast.makeText(
requireContext(),
R.string.upload_success_message,
Toast.LENGTH_SHORT
).show()
}
}
}
private fun deleteIncompleteRegistrations(userDataList: List<UserData>) {
userDataList.forEach { userData ->
if (userData.csvPath.isEmpty()) {
viewModel.deleteById(userData._id)
}
}
}
private fun deleteHemoCubeIncompleteRegistrations(userDataList: List<HemoCubeTestData>) {
userDataList.forEach { userData ->
if (userData.testTime?.isEmpty() == true) {
hemoCubeViewModel.deleteById(userData._id)
}
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View File

@@ -0,0 +1,5 @@
package com.example.hpostesting.presentation.dashboard
interface ItemClickListener {
fun onClick(pos: Int)
}

View File

@@ -0,0 +1,49 @@
package com.example.hpostesting.presentation.dashboard
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import com.example.hpostesting.presentation.dashboard.ui.slideshow.SlideshowViewModel
import `in`.sminnovations.hpostesting.databinding.FragmentSlideshowBinding
class SlideshowFragment : Fragment() {
private var _binding: FragmentSlideshowBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
val slideshowViewModel =
ViewModelProvider(this).get(SlideshowViewModel::class.java)
_binding = FragmentSlideshowBinding.inflate(inflater, container, false)
val root: View = binding.root
val pInfo = requireActivity().packageManager.getPackageInfo(
requireActivity().packageName, 0
)
val version = pInfo.versionName
binding.textSlideshow.text = version
// val textView: TextView = binding.textSlideshow
// slideshowViewModel.text.observe(viewLifecycleOwner) {
// textView.text = it
// }
return root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View File

@@ -0,0 +1,92 @@
package com.example.hpostesting.presentation.dashboard.ui
import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
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("PREFERENCE_NAME", 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 = "Please enter a proper Login ID"
}
if (password.isBlank()) {
binding.password.error = "Please enter a proper password"
}
}
}
}
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(), "Wrong Password", Toast.LENGTH_SHORT).show()
}
}
Toast.makeText(requireContext(), "Wrong UserID", 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

@@ -0,0 +1,13 @@
package com.example.hpostesting.presentation.dashboard.ui.gallery
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class mGalleryViewModel : ViewModel() {
private val _text = MutableLiveData<String>().apply {
value = "This is gallery Fragment"
}
val text: LiveData<String> = _text
}

View File

@@ -0,0 +1,13 @@
package com.example.hpostesting.presentation.dashboard.ui.home
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class HomeViewModel : ViewModel() {
private val _text = MutableLiveData<String>().apply {
value = "This is home Fragment"
}
val text: LiveData<String> = _text
}

View File

@@ -0,0 +1,13 @@
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

@@ -0,0 +1,598 @@
package com.example.hpostesting.presentation.hemocube
import android.content.Context
import android.content.Intent
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.fragment.app.activityViewModels
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.lifecycleScope
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.toHemoCubeTestData
import com.example.hpostesting.presentation.KitScanActivity
import com.example.hpostesting.presentation.UsbServiceListener
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.example.hpostesting.presentation.utils.MyDialogListener
import com.example.hpostesting.presentation.utils.UIUtils
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 `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentHemoCubeReferenceBinding
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.tasks.await
import kotlinx.coroutines.withContext
import kotlin.math.log10
class HemoCubeFragment : Fragment() {
private lateinit var binding: FragmentHemoCubeReferenceBinding
private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels()
private lateinit var sharedPreferences: SharedPreferences
private var isOnline = false
private var currentDeviceData: DeviceData? = null
private var resultData: String = ""
private var isUsingExistingBuffer = false
private var isTestOngoing = false
private var startListening = MutableLiveData<Boolean>(false)
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
): View {
binding = FragmentHemoCubeReferenceBinding.inflate(inflater, container, false)
sharedPreferences =
requireContext().getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initViews()
observeViewModel()
// checkAndStartProcess()
}
private fun initViews() {
binding.btnSubmit.setOnClickListener {
val bloodGroupText = binding.etBloodGroup.text.toString()
if (bloodGroupText.isEmpty()) {
binding.etBloodGroup.error = "Please enter your blood group"
} else {
fetchResult()
}
}
if (isTestOngoing) {
binding.btnKit.visibility = View.GONE
binding.btnKit.isEnabled = false
binding.btnKit.isClickable = false
}
binding.btnSubmit.isEnabled = false
binding.btnSubmit.isClickable = false
binding.btnSamplestart.setOnClickListener {
startSampleProcess()
it.visibility = View.GONE
}
binding.btnPlacebuffer.setOnClickListener {
checkAndStartProcess()
it.visibility = View.GONE
}
binding.btnKit.setOnClickListener {
if (isTestOngoing) {
val title = "WARNING"
val message =
"There is a on going test, do you want to stop it. if Yes please disconnect the device and connect it again, once you reached to kitDetails Screen"
val negativeText = getString(R.string.no)
val positiveText = "Yes"
UIUtils.createAlertDialog(requireContext(),
title,
message,
negativeText,
positiveText,
object : MyDialogListener {
override fun onClickNegativeButton() {
}
override fun onClickPositiveButton() {
resetKitCount()
val intent = Intent(context, KitScanActivity::class.java)
startActivity(intent)
(activity as HemocubeActivity).finish()
}
})
} else {
resetKitCount()
val intent = Intent(context, KitScanActivity::class.java)
startActivity(intent)
(activity as HemocubeActivity).finish()
}
}
}
private suspend fun checkBloodGroup() {
binding.apply {
val bloodGroup = etBloodGroup.text.toString()
if (bloodGroup.isEmpty()) {
etBloodGroup.error = "Please enter your blood group"
} else {
val db: FirebaseFirestore = Firebase.firestore
val userdata = db.collection("patientData")
.whereEqualTo("_id", hemoCubeViewModel.testDetails?._id).get().await()
if (userdata.documents.isNotEmpty()) {
db.collection("patientData").document(userdata.documents[0].id)
.update("bloodGroup", bloodGroup)
withContext(Dispatchers.Main) {
val i = Intent(
requireContext().applicationContext, DashboardActivity::class.java
)
startActivity(i)
(activity as HemocubeActivity).finish()
}
}
}
}
}
private fun observeViewModel() {
hemoCubeViewModel.fireBaseUpload.observe(viewLifecycleOwner) { result ->
if (result == "Success") {
showToast("Test Results Uploaded Successfully")
lifecycleScope.launch {
checkBloodGroup()
}
}
if (result == "Local") {
showToast("Internet not available, test details stored locally")
startActivity(Intent(requireActivity(), DashboardActivity::class.java))
}
binding.progressBar.visibility = View.GONE
}
hemoCubeViewModel.getDeviceData(sharedPreferences.getString(Constants.USER_ID, ""))
hemoCubeViewModel.deviceData.observe(viewLifecycleOwner) {
currentDeviceData = it
}
hemoCubeViewModel.networkStatusLiveData.observe(viewLifecycleOwner) { isNetworkAvailable ->
apply {
DataHolder.hemoCubeTestData?.let {
currentDeviceData?.coefficients?.let { coefficients ->
val coefficient1 = coefficients[0]
val coefficient2 = coefficients[1]
val result = coefficient1 * coefficient2
showToast("coefficients: $coefficient1, $coefficient2")
}
}
isOnline = isNetworkAvailable
}
}
hemoCubeViewModel.messages.observe(viewLifecycleOwner) {
binding.tvSubtitle4.text = it
}
// startListening.observe(viewLifecycleOwner) {
// if (it) {
// lifecycleScope.launch {
// delay(1000)
// if (binding.tvSubtitle4.text.toString().isEmpty()) {
// (activity as HemocubeActivity).reconnectDevice()
// if (isBufferValueAvailable()) {
// showBufferAlertDialog()
// } else {
// listenToHemoCube()
// startBufferProcess()
// }
// }
// }
// }
// }
}
private fun checkAndStartProcess() {
// if (isBufferValueAvailable()) {
// showBufferAlertDialog()
// } else {
listenToHemoCube()
startBufferProcess()
// }
}
private fun isBufferValueAvailable(): Boolean {
return if (sharedPreferences.getString(
Constants.BUFFER_VALUE_1, ""
) != "" && sharedPreferences.getString(Constants.BUFFER_VALUE_2, "") != ""
) {
sharedPreferences.getString(Constants.BUFFER_VALUE_1, "")
?.toDouble()!! > 0.0 && sharedPreferences.getString(Constants.BUFFER_VALUE_2, "")
?.toDouble()!! > 0.0
} else {
false
}
}
private fun showBufferAlertDialog() {
val title = "WARNING"
val message = "Do you want to continue with existing buffer?"
val negativeText = getString(R.string.no)
val positiveText = "Yes"
UIUtils.createAlertDialog(requireContext(),
title,
message,
negativeText,
positiveText,
object : MyDialogListener {
override fun onClickNegativeButton() {
listenToHemoCube()
startBufferProcess()
}
override fun onClickPositiveButton() {
listenToHemoCube()
startSampleProcess()
isUsingExistingBuffer = true
}
})
}
private fun listenToHemoCube() {
if (DataHolder.hemoCubeTestData == null) {
DataHolder.hemoCubeTestData = DataHolder.selectedTest?.toHemoCubeTestData()
}
hemoCubeViewModel.progressBar.postValue(true)
val fullReadOutput = StringBuilder()
startListening.postValue(true)
try {
(activity as HemocubeActivity).mService.listenToHemoCube(object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
data?.let {
val stringData = String(it)
fullReadOutput.append(stringData)
handleUsbData(stringData, fullReadOutput)
}
}
override fun onUsbError(e: Exception?) {
hemoCubeViewModel.progressBar.postValue(false)
}
})
} catch (e: Exception) {
showToast("test is going on")
Firebase.crashlytics.recordException(e)
}
}
private fun handleUsbData(stringData: String, fullReadOutput: StringBuilder) {
if (stringData.contains("#")) {
hemoCubeViewModel.messages.postValue(stringData)
isTestOngoing = true
}
resultData += fullReadOutput.toString()
when {
stringData.contains("ERROR 500") ->
// showError500Dialog()
checkAndStartProcess()
stringData.contains("ERROR 501") -> showError501Dialog()
stringData.contains("#Buffer Completed") ->
// showStartSampleDialog()
activity?.runOnUiThread {
binding.btnSamplestart.visibility = View.VISIBLE
binding.btnSamplestart.isClickable = true
}
stringData.contains("#Sample Completed") -> {
activity?.runOnUiThread {
binding.btnSubmit.isEnabled = true
binding.btnSubmit.isClickable = true
}
}
stringData.contains("RESULT") || resultData.contains("REND") -> {
var validString: String
val results: List<String>
if (stringData.contains("RESULT")) {
validString = isValidResult(stringData)
if (validString.isEmpty()) {
results = resultData.split("\n")
validString = parseResult(results)
}
} else {
results = resultData.split("\n")
validString = parseResult(results)
}
if (validString.isNotEmpty()) {
handleValidResult(validString, resultData)
}
}
}
}
private fun showError() {
activity?.runOnUiThread {
UIUtils.createAlertDialog(requireContext(),
"Device Error",
"Something is wrong with the device, please disconnect and reconnect the device and test the user again",
getString(R.string.noo),
"Yes",
object : MyDialogListener {
override fun onClickNegativeButton() {}
override fun onClickPositiveButton() {
startActivity(Intent(requireActivity(), DashboardActivity::class.java))
}
})
}
}
private fun showError500Dialog() {
UIUtils.createAlertDialog(requireContext(),
"BUFFER ERROR",
"Do you want to continue with existing buffer?",
getString(R.string.noo),
"Yes",
object : MyDialogListener {
override fun onClickNegativeButton() {}
override fun onClickPositiveButton() {
listenToHemoCube()
startBufferProcess()
}
})
}
fun handleBackButtonPress() {
if (isTestOngoing) {
// If the test is ongoing, don't allow the back button action
// You can optionally show a message to the user indicating why the back button is disabled
// For example, show a Toast or Snackbar.
showToast("Test is ongoing. Cannot go back.")
} else {
// If the test is not ongoing, you can trigger the back action of the hosting activity
activity?.onBackPressed()
}
}
private fun showError501Dialog() {
UIUtils.createAlertDialog(requireContext(),
"SAMPLE ERROR",
"Do you want to continue with Sample?",
getString(R.string.noo),
"Yes",
object : MyDialogListener {
override fun onClickNegativeButton() {}
override fun onClickPositiveButton() {
listenToHemoCube()
startSampleProcess()
}
})
}
private fun showStartSampleDialog() {
activity?.runOnUiThread {
UIUtils.createAlertDialog(requireContext(),
"Start Sample",
"Do you want to start sample reading?",
getString(R.string.no),
"Yes",
object : MyDialogListener {
override fun onClickNegativeButton() {}
override fun onClickPositiveButton() {
listenToHemoCube()
startSampleProcess()
}
})
}
}
private fun handleValidResult(validString: String, fullReadOutput: String) {
try {
val result = validString.split(" ")
if (result.size == 8) {
val deviceSerialNo = result[2]
val led1BufferForDevice = if (isUsingExistingBuffer) {
sharedPreferences.getString(Constants.BUFFER_VALUE_1, "")?.toDoubleOrNull()
} else {
result[3].toDoubleOrNull()
}
val led2BufferForDevice = if (isUsingExistingBuffer) {
sharedPreferences.getString(Constants.BUFFER_VALUE_2, "")?.toDoubleOrNull()
} else {
result[4].toDoubleOrNull()
}
val pInfo = requireActivity().packageManager.getPackageInfo(
requireActivity().packageName, 0
)
val version = pInfo.versionName
val led1Sample = result[5].toDoubleOrNull()
val led2Sample = result[6].toDoubleOrNull()
val led1Average = log10(led1BufferForDevice?.div(led1Sample!!) ?: 0.0)
val led2Average = log10(led2BufferForDevice?.div(led2Sample!!) ?: 0.0)
val deviceRatio = led1Average / led2Average
// if (led1BufferForDevice!! > 20000 && led1BufferForDevice < 24000 && led2BufferForDevice!! > 20000 && led2BufferForDevice < 24000) {
// if (led1Sample!! < led1BufferForDevice && led1Sample < 24000 && led2Sample!! < led2BufferForDevice && led2Sample < 24000) {
// if (deviceRatio < 0.08) {
// if (deviceRatio > 1.07) {
//
// }
// }
// }
// }
DataHolder.hemoCubeTestData?.apply {
deviceId = deviceSerialNo
led1Buffer = led1BufferForDevice
led2Buffer = led2BufferForDevice
appVersion = version
this.led1Sample = led1Sample
this.led2Sample = led2Sample
this.led1Average = led1Average
this.led2Average = led2Average
this.deviceRatio = deviceRatio
this.calculatedRatio = calculateRatio(deviceRatio)
this.classificationResult = findResult(calculatedRatio)
hemoCubeViewModel.messages.postValue(this.classificationResult)
this.resultData = fullReadOutput
if (!isBufferValueAvailable()) {
with(sharedPreferences.edit()) {
putString(Constants.BUFFER_VALUE_1, led1Buffer.toString())
putString(Constants.BUFFER_VALUE_2, led2Buffer.toString())
apply()
}
}
activity?.runOnUiThread {
binding.progressBar.visibility = View.VISIBLE
}
hemoCubeViewModel.uploadHemoCubeResultToDatabase(
isOnline, true, sharedPreferences.getString(Constants.KIT_NUMBER, "")
)
}
}
} catch (e: Exception) {
Toast.makeText(
requireContext(),
"Error while processing device data",
Toast.LENGTH_SHORT
).show()
Firebase.crashlytics.recordException(e)
}
}
private fun findResult(calculatedRatio: Double?): String {
try {
if (calculatedRatio != null) {
if (calculatedRatio < 0.085)
return "Inconclusive. Very low Absorbance - Repeat test with Higher Blood Volume"
if (calculatedRatio in 0.085..0.155)
return "Normal"
if (calculatedRatio in 0.155..0.175)
return "Negative Borderline. Repeat Test"
if (calculatedRatio in 0.175..0.22)
return "Sickle Cell Trait"
if (calculatedRatio in 0.22..0.25)
return "Positive for Sickle Cell. HPLC for Confirmation"
if (calculatedRatio in 0.25..0.35)
return "Sickle Cell Disease"
if (calculatedRatio > 0.35)
return "Inconclusive. Repeat with test with lower volume of blood"
} else {
return "NULL"
}
} catch (e: Exception) {
showToast("error while performing classification")
Firebase.crashlytics.recordException(e)
return "ERROR"
}
return "NULL"
}
private fun showToast(message: String) {
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
}
private fun startBufferProcess() {
hemoCubeViewModel.progressBar.postValue(true)
(activity as HemocubeActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.startBuffer,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {}
override fun onUsbError(e: Exception?) {
hemoCubeViewModel.progressBar.postValue(false)
}
})
}
private fun startSampleProcess() {
hemoCubeViewModel.progressBar.postValue(true)
(activity as HemocubeActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.startSample,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {}
override fun onUsbError(e: Exception?) {
hemoCubeViewModel.progressBar.postValue(false)
}
})
}
private fun fetchResult() {
hemoCubeViewModel.progressBar.postValue(true)
(activity as HemocubeActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.getSample,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {}
override fun onUsbError(e: Exception?) {
hemoCubeViewModel.progressBar.postValue(false)
}
})
}
private fun calculateRatio(ratio: Double): Double {
val coefficient1 = currentDeviceData?.coefficients?.get(0) ?: 0.0
val coefficient2 = currentDeviceData?.coefficients?.get(1) ?: 0.0
return coefficient1 * ratio + coefficient2
}
private fun parseResult(frames: List<String>): String {
val lines = mutableListOf<String>()
for (frame in frames.reversed()) {
if (frame.contains("REND") || frame.contains("RESULT")) lines += frame
if (frame.contains("RESULT")) {
break
}
}
val line = lines.reversed().joinToString("").trim()
if (line.contains("RESULT") && line.split(" ").size == 8) {
return line
}
return ""
}
private fun isValidResult(line: String): String {
return if (line.contains("RESULT") && line.split(" ").size == 8) {
line
} else {
""
}
}
private fun resetKitCount() {
with(sharedPreferences.edit()) {
putString(Constants.KIT_NUMBER, "")
putInt(Constants.KIT_COUNT, 0)
apply()
}
}
}

View File

@@ -0,0 +1,147 @@
package com.example.hpostesting.presentation.hemocube
import android.content.Context
import android.content.SharedPreferences
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.NetworkStatusLiveData
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.dao.HemoCubeDao
import com.example.hpostesting.data.model.Response
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.toHemoCubeTestData
import com.example.hpostesting.data.repository.DatabaseRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import javax.inject.Inject
@HiltViewModel
class HemoCubeViewModel @Inject constructor(
private val hemoCubeDao: HemoCubeDao,
private val repository: DatabaseRepository,
context: Context,
) : ViewModel() {
var isServiceConnected = false
val progressBar = MutableLiveData(false)
val testDetails = DataHolder.selectedTest?.toHemoCubeTestData()
val messages = MutableLiveData<String>()
private val sharedPreference: SharedPreferences =
context.getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE)
// Get the device ID of the device you want to retrieve data for (e.g., the first device in the list)
private val _networkStatusLiveData = NetworkStatusLiveData(context)
val allUserData = hemoCubeDao.getAll()
val deviceData = MutableLiveData<DeviceData?>()
val networkStatusLiveData: LiveData<Boolean>
get() = _networkStatusLiveData
val fireBaseUpload = MutableLiveData<String>()
fun uploadHemoCubeResultToDatabase(isOnline: Boolean, testStatus: Boolean, kitSerial: String?) =
viewModelScope.launch {
if (kitSerial != null) {
testDetails?.kitSerial = kitSerial
}
testDetails?.testStatus = testStatus
try {
if (isOnline) {
parseData()
addResultTestToDb()
} else {
parseData()
testDetails?.testTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
hemoCubeDao.insertAll(testDetails!!)
fireBaseUpload.postValue("Local")
}
} catch (e: Exception) {
Log.e("Testdb", "Upload failed: ${e.message}")
}
}
fun getDeviceData(deviceId: String?) = viewModelScope.launch {
deviceData.postValue(deviceId?.let { repository.getDeviceDataById(it) })
}
private fun parseData() {
testDetails?.deviceRatio = DataHolder.hemocubeResult
testDetails?.resultData = DataHolder.hemoCubeTestData?.resultData.toString()
testDetails?.location = DataHolder.location
testDetails?.testTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
testDetails?.appVersion = DataHolder.hemoCubeTestData?.appVersion
testDetails?.deviceId = DataHolder.hemoCubeTestData?.deviceId
testDetails?.deviceSerialNumber =
sharedPreference.getString(Constants.USER_ID, "").toString()
testDetails?.kitSerial = sharedPreference.getString(Constants.KIT_NUMBER, "").toString()
testDetails?.led1Buffer = DataHolder.hemoCubeTestData?.led1Buffer
testDetails?.led2Buffer = DataHolder.hemoCubeTestData?.led2Buffer
testDetails?.led1Sample = DataHolder.hemoCubeTestData?.led1Sample
testDetails?.led2Sample = DataHolder.hemoCubeTestData?.led2Sample
testDetails?.led1Average = DataHolder.hemoCubeTestData?.led1Average
testDetails?.led2Average = DataHolder.hemoCubeTestData?.led2Average
testDetails?.deviceRatio = DataHolder.hemoCubeTestData?.deviceRatio
testDetails?.calculatedRatio = DataHolder.hemoCubeTestData?.calculatedRatio
testDetails?.classificationResult = DataHolder.hemoCubeTestData?.classificationResult!!
}
private fun addResultTestToDb() {
viewModelScope.launch {
try {
testDetails!!.reportUploadTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
when (val response = repository.addTestToDatabase(testDetails)) {
is Response.Success -> {
val kitCount = sharedPreference.getInt(Constants.KIT_COUNT, 0)
with(sharedPreference.edit()) {
putInt(Constants.KIT_COUNT, kitCount.plus(1))
apply()
}
Log.i("Testdb", "Data uploaded to Firestore successfully")
fireBaseUpload.postValue("Success")
}
is Response.Error -> {
Log.e("Testdb", "Error uploading data to Firestore: $response")
fireBaseUpload.postValue("Error")
}
}
} catch (e: Exception) {
Log.e("Testdb", "Exception during data upload: ${e.message}")
fireBaseUpload.postValue("Error")
}
}
}
fun bulkAddResultTestToDb(userData: HemoCubeTestData) {
viewModelScope.launch {
userData.reportUploadTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
when (repository.addTestToDatabase(userData)) {
is Response.Success -> {
fireBaseUpload.postValue("Success")
deleteById(userData._id)
}
else -> {}
}
}
}
fun deleteById(userId: String) = viewModelScope.launch {
hemoCubeDao.deleteById(id = userId)
}
}

View File

@@ -0,0 +1,188 @@
package com.example.hpostesting.presentation.hemocube
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.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.presentation.testRight.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.ActivityHemocubeBinding
@AndroidEntryPoint
open class HemocubeActivity : AppCompatActivity() {
private lateinit var binding: ActivityHemocubeBinding
private val viewModel by viewModels<HemoCubeViewModel>()
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 onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityHemocubeBinding.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()
}
}
}
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.HOMOCUBE_USB_PERMISSION), PendingIntent.FLAG_MUTABLE
)
} else {
mPendingIntent = PendingIntent.getBroadcast(
this,
0,
Intent(Constants.HOMOCUBE_USB_PERMISSION),
PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
)
}
val filter = IntentFilter(Constants.HOMOCUBE_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)
}
open fun reconnectDevice() {
mService.disconnect()
unbindService(connection)
viewModel.isServiceConnected = false
connectUsb(true)
}
private fun moveToNext() {
if (supportFragmentManager.isDestroyed) return
supportFragmentManager.beginTransaction().replace(binding.fghemocube.id, HemoCubeFragment())
.commit()
}
override fun onBackPressed() {
val fragment = supportFragmentManager.findFragmentById(R.id.fghemocube)
if (fragment is HemoCubeFragment) {
fragment.handleBackButtonPress()
} else {
super.onBackPressed()
}
}
fun onErrorReported(msg: String) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
if (!isFinishing) onBackPressed()
}
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
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,32 +1,38 @@
package com.example.hpos.presentation.testRight
package com.example.hpostesting.presentation.testRight
import android.app.PendingIntent
import android.content.*
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.*
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 androidx.lifecycle.ViewModelProvider
import com.example.hpos.R
import com.example.hpos.data.DataHolder
import com.example.hpos.data.constant.Constants
import com.example.hpos.databinding.ActivityTestRightBinding
import com.example.hpos.util.MyViewModelFactory
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.Constants
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.ActivityTestRightBinding
@AndroidEntryPoint
class TestRightActivity : AppCompatActivity() {
private lateinit var binding: ActivityTestRightBinding
private lateinit var viewModel: TestRightViewModel
private val viewModel by viewModels<TestRightViewModel>()
private var myMenu: Menu? = null
private lateinit var mDriver: UsbSerialDriver
@@ -58,6 +64,8 @@ class TestRightActivity : AppCompatActivity() {
val binder = service as UsbService.UsbServiceBinder
mService = binder.getService()
viewModel.isServiceConnected = true
// Todo: Uncomment this
mConnection.let { mService.connect(mDriver, mConnection!!) }
moveToNext()
}
@@ -71,10 +79,6 @@ class TestRightActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
binding = ActivityTestRightBinding.inflate(layoutInflater)
setContentView(binding.root)
viewModel = ViewModelProvider(
this,
MyViewModelFactory(this.applicationContext)
)[TestRightViewModel::class.java]
setSupportActionBar(binding.myToolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
@@ -99,11 +103,6 @@ class TestRightActivity : AppCompatActivity() {
}
}
// private fun testing() {
// supportFragmentManager.beginTransaction()
// .replace(binding.flMain.id, TestRightExpSample()).commit()
// }
private fun connectUsb(permissionGranted: Boolean) {
Log.d(TAG, "connectUsb() called, permission variable = $permissionGranted")
val manager = getSystemService(Context.USB_SERVICE) as UsbManager
@@ -114,11 +113,7 @@ class TestRightActivity : AppCompatActivity() {
} else {
mDriver = availableDrivers[0]
if (mDriver.device.productId != Constants.DEVICE_PRODUCT_ID || mDriver.device.vendorId != Constants.DEVICE_VENDOR_ID){
Toast.makeText(this, "Device Connected is not supported", Toast.LENGTH_SHORT).show()
onBackPressed()
return
}
viewModel.testDetails?.deviceId = mDriver.device.serialNumber.toString()
DataHolder.deviceSerialNumber = mDriver.device.serialNumber.toString()
mConnection = manager.openDevice(mDriver.device)
@@ -130,12 +125,7 @@ class TestRightActivity : AppCompatActivity() {
}
}
/*
* Request user permission. The response will be received in the BroadcastReceiver
*/
private fun requestUserPermission(manager: UsbManager, device: UsbDevice) {
// Log.d(TAG, "requestUserPermissions() called -> vendor id = ${device.vendorId} & product id = ${device.productId}")
val mPendingIntent: PendingIntent
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
mPendingIntent = PendingIntent.getBroadcast(
@@ -149,7 +139,7 @@ class TestRightActivity : AppCompatActivity() {
this,
0,
Intent(Constants.ACTION_USB_PERMISSION),
PendingIntent.FLAG_ONE_SHOT
PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
)
}
@@ -184,11 +174,6 @@ class TestRightActivity : AppCompatActivity() {
fun onErrorReported(msg: String) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
// Snackbar.make(binding.clParent, msg, Snackbar.LENGTH_LONG)
// .setAction("CLOSE") { Toast.makeText(this, "Will soon", Toast.LENGTH_SHORT).show() }
// .setActionTextColor(resources.getColor(R.color.white))
// .show()
if (!isFinishing)
onBackPressed()
}
@@ -198,16 +183,6 @@ class TestRightActivity : AppCompatActivity() {
myMenu = menu
return true
}
// override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
// R.id.action_usb -> {
//// Toast.makeText(this, "USB Connected", Toast.LENGTH_SHORT).show()
//// myMenu?.get(0)?.icon = ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_off_24)
// true
// }
// else -> {super.onOptionsItemSelected(item)}
// }
override fun onDestroy() {
super.onDestroy()
if (viewModel.isServiceConnected) {
@@ -216,10 +191,4 @@ class TestRightActivity : AppCompatActivity() {
viewModel.isServiceConnected = false
}
}
// fun View.setAllEnabled(enabled: Boolean) {
// isEnabled = enabled
// if (this is ViewGroup) children.forEach { child -> child.setAllEnabled(enabled) }
// }
}

View File

@@ -1,4 +1,4 @@
package com.example.hpos.presentation.testRight
package com.example.hpostesting.presentation.testRight
import android.os.Bundle
import android.os.Handler
@@ -8,32 +8,28 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.view.children
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import com.example.hpos.R
import com.example.hpos.data.DataHolder
import com.example.hpos.data.constant.Constants
import com.example.hpos.data.constant.TestRightCommands
import com.example.hpos.data.model.ErrorMessage
import com.example.hpos.databinding.FragmentTestRightExpReferenceBinding
import com.example.hpos.presentation.UsbServiceListener
import com.example.hpos.presentation.utils.MyDialogListener
import com.example.hpos.presentation.utils.UIUtils
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.TestRightCommands
import com.example.hpostesting.data.model.ErrorMessage
import com.example.hpostesting.presentation.UsbServiceListener
import com.example.hpostesting.presentation.utils.MyDialogListener
import com.example.hpostesting.presentation.utils.UIUtils
import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentTestRightExpReferenceBinding
@AndroidEntryPoint
class TestRightExpReference : Fragment() {
private lateinit var binding: FragmentTestRightExpReferenceBinding
private val viewModel: TestRightViewModel by activityViewModels()
private val TAG = "TestRightExpReference"
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
// Inflate the layout for this fragment
binding = FragmentTestRightExpReferenceBinding.inflate(inflater, container, false)
return binding.root
}
@@ -41,34 +37,26 @@ class TestRightExpReference : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupListeners()
// if (DataHolder.isReferenceTaken)
// moveToSamplePage()
//
// DataHolder.sampleReadCounter <= Constants.MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE
if (DataHolder.deviceConstant == null) {
viewModel.progressBar.postValue(true)
Handler(Looper.getMainLooper()).postDelayed(
{ sendCmdToFetchDeviceConstant() },
Constants.DELAY_BETWEEN_COMMANDS
{ sendCmdToFetchDeviceConstant() }, Constants.DELAY_BETWEEN_COMMANDS
)
}
}
private fun setupListeners() {
binding.btnSetReference.setOnClickListener {
UIUtils.createAlertDialog(
requireContext(),
UIUtils.createAlertDialog(requireContext(),
getString(R.string.have_you_placed),
getString(R.string.please_place),
getString(R.string.no),
getString(R.string.yes),
object : MyDialogListener {
override fun onClickNegativeButton() {
// Todo: Only for testing
// viewModel.progressBar.postValue(true)
}
override fun onClickPositiveButton() {
startTakingReference()
}
@@ -76,16 +64,15 @@ class TestRightExpReference : Fragment() {
}
viewModel.errorTriggered.observe(viewLifecycleOwner) {
if (it != null){
if (it != null) {
UIUtils.onShowErrorToast(requireContext(), it.message)
if (it.code == Constants.ERROR_CRITICAL){
if (it.code == Constants.ERROR_CRITICAL) {
activity?.onBackPressed()
}
}
}
viewModel.progressBar.observe(viewLifecycleOwner) {
// Log.d(TAG, "SURYA OBSERVER Activated outcome = $it")
if (it) {
binding.progressBar.visibility = View.VISIBLE
binding.clParent.alpha = 0.5f
@@ -96,7 +83,6 @@ class TestRightExpReference : Fragment() {
binding.btnSetReference.isEnabled = true
}
}
}
/**
@@ -107,19 +93,17 @@ class TestRightExpReference : Fragment() {
* 4. command print
*/
private fun startTakingReference() {
// requireActivity().runOnUiThread {
sendCmdToSetLed()
// }
}
// private fun sendCmdToFetchDeviceConstant(recursive: Boolean) {
private fun sendCmdToFetchDeviceConstant() {
Log.d(TAG, "sendCmdToFetchDeviceConstant() called")
viewModel.progressBar.postValue(true)
val fullReadOutput = StringBuilder()
(activity as TestRightActivity).mService.eventDrivenWrite(TestRightCommands.read,
(activity as TestRightActivity).mService.eventDrivenWrite(
TestRightCommands.read,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
data?.let {
@@ -129,8 +113,7 @@ class TestRightExpReference : Fragment() {
if (stringData.contains("OK", true)) {
Log.d(
TAG,
"onUsbRead() called in sendCmdToFetchDeviceConstant() found OK"
TAG, "onUsbRead() called in sendCmdToFetchDeviceConstant() found OK"
)
viewModel.mapDeviceConstants(fullReadOutput.toString())
viewModel.progressBar.postValue(false)
@@ -138,7 +121,11 @@ class TestRightExpReference : Fragment() {
Log.d(TAG, "results = FINE")
viewModel.progressBar.postValue(false)
viewModel.errorTriggered.postValue(ErrorMessage("Please Try Again!!", Constants.ERROR_CRITICAL))
viewModel.errorTriggered.postValue(
ErrorMessage(
"Please Try Again!!", Constants.ERROR_CRITICAL
)
)
}
}
@@ -146,7 +133,11 @@ class TestRightExpReference : Fragment() {
override fun onUsbError(e: Exception?) {
Log.e(TAG, "onUsbIoError() called in sendCmdToFetchDeviceConstant() -> $e")
viewModel.errorTriggered.postValue(ErrorMessage("Please Try Again this step", Constants.ERROR_NORMAL))
viewModel.errorTriggered.postValue(
ErrorMessage(
"Please Try Again this step", Constants.ERROR_NORMAL
)
)
viewModel.progressBar.postValue(false)
}
@@ -171,8 +162,7 @@ class TestRightExpReference : Fragment() {
Runnable {
viewModel.progressBar.postValue(false)
sendCmdToAutoset()
},
Constants.DELAY_BETWEEN_COMMANDS
}, Constants.DELAY_BETWEEN_COMMANDS
)
}
}
@@ -203,8 +193,7 @@ class TestRightExpReference : Fragment() {
Runnable {
viewModel.progressBar.postValue(false)
sendCmdToRun()
},
Constants.DELAY_BETWEEN_COMMANDS
}, Constants.DELAY_BETWEEN_COMMANDS
)
}
@@ -237,12 +226,10 @@ class TestRightExpReference : Fragment() {
Runnable {
viewModel.progressBar.postValue(false)
sendCmdToFetchLightIntensities()
},
Constants.DELAY_BETWEEN_COMMANDS
}, Constants.DELAY_BETWEEN_COMMANDS
)
}
}
// }
}
override fun onUsbError(e: Exception?) {
@@ -256,24 +243,23 @@ class TestRightExpReference : Fragment() {
Log.d(TAG, "sendCmdToFetchLightIntensities() called")
viewModel.progressBar.postValue(true)
val fullReadOutput = StringBuilder()
DataHolder.testExp = true
(activity as TestRightActivity).mService.eventDrivenWrite(TestRightCommands.printAll,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
data?.let {
val stringData = String(it)
fullReadOutput.append(stringData)
// Log.d(TAG, stringData)
// if (stringData.contains("OK", true)) {
// if (fullReadOutput.substring(Math.max(fullReadOutput.length - 15, 0)).contains("OK", true)) {
if (stringData.trim().isNotEmpty() && fullReadOutput.substring(Math.max(fullReadOutput.length - 15, 0)).contains("OK [0]", true)) {
if (stringData.trim().isNotEmpty() && fullReadOutput.substring(
Math.max(
fullReadOutput.length - 15, 0
)
).contains("OK [0]", true)
) {
Log.d(TAG, "onUsbRead() called in sendCmdToFetchLightIntensities()")
// Log.d(TAG, fullReadOutput.toString())
viewModel.mapIntensityValues(fullReadOutput.toString(), true)
// viewModel.saveLogTest(requireContext().applicationContext, true, fullReadOutput.toString())
DataHolder.isReferenceTaken = true
Handler(Looper.getMainLooper()).postDelayed(
@@ -288,7 +274,11 @@ class TestRightExpReference : Fragment() {
override fun onUsbError(e: Exception?) {
Log.e(TAG, "onUsbIoError() called in sendCmdToFetchLightIntensities() -> $e")
viewModel.errorTriggered.postValue(ErrorMessage("Please Try Again this step", Constants.ERROR_NORMAL))
viewModel.errorTriggered.postValue(
ErrorMessage(
"Please Try Again this step", Constants.ERROR_NORMAL
)
)
viewModel.progressBar.postValue(false)
}

View File

@@ -1,5 +1,6 @@
package com.example.hpos.presentation.testRight
package com.example.hpostesting.presentation.testRight
import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.os.Looper
@@ -9,20 +10,20 @@ import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import com.example.hpos.R
import com.example.hpos.data.DataHolder
import com.example.hpos.data.PreferenceUtility
import com.example.hpos.data.constant.Constants
import com.example.hpos.data.constant.TestRightCommands
import com.example.hpos.data.model.ErrorMessage
import com.example.hpos.data.model.PatientData
import com.example.hpos.data.model.TestRightResultType
import com.example.hpos.data.model.TestType
import com.example.hpos.databinding.FragmentTestRightExpSampleBinding
import com.example.hpos.presentation.UsbServiceListener
import com.example.hpos.presentation.utils.MyDialogListener
import com.example.hpos.presentation.utils.UIUtils
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.TestRightCommands
import com.example.hpostesting.data.model.ErrorMessage
import com.example.hpostesting.data.model.test.TestType
import com.example.hpostesting.presentation.MainActivity
import com.example.hpostesting.presentation.UsbServiceListener
import com.example.hpostesting.presentation.utils.MyDialogListener
import com.example.hpostesting.presentation.utils.UIUtils
import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentTestRightExpSampleBinding
@AndroidEntryPoint
class TestRightExpSample : Fragment() {
private lateinit var binding: FragmentTestRightExpSampleBinding
@@ -34,16 +35,7 @@ class TestRightExpSample : Fragment() {
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
// Inflate the layout for this fragment
binding = FragmentTestRightExpSampleBinding.inflate(inflater, container, false)
// if (DataHolder.sampleReadCounter > Constants.MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE) {
// binding.btnUpdateReference.enable()
// binding.clInstructions.setAllEnabled(false)
// } else {
// binding.btnUpdateReference.disable()
// binding.clInstructions.setAllEnabled(false)
// }
return binding.root
}
@@ -74,58 +66,45 @@ class TestRightExpSample : Fragment() {
}
binding.btnSubmit.setOnClickListener {
val details = checkAndReturnPatientDetails()
if (details != null) {
viewModel.patientDetails = details
UIUtils.createAlertDialog(
requireContext(),
getString(R.string.have_you_placed_sample),
getString(R.string.please_place_sample),
getString(R.string.no),
getString(R.string.yes_and_run),
object : MyDialogListener {
override fun onClickNegativeButton() {}
override fun onClickPositiveButton() {
startAcquiring()
}
})
}
UIUtils.createAlertDialog(
requireContext(),
"WARNING",
"Please check if you have placed the sample of this person ${viewModel.testDetails?._id}",
getString(R.string.no),
"Yes",
object : MyDialogListener {
override fun onClickNegativeButton() {}
override fun onClickPositiveButton() {
UIUtils.createAlertDialog(
requireContext(),
getString(R.string.have_you_placed_sample),
getString(R.string.please_place_sample),
getString(R.string.no),
getString(R.string.yes_and_run),
object : MyDialogListener {
override fun onClickNegativeButton() {}
override fun onClickPositiveButton() {
startAcquiring()
}
})
}
})
// }
}
binding.tvSkip.setOnClickListener {
DataHolder.sampleReadCounter = 0
DataHolder.isReferenceTaken = false
val i = Intent(requireContext(), MainActivity::class.java)
startActivity(i)
}
binding.etNameBlock.setOnClickListener { binding.etName.isErrorEnabled = false }
binding.etAgeBlock.setOnClickListener { binding.etAge.isErrorEnabled = false }
binding.etGenderBlock.setOnClickListener { binding.ddGender.isErrorEnabled = false }
}
private fun checkAndReturnPatientDetails(): PatientData? {
val name = binding.etName.editText?.text?.trim()
if (name.isNullOrEmpty()) {
binding.etName.error = getString(R.string.name_error)
return null
}
val age = binding.etAge.editText?.text?.trim()
if (age.isNullOrEmpty()) {
binding.etAge.error = getString(R.string.age_error)
return null
} else if (age.toString().toInt() < 0 || age.toString().toInt() > 199) {
binding.etAge.error = getString(R.string.age_error_out_of_bound)
return null
}
val gender = binding.ddGender.editText?.text
if (gender.isNullOrEmpty()) {
binding.ddGender.error = getString(R.string.gender_error)
return null
}
return PatientData(name.toString(), age.toString().toInt(), gender.toString(), TestRightResultType.UNDEFINED)
}
/**
* Executing the commands sequentially each after successfully executing one.
* 1. command run
* 2. command print
*/
private fun startAcquiring() {
// binding.progressBar.visibility = View.VISIBLE
sendCmdToRun()
}
@@ -141,9 +120,6 @@ class TestRightExpSample : Fragment() {
val stringData = String(it)
fullReadOutput.append(stringData)
Log.d(TAG, stringData)
// if (stringData.contains("OK", true)) {
// if (stringData.contains("OK", true) || fullReadOutput.substring(Math.max(fullReadOutput.length - 15, 0)).contains("OK", true)) {
// if (fullReadOutput.substring(Math.max(fullReadOutput.length - 15, 0)).contains("OK", true)) {
if (fullReadOutput.substring(Math.max(fullReadOutput.length - 15, 0)).contains("OK [0]", true)) {
Log.d(TAG, "onUsbRead() called in sendCmdToRun()")
Handler(Looper.getMainLooper()).postDelayed(
@@ -171,6 +147,8 @@ class TestRightExpSample : Fragment() {
Log.d(TAG, "sendCmdToFetchLightIntensities() called")
viewModel.progressBar.postValue(true)
val fullReadOutput = StringBuilder()
DataHolder.testExp = false
(activity as TestRightActivity).mService.eventDrivenWrite(TestRightCommands.printAll,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
@@ -178,17 +156,10 @@ class TestRightExpSample : Fragment() {
val stringData = String(it)
fullReadOutput.append(stringData)
Log.d(TAG, stringData)
// if (stringData.contains("OK", true)) {
// if (stringData.contains("OK", true) || stringData.contains("O", true) || stringData.contains("K", true)) {
// if (stringData.contains("OK", true) || fullReadOutput.substring(Math.max(fullReadOutput.length - 15, 0)).contains("OK", true)) {
// if (fullReadOutput.substring(Math.max(fullReadOutput.length - 15, 0)).contains("OK", true)) {
if (stringData.trim().isNotEmpty() && fullReadOutput.substring(Math.max(fullReadOutput.length - 15, 0)).contains("OK [0]", true)) {
Log.d(TAG, "onUsbRead() called in sendCmdToFetchLightIntensities()")
viewModel.mapIntensityValues(fullReadOutput.toString(), false)
// viewModel.saveLogTest(requireContext().applicationContext, false, fullReadOutput.toString())
// showResultsAfterAcquiring()
Handler(Looper.getMainLooper()).postDelayed(
{
checkIfToRunAgain()
@@ -214,15 +185,11 @@ class TestRightExpSample : Fragment() {
viewModel.mapWavelengthToAbsorbance()
// Todo: Save CSV + Test CSV
if (DataHolder.selectedTestType == TestType.SICKLECERT) {
viewModel.calculateResults()
} else {
viewModel.calculateResultsForSickleFind()
}
// Todo: Save Log
saveDataLocally()
if (viewModel.numberOfSampleRun < Constants.NO_OF_TIMES_TO_RUN_SAMPLE) {
@@ -239,49 +206,14 @@ class TestRightExpSample : Fragment() {
}
private fun showResultsAfterAcquiring() {
// viewModel.mapWavelengthToAbsorbance()
// viewModel.calculateResults()
viewModel.progressBar.postValue(false)
// binding.progressBar.visibility = View.GONE
parentFragmentManager.beginTransaction().replace(R.id.fl_main, TestRightResults())
.commit()
}
private fun saveDataLocally() {
val patientName = viewModel.patientDetails.name
// if (patientName.length > 5){
// patientName = patientName.substring(0, 5)
// }
val id = PreferenceUtility.generateId(requireContext())
val prefixCsv: String = if (DataHolder.selectedTestType == TestType.SICKLECERT)
"HPOSSC_${DataHolder.deviceSerialNumber}_${patientName}_"
else
"HPOSSF_${DataHolder.deviceSerialNumber}_${patientName}_"
// val prefixCsv = "HPOSSC_${DataHolder.deviceSerialNumber}_${patientName}_"
val fileExtensionCsv = ".csv"
val fileNameCsv = prefixCsv + id + fileExtensionCsv
saveCsv(fileNameCsv)
val prefixTxt = "log_${DataHolder.deviceSerialNumber}_${patientName}_"
val fileExtensionTxt = ".txt"
val fileNameTxt = prefixTxt + id + fileExtensionTxt
saveLog(fileNameTxt)
}
private fun saveCsv(fileName: String) {
Log.d(TAG, "saveCsv() called")
viewModel.saveCsv(requireContext().applicationContext, fileName)
viewModel.saveCsvForTesting(requireContext().applicationContext, "detailed_$fileName")
}
private fun saveLog(fileName: String) {
Log.d(TAG, "saveLog() called")
viewModel.saveLogWithPatient(requireContext().applicationContext, fileName)
viewModel.saveCsv(requireContext().applicationContext, viewModel.getCSVFileName())
viewModel.saveLogWithPatient(requireContext().applicationContext, viewModel.getLogFileName())
}
}

View File

@@ -0,0 +1,166 @@
package com.example.hpostesting.presentation.testRight
import android.content.Context
import android.content.Intent
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.fragment.app.activityViewModels
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.model.test.TestRightResultType
import com.example.hpostesting.data.model.test.TestType
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.example.hpostesting.util.MyUtils.calculateAgeFromYOB
import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.firestore.ktx.firestore
import com.google.firebase.ktx.Firebase
import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentTestRightResultsBinding
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.tasks.await
import kotlinx.coroutines.withContext
@AndroidEntryPoint
class TestRightResults : Fragment() {
private lateinit var binding: FragmentTestRightResultsBinding
private val viewModel: TestRightViewModel by activityViewModels()
private lateinit var sharedPreference: SharedPreferences
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
binding = FragmentTestRightResultsBinding.inflate(inflater, container, false)
sharedPreference =
requireContext().getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupListeners()
updateResults()
viewModel.fireBaseUpload.observe(viewLifecycleOwner) {
if (it == "Success") {
Toast.makeText(
requireContext(), "Test Results Upload Successfully", Toast.LENGTH_SHORT
).show()
}
binding.progressBar.visibility = View.GONE
}
}
private fun setupListeners() {
binding.ivHome.setOnClickListener {
CoroutineScope(Dispatchers.IO).launch {
checkBloodGroup()
}
}
binding.ivNext.setOnClickListener {
val i = Intent(requireContext().applicationContext, DashboardActivity::class.java)
startActivity(i)
// moveToSamplePage()
}
}
private suspend fun checkBloodGroup() {
binding.apply {
val bloodGroup = etBloodGroup.text.toString()
if (bloodGroup.isEmpty()) {
etBloodGroup.error = "Please enter your blood group"
} else {
val db: FirebaseFirestore = Firebase.firestore
val userdata =
db.collection("patientData").whereEqualTo("_id", viewModel.testDetails?._id)
.get().await()
if (userdata.documents.isNotEmpty()) {
db.collection("patientData").document(userdata.documents[0].id)
.update("bloodGroup", bloodGroup)
withContext(Dispatchers.Main) {
val i = Intent(
requireContext().applicationContext,
DashboardActivity::class.java
)
startActivity(i)
}
}
}
}
}
private fun updateResults() {
if (viewModel.testDetails?.name == "" && viewModel.testDetails?.birthYear == "") {
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()
)
}
binding.tvId.text = getString(R.string.patient_id_in_tv, viewModel.testDetails?._id)
if (DataHolder.selectedTestType == TestType.SICKLECERT) {
binding.resultNormal.visibility = View.VISIBLE
} else {
when (viewModel.testDetails?.result) {
TestRightResultType.SICKLECELLDISEASE -> {
binding.resultDisease.visibility = View.VISIBLE
binding.resultDisease.text = "Positive"
}
TestRightResultType.NORMAL -> {
binding.resultNormal.visibility = View.VISIBLE
binding.resultNormal.text = "Negative"
}
else -> {
Toast.makeText(
requireContext().applicationContext, "Please Test Again", Toast.LENGTH_LONG
).show()
moveToSamplePage()
}
}
}
viewModel.networkStatusLiveData.observe(viewLifecycleOwner) { isNetworkAvailable ->
val deviceStaticId = sharedPreference.getString(Constants.USER_ID, "")
if (isNetworkAvailable) {
viewModel.uploadResultToDatabase(requireContext(), true, deviceStaticId!!)
binding.progressBar.visibility = View.VISIBLE
} else {
viewModel.uploadResultToDatabase(requireContext(), false, deviceStaticId!!)
Toast.makeText(
requireContext(),
"Internet not available, Test Data added to Local DB",
Toast.LENGTH_SHORT
).show()
}
}
}
private fun moveToSamplePage() {
if (DataHolder.sampleReadCounter > Constants.MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE) {
DataHolder.sampleReadCounter = 0
DataHolder.isReferenceTaken = false
parentFragmentManager.beginTransaction().replace(R.id.fl_main, TestRightExpReference())
.commit()
} else {
parentFragmentManager.beginTransaction().replace(R.id.fl_main, TestRightExpSample())
.commit()
}
}
}

View File

@@ -1,38 +1,69 @@
package com.example.hpos.presentation.testRight
package com.example.hpostesting.presentation.testRight
import android.content.Context
import android.net.Uri
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.example.hpos.data.DataHolder
import com.example.hpos.data.constant.Constants
import com.example.hpos.data.model.*
import com.example.hpos.domain.*
import com.example.hpos.util.MyUtils
import androidx.lifecycle.viewModelScope
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.NetworkStatusLiveData
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.dao.UserDao
import com.example.hpostesting.data.model.CalculationVariableForTest
import com.example.hpostesting.data.model.ErrorMessage
import com.example.hpostesting.data.model.Response
import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.data.model.test.TestRightCalculationData
import com.example.hpostesting.data.model.test.TestRightDeviceConstants
import com.example.hpostesting.data.model.test.TestType
import com.example.hpostesting.data.repository.DatabaseRepository
import com.example.hpostesting.domain.ResultCalculationWithMaxImpl
import com.example.hpostesting.domain.SaveRawData
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.google.firebase.storage.FirebaseStorage
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import kotlinx.coroutines.tasks.await
import java.io.File
import java.text.SimpleDateFormat
import java.util.*
import java.util.Collections.sort
import kotlin.collections.ArrayList
import java.util.Calendar
import java.util.Date
import java.util.Locale
import javax.inject.Inject
import kotlin.math.log10
import kotlin.math.pow
class TestRightViewModel : ViewModel() {
private val TAG = "TestRightViewModel"
@HiltViewModel
class TestRightViewModel @Inject constructor(
private val saveRawData: SaveRawData,
private val saveRawDataTest: SaveRawDataTest,
private val repository: DatabaseRepository,
private val userDao: UserDao,
context: Context
) : ViewModel() {
var isServiceConnected = false
val progressBar = MutableLiveData(false)
// val errorTriggered = MutableLiveData<String>("")
val errorTriggered = MutableLiveData<ErrorMessage>()
var numberOfSampleRun = 0
lateinit var patientDetails: PatientData
val fireBaseUpload = MutableLiveData<String>()
val testDetails = DataHolder.selectedTest
private val _networkStatusLiveData = NetworkStatusLiveData(context)
val networkStatusLiveData: LiveData<Boolean>
get() = _networkStatusLiveData
val allUserData = userDao.getAll()
// var deviceConstant: TestRightDeviceConstants? = null
private lateinit var calculationData: TestRightCalculationData
/* (For exp sample) Contains pixel no. -> Intensity of light falling on that pixel */
val intensitySampleArray = ArrayList<Double>()
val wavelengthToAbsorbance = ArrayList<ArrayList<Double>>()
@@ -40,8 +71,6 @@ class TestRightViewModel : ViewModel() {
val calculationVariableList = ArrayList<CalculationVariableForTest>()
fun mapDeviceConstants(string: String) {
// Log.d(TAG, "mapDeviceConstants() called")
// Log.d(TAG, "mapDeviceConstants() value -> $string")
if (string.isNotEmpty()) {
val listOfStrings = string.split(",")
if (listOfStrings.size >= 4) {
@@ -58,8 +87,7 @@ class TestRightViewModel : ViewModel() {
// "Error 201: In processing the data from device"
errorTriggered.postValue(
ErrorMessage(
"Error 201: In processing the data from device",
Constants.ERROR_NORMAL
"Error 201: In processing the data from device", Constants.ERROR_NORMAL
)
)
}
@@ -68,8 +96,7 @@ class TestRightViewModel : ViewModel() {
// "Error 202: Unable to fetch data from device."
errorTriggered.postValue(
ErrorMessage(
"Error 202: Unable to fetch data from device.",
Constants.ERROR_NORMAL
"Error 202: Unable to fetch data from device.", Constants.ERROR_NORMAL
)
)
}
@@ -82,13 +109,9 @@ class TestRightViewModel : ViewModel() {
if (DataHolder.deviceConstant != null) {
for (x in 1..Constants.TEST_RIGHT_TOTAL_PIXEL) {
// val index = x - 1
val wavelength: Double =
(DataHolder.deviceConstant!!.a.toDouble() * (x.toDouble()
.pow((3).toDouble()))) +
(DataHolder.deviceConstant!!.b.toDouble() * (x.toDouble()
.pow((2).toDouble()))) +
(DataHolder.deviceConstant!!.c.toDouble() * x) +
(DataHolder.deviceConstant!!.d.toDouble())
val wavelength: Double = (DataHolder.deviceConstant!!.a.toDouble() * (x.toDouble()
.pow((3).toDouble()))) + (DataHolder.deviceConstant!!.b.toDouble() * (x.toDouble()
.pow((2).toDouble()))) + (DataHolder.deviceConstant!!.c.toDouble() * x) + (DataHolder.deviceConstant!!.d.toDouble())
DataHolder.wavelengthToPixelArray.add(wavelength)
}
@@ -97,8 +120,7 @@ class TestRightViewModel : ViewModel() {
// "Error 203: Unable to fetch data from device."
errorTriggered.postValue(
ErrorMessage(
"Error 203: Unable to fetch data from device.",
Constants.ERROR_NORMAL
"Error 203: Unable to fetch data from device.", Constants.ERROR_NORMAL
)
)
@@ -111,26 +133,20 @@ class TestRightViewModel : ViewModel() {
if (isReference) DataHolder.intensityReferenceArray.clear()
else intensitySampleArray.clear()
Log.d("SURYAKUMAR", fullString)
val listOfString = fullString.split("\n")
for (line in listOfString) {
if ("Buf" in line) {
/* Removing trailing spaces and "Buf" from the string then taking lhs & rhs of ':' */
val numbers = line.trim()
.substring(3).split(":")
if ("Buf" in line) {/* Removing trailing spaces and "Buf" from the string then taking lhs & rhs of ':' */
val numbers = line.trim().substring(3).split(":")
if (numbers.size >= 2) {
if (isReference)
DataHolder.intensityReferenceArray.add(numbers[1].toDouble())
else
intensitySampleArray.add(numbers[1].toDouble())
if (isReference) DataHolder.intensityReferenceArray.add(numbers[1].toDouble())
else intensitySampleArray.add(numbers[1].toDouble())
} else {
// "Error 204: Unable to fetch data from device."
errorTriggered.postValue(
ErrorMessage(
"Error 204: Unable to fetch data from device.",
Constants.ERROR_NORMAL
"Error 204: Unable to fetch data from device.", Constants.ERROR_NORMAL
)
)
@@ -240,7 +256,11 @@ class TestRightViewModel : ViewModel() {
val resultCalculation: TestRightResultCalculation = ResultCalculationWithMaxImpl()
calculationData = resultCalculation.getResults(wavelengthToAbsorbance)
// patientDetails.results = resultCalculation.getResults(wavelengthToAbsorbance)
patientDetails.results = calculationData.result
// patientDetails.results = calculationData.result
testDetails?.result = calculationData.result
testDetails?.resultRatio = calculationData.ratioValue
testDetails?.testStatus = true
}
@@ -249,25 +269,28 @@ class TestRightViewModel : ViewModel() {
val resultCalculation: TestRightResultCalculation =
SickleFindResultCaluculationWithMaxImpl()
calculationData = resultCalculation.getResults(wavelengthToAbsorbance)
patientDetails.results = calculationData.result
testDetails?.result = calculationData.result
testDetails?.testStatus = true
}
fun saveCsv(appContext: Context, filename: String) {
// try {
var folderPath: String? = DataHolder.appFolderPath
if (DataHolder.isAppFolderCreated) {
SaveRawData().saveCsv(folderPath!!, filename, wavelengthToAbsorbance)
var folderPath: String? = DataHolder.appFolderPath
if (DataHolder.isAppFolderCreated) {
// SaveRawData().saveCsv(folderPath!!, filename, wavelengthToAbsorbance)
saveRawData.saveCsv(folderPath!!, filename, wavelengthToAbsorbance)
} else {
folderPath = MyUtils.createAppFolder(appContext)
if (folderPath != null) {
DataHolder.isAppFolderCreated = true
DataHolder.appFolderPath = folderPath
// SaveRawData().saveCsv(folderPath, filename, wavelengthToAbsorbance)
saveRawData.saveCsv(folderPath, filename, wavelengthToAbsorbance)
} else {
folderPath = MyUtils.createAppFolder(appContext)
if (folderPath != null) {
DataHolder.isAppFolderCreated = true
DataHolder.appFolderPath = folderPath
SaveRawData().saveCsv(folderPath, filename, wavelengthToAbsorbance)
} else {
// errorTriggered.postValue("Unable to save CSV, Please try again")
}
}
}
// } catch (e: java.io.FileNotFoundException) {
// errorTriggered.postValue(
// ErrorMessage(
@@ -280,19 +303,22 @@ class TestRightViewModel : ViewModel() {
fun saveCsvForTesting(appContext: Context, filename: String) {
// try {
var folderPath: String? = DataHolder.appFolderPath
if (DataHolder.isAppFolderCreated) {
SaveRawDataTest().saveCsv(folderPath!!, filename, calculationVariableList)
var folderPath: String? = DataHolder.appFolderPath
if (DataHolder.isAppFolderCreated) {
// SaveRawDataTest().saveCsv(folderPath!!, filename, calculationVariableList)
saveRawDataTest.saveCsv(folderPath!!, filename, calculationVariableList)
} else {
folderPath = MyUtils.createAppFolder(appContext)
if (folderPath != null) {
DataHolder.isAppFolderCreated = true
DataHolder.appFolderPath = folderPath
// SaveRawDataTest().saveCsv(folderPath, filename, calculationVariableList)
saveRawDataTest.saveCsv(folderPath, filename, calculationVariableList)
} else {
folderPath = MyUtils.createAppFolder(appContext)
if (folderPath != null) {
DataHolder.isAppFolderCreated = true
DataHolder.appFolderPath = folderPath
SaveRawDataTest().saveCsv(folderPath, filename, calculationVariableList)
} else {
// errorTriggered.postValue("Unable to save CSV, Please try again")
}
}
}
// } catch (e: java.io.FileNotFoundException) {
// errorTriggered.postValue(
// ErrorMessage(
@@ -305,20 +331,22 @@ class TestRightViewModel : ViewModel() {
fun saveLog(appContext: Context, fileName: String) {
// try {
var folderPath: String? = DataHolder.appFolderPath
var folderPath: String? = DataHolder.appFolderPath
if (DataHolder.isAppFolderCreated) {
SaveRawData().saveLog(folderPath!!, fileName, calculationData)
if (DataHolder.isAppFolderCreated) {
// SaveRawData().saveLog(folderPath!!, fileName, calculationData)
saveRawData.saveLog(folderPath!!, fileName, calculationData)
} else {
folderPath = MyUtils.createAppFolder(appContext)
if (folderPath != null) {
DataHolder.isAppFolderCreated = true
DataHolder.appFolderPath = folderPath
// SaveRawData().saveLog(folderPath, fileName, calculationData)
saveRawData.saveLog(folderPath, fileName, calculationData)
} else {
folderPath = MyUtils.createAppFolder(appContext)
if (folderPath != null) {
DataHolder.isAppFolderCreated = true
DataHolder.appFolderPath = folderPath
SaveRawData().saveLog(folderPath, fileName, calculationData)
} else {
// errorTriggered.postValue("Unable to save Log, Please try again")
}
}
}
// } catch (e: java.io.FileNotFoundException) {
// errorTriggered.postValue(
// ErrorMessage(
@@ -331,30 +359,26 @@ class TestRightViewModel : ViewModel() {
fun saveLogWithPatient(appContext: Context, fileName: String) {
// try {
var folderPath: String? = DataHolder.appFolderPath
var folderPath: String? = DataHolder.appFolderPath
if (DataHolder.isAppFolderCreated) {
SaveRawData().saveLogWithPatientData(
folderPath!!,
fileName,
calculationData,
patientDetails
if (DataHolder.isAppFolderCreated) {
// SaveRawData().saveLogWithPatientData(
saveRawData.saveLogWithPatientData(
folderPath!!, fileName, calculationData, testDetails
)
} else {
folderPath = MyUtils.createAppFolder(appContext)
if (folderPath != null) {
DataHolder.isAppFolderCreated = true
DataHolder.appFolderPath = folderPath
// SaveRawData().saveLogWithPatientData(
saveRawData.saveLogWithPatientData(
folderPath, fileName, calculationData, testDetails
)
} else {
folderPath = MyUtils.createAppFolder(appContext)
if (folderPath != null) {
DataHolder.isAppFolderCreated = true
DataHolder.appFolderPath = folderPath
SaveRawData().saveLogWithPatientData(
folderPath,
fileName,
calculationData,
patientDetails
)
} else {
// errorTriggered.postValue("Unable to save Log, Please try again")
}
}
}
// } catch (e: java.io.FileNotFoundException) {
// errorTriggered.postValue(
// ErrorMessage(
@@ -376,17 +400,136 @@ class TestRightViewModel : ViewModel() {
var folderPath: String? = DataHolder.appFolderPath
if (DataHolder.isAppFolderCreated) {
SaveRawDataTest().saveLog(folderPath!!, fileName, isReference, fullString)
saveRawDataTest.saveLog(folderPath!!, fileName, isReference, fullString)
// SaveRawDataTest().saveLog(folderPath!!, fileName, isReference, fullString)
} else {
folderPath = MyUtils.createAppFolder(appContext)
if (folderPath != null) {
DataHolder.isAppFolderCreated = true
DataHolder.appFolderPath = folderPath
SaveRawDataTest().saveLog(folderPath, fileName, isReference, fullString)
saveRawDataTest.saveLog(folderPath, fileName, isReference, fullString)
// SaveRawDataTest().saveLog(folderPath, fileName, isReference, fullString)
} else {
// errorTriggered.postValue("Unable to save Log, Please try again")
}
}
}
fun getCSVFileName(): String {
val prefixCsv: String =
if (DataHolder.selectedTestType == TestType.SICKLECERT) "HPOSSC_${testDetails?._id}"
else "HPOSSF_${testDetails?._id}"
val fileExtensionCsv = ".csv"
return prefixCsv + fileExtensionCsv
}
fun getLogFileName(): String {
val prefixTxt = "log_${testDetails?._id}"
val fileExtensionTxt = ".txt"
return prefixTxt + fileExtensionTxt
}
private fun addResultTestToDb() {
testDetails?.testTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
viewModelScope.launch {
testDetails!!.reportUploadTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
when (repository.addTestToDatabase(testDetails)) {
is Response.Success -> {
fireBaseUpload.postValue("Success")
}
else -> {}
}
}
}
fun uploadResultToDatabase(context: Context, isOnline: Boolean,deviceSerialNumber: String) = viewModelScope.launch {
val csvFilePath = MyUtils.getAppFolderPath(context) + getCSVFileName()
val logTxtFilePath = MyUtils.getAppFolderPath(context) + getLogFileName()
testDetails?.csvPath = csvFilePath
testDetails?.reportPath = logTxtFilePath
testDetails?.deviceSerialNumber = deviceSerialNumber
if (isOnline) {
val storageRef = FirebaseStorage.getInstance().reference
val storageTestDetailsRef = storageRef.child("${testDetails?._id}/")
try {
val csvFileUri = Uri.fromFile(File(csvFilePath))
val logTxtFileUri = Uri.fromFile(File(logTxtFilePath))
val csvUploadTask =
storageTestDetailsRef.child(csvFileUri.lastPathSegment!!).putFile(csvFileUri)
.await()
val logUploadTask = storageTestDetailsRef.child(logTxtFileUri.lastPathSegment!!)
.putFile(logTxtFileUri).await()
val csvUri = csvUploadTask.storage.downloadUrl.await().toString()
val logUri = logUploadTask.storage.downloadUrl.await().toString()
val serialNumber = Constants.STATICID.firstOrNull { it == deviceSerialNumber }
testDetails?.csvPath = csvUri
testDetails?.reportPath = logUri
addResultTestToDb()
} catch (exception: Exception) {
// Handle the exception appropriately (e.g., log the error, display an error message)
}
} else {
testDetails?.testTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
userDao.insertAll(testDetails!!)
}
}
fun bulkUploadResultToDatabase(userData: UserData) = viewModelScope.launch {
val storageRef = FirebaseStorage.getInstance().reference
val storageTestDetailsRef = storageRef.child("${testDetails?._id}/")
try {
val csvFileUri = Uri.fromFile(File(userData.csvPath))
val logTxtFileUri = Uri.fromFile(File(userData.reportPath))
val csvUploadTask =
storageTestDetailsRef.child(csvFileUri.lastPathSegment!!).putFile(csvFileUri)
.await()
val logUploadTask =
storageTestDetailsRef.child(logTxtFileUri.lastPathSegment!!).putFile(logTxtFileUri)
.await()
val csvUri = csvUploadTask.storage.downloadUrl.await().toString()
val logUri = logUploadTask.storage.downloadUrl.await().toString()
userData.csvPath = csvUri
userData.reportPath = logUri
bulkAddResultTestToDb(userData)
} catch (exception: Exception) {
// Handle the exception appropriately (e.g., log the error, display an error message)
}
}
private fun bulkAddResultTestToDb(userData: UserData) {
viewModelScope.launch {
userData.reportUploadTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
when (repository.addTestToDatabase(userData)) {
is Response.Success -> {
fireBaseUpload.postValue("Success")
}
else -> {}
}
}
}
fun deleteById(userId: String) = viewModelScope.launch {
userDao.deleteById(id = userId)
}
}

View File

@@ -0,0 +1,87 @@
package com.example.hpostesting.presentation.testRight
import android.app.Service
import android.content.Intent
import android.hardware.usb.UsbDeviceConnection
import android.os.Binder
import android.os.IBinder
import android.util.Log
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.constant.TestRightCommands
import com.example.hpostesting.presentation.UsbServiceListener
import com.hoho.android.usbserial.driver.UsbSerialDriver
import com.hoho.android.usbserial.driver.UsbSerialPort
import com.hoho.android.usbserial.util.SerialInputOutputManager
import java.io.IOException
class UsbService : Service() {
private val binder = UsbServiceBinder()
private lateinit var mPort: UsbSerialPort
private var isUsbConnected = false
private val TAG = "UsbService"
inner class UsbServiceBinder : Binder() {
fun getService(): UsbService = this@UsbService
}
override fun onBind(intent: Intent): IBinder {
return binder
}
var listener: UsbServiceListener? = null
var bus: UsbServiceListener? = null
fun connect(driver: UsbSerialDriver, connection: UsbDeviceConnection) {
mPort = driver.ports[0] // Most devices have just one port (port 0)
mPort.open(connection)
mPort.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE)
isUsbConnected = true
Log.d(TAG, "My Usb Connected ${mPort.driver}")
val usbIoManager = SerialInputOutputManager(mPort,
object : SerialInputOutputManager.Listener{
override fun onNewData(data: ByteArray?) {
listener?.onUsbRead(data)
}
override fun onRunError(e: Exception?) {
Log.e(TAG, "onRunError() called inside eventDrivenWrite()")
listener?.onUsbError(e)
}
})
usbIoManager.start();
}
fun disconnect() {
if(isUsbConnected){
mPort.close()
isUsbConnected = false;
Log.d(TAG, "My Usb disconnected:: ${mPort.driver}")
}
}
fun eventDrivenWrite(command: TestRightCommands, listener: UsbServiceListener) {
this.listener = listener
try {
mPort.write(command.command.toByteArray(), Constants.WRITE_TIMEOUT_MILLIS)
} catch (e: IOException) {
listener.onUsbError(e)
}
}
fun listenToHemoCube(listener: UsbServiceListener) {
this.listener = listener
try {
} catch (e: IOException) {
listener.onUsbError(e)
}
}
fun sendAndListenToHemoCube(command: HemoCubeCommands, listener: UsbServiceListener) {
try {
this.bus = listener
mPort.write(command.command.toByteArray(), Constants.WRITE_TIMEOUT_MILLIS)
} catch (e: IOException) {
listener.onUsbError(e)
}
}
}

View File

@@ -1,4 +1,4 @@
package com.example.hpos.presentation.utils
package com.example.hpostesting.presentation.utils
interface MyDialogListener {
fun onClickNegativeButton()

View File

@@ -1,4 +1,4 @@
package com.example.hpos.presentation.utils
package com.example.hpostesting.presentation.utils
import android.content.Context
import android.widget.Toast

View File

@@ -0,0 +1,11 @@
package com.example.hpostesting
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
fun main(){
val dateFormat = SimpleDateFormat("MM:HHddMMyyyy", Locale.getDefault())
val currentDate = Date()
print(dateFormat.format(currentDate))
}

View File

@@ -0,0 +1,89 @@
package com.example.hpostesting.util
import android.content.Context
import android.os.Environment
import com.example.hpostesting.data.model.patient.PatientDetails
import `in`.sminnovations.hpostesting.R
import java.io.File
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
object MyUtils {
fun createAppFolder(context: Context) : String? {
val folderPath = getAppFolderPath(context)
val file = File(folderPath)
return if (!file.exists()) {
if (!file.mkdirs()) {
null
} else {
folderPath
}
} else {
folderPath
}
}
fun getAppFolderPath(context: Context) : String {
return Environment.getExternalStorageDirectory().absolutePath + "/" + context.resources.getString(R.string.app_name) + "/"
}
fun isInternetConnected(): Boolean {
val runtime = Runtime.getRuntime()
try {
val ipProcess = runtime.exec("/system/bin/ping -c 1 8.8.8.8")
val exitValue = ipProcess.waitFor()
return exitValue == 0
} catch (e: IOException) {
e.printStackTrace()
} catch (e: InterruptedException) {
e.printStackTrace()
}
return false
}
fun generateTestIdForPatient(patientId: String): String {
val dateFormat = SimpleDateFormat("HHmm_ddMMyyyy", Locale.getDefault())
return patientId + "_" + dateFormat.format(Date())
}
fun String.mapToGender(): PatientDetails.Gender {
return if (this.lowercase() == "m"|| this.lowercase() == "male") {
PatientDetails.Gender.MALE
} else if (this.lowercase() == "f"|| this.lowercase() == "female") {
PatientDetails.Gender.FEMALE
} else {
PatientDetails.Gender.OTHER
}
}
fun String.mapToCategory(): PatientDetails.Category {
return when (this.lowercase()){
"gen" -> PatientDetails.Category.GENERAL
"general" -> PatientDetails.Category.GENERAL
"obc" -> PatientDetails.Category.OBC
"sc" -> PatientDetails.Category.SC
"st" -> PatientDetails.Category.ST
else -> {PatientDetails.Category.GENERAL}
}
}
fun String.fetchYOBFromDOB(): Int {
val startIndex = if (this.length >= 4) this.length - 4 else 0
return this.substring(startIndex).toInt()
}
fun Int.calculateAgeFromYOB(): Int {
val currentY = SimpleDateFormat("yyyy").format(Date()).toInt()
return (currentY - this)
}
fun String.mapYesNoStringToBool(): Boolean {
return this.lowercase() == "yes"
}
}

View File

@@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:tint="#FFFFFF" android:viewportHeight="24"
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
</vector>

View File

@@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:tint="#005DB3" android:viewportHeight="24"
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z"/>
</vector>

View File

@@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:tint="#EF0A0A" android:viewportHeight="24"
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M17,7l-1.41,1.41L18.17,11H8v2h10.17l-2.58,2.58L17,17l5,-5zM4,5h8V3H4c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h8v-2H4V5z"/>
</vector>

View File

@@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:tint="#005DB3" android:viewportHeight="24"
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
</vector>

View File

@@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:tint="#000000" android:viewportHeight="24"
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M9.5,6.5v3h-3v-3H9.5M11,5H5v6h6V5L11,5zM9.5,14.5v3h-3v-3H9.5M11,13H5v6h6V13L11,13zM17.5,6.5v3h-3v-3H17.5M19,5h-6v6h6V5L19,5zM13,13h1.5v1.5H13V13zM14.5,14.5H16V16h-1.5V14.5zM16,13h1.5v1.5H16V13zM13,16h1.5v1.5H13V16zM14.5,17.5H16V19h-1.5V17.5zM16,16h1.5v1.5H16V16zM17.5,14.5H19V16h-1.5V14.5zM17.5,17.5H19V19h-1.5V17.5zM22,7h-2V4h-3V2h5V7zM22,22v-5h-2v3h-3v2H22zM2,22h5v-2H4v-3H2V22zM2,2v5h2V4h3V2H2z"/>
</vector>

View File

@@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:tint="#005DB3" android:viewportHeight="24"
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.8,11.69 4.8,12s0.02,0.64 0.07,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z"/>
</vector>

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