Compare commits

...

288 Commits

Author SHA1 Message Date
Mariya
1d34ce2a52 Added Offline Incubation feature
Added testStatus field
2023-12-07 16:42:32 +05:30
Mariya
ec3d0b8628 Added Offline Incubation feature 2023-12-07 16:31:33 +05:30
Mariya
7464bfef6d deleted unwanted code 2023-12-07 16:00:34 +05:30
Mariya
85986c87b1 offline incubation code is added 2023-12-07 15:36:28 +05:30
Mariya
dadddfd558 Issues fixed 2023-12-06 17:25:45 +05:30
Mariya
0903647500 Issues fixed 2023-12-06 16:08:52 +05:30
Mariya
326c66fea7 Issues fixed 2023-12-06 11:32:38 +05:30
Mariya
045eaee578 Issues fixed 2023-12-05 20:43:03 +05:30
Mariya
302960922e Issues fixed 2023-12-05 20:41:47 +05:30
Mariya
ea4fb6e4d2 Issues fixed 2023-12-05 20:16:20 +05:30
Mariya
80fa523ec9 String Issues fixed 2023-12-05 17:57:32 +05:30
Mariya
7a2e5ead51 String Issues fixed 2023-12-05 17:53:46 +05:30
Mariya
f109c52288 app Build added 2023-12-05 17:50:46 +05:30
Mariya
4a248f7c49 deleted unwanted codes 2023-12-01 12:23:44 +05:30
Mariya
2123b2a7b4 Merge remote-tracking branch 'origin/preprod' into preprod 2023-12-01 10:54:05 +05:30
Pritimay Sarkar
704223e403 Merge branch 'LanguageTranslation' into 'preprod'
Merge multi-lingual changes to preprod

See merge request sminnovations/hpos!15
2023-11-30 08:52:52 +00:00
Pritimay Sarkar
6097a05701 Merge branch 'preprod' into 'LanguageTranslation'
# Conflicts:
#   app/src/main/java/com/example/hpostesting/data/dao/MyDataBase.kt
#   app/src/main/java/com/example/hpostesting/presentation/KitScanActivity.kt
#   app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt
#   app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt
2023-11-30 08:52:01 +00:00
Mariya
290bf77950 Merge remote-tracking branch 'origin/preprod' into preprod 2023-11-30 13:38:13 +05:30
Mariya
ad595a6299 pending translation strings of hemocube fragment added 2023-11-30 13:21:02 +05:30
Mariya
22bf66fc94 kannada and hindi version of strings added 2023-11-29 15:51:38 +05:30
Mariya
1dd66bcd6e kannada and hindi version of strings added 2023-11-28 15:39:57 +05:30
Pritimay Sarkar
a02ba3e9ea release 2.1.39 with updated coeffs for dev2 2023-11-28 12:05:06 +05:30
Pritimay Sarkar
457c652161 add low Hb check and log errors 2023-11-27 10:23:44 +05:30
Mariya
5bebd88dfd Merge remote-tracking branch 'origin/preprod' into preprod 2023-11-24 11:36:20 +05:30
Mariya
657b9aea65 removed Unwanted code 2023-11-22 17:10:40 +05:30
Mariya
90590ee535 removed Unwanted code 2023-11-22 17:10:06 +05:30
Mariya
3d39c43c22 Digital Counselling Card , All is finished 2023-11-22 16:31:46 +05:30
Pritimay Sarkar
6fa5e760c1 Merge branch 'Bug_Entering_a_new_kit_number_through_the_home_screen_triggers_an_invalid_message' into preprod 2023-11-22 10:37:54 +05:30
Pritimay Sarkar
8940352e05 prior testing related changes for clinical validation 2023-11-22 10:36:59 +05:30
Mariya
47fabf036f Merge branch 'DigitalCard' into DigitalPreprodCombine
# Conflicts:
#	app/src/main/java/com/example/hpostesting/data/dao/MyDataBase.kt
#	app/src/main/java/com/example/hpostesting/data/model/patient/UserData.kt
2023-11-21 14:19:36 +05:30
Mariya
d7a41e8f31 updated preprod changes added 2023-11-21 14:17:48 +05:30
Mariya
f26f3098bb updated preprod changes added 2023-11-21 14:15:55 +05:30
Mariya
4d454ea031 Merge remote-tracking branch 'origin/preprod' into preprod 2023-11-21 14:08:37 +05:30
Mariya
e92a80caec digital card fragment coding is finished, testing is pending 2023-11-21 13:40:42 +05:30
Kaif
28bd9cbd43 Kit number invalid error fixed 2023-11-20 14:14:19 +05:30
Pritimay Sarkar
fc3e4d506a Merge branch 'unit-tests' into 'preprod'
add setup for two unit tests

See merge request sminnovations/hpos!14
2023-11-18 01:14:42 +00:00
Pritimay Sarkar
60fbd70f2d correct strings msg 2023-11-17 18:20:33 +05:30
Pritimay Sarkar
7f2cafeef4 add two test 2023-11-17 14:48:53 +05:30
Mariya
b37d3f1fce digital card fragment coding is finished, testing is pending 2023-11-17 12:31:27 +05:30
Pritimay Sarkar
1d22fa54c9 add constants 2023-11-17 11:09:57 +05:30
Pritimay Sarkar
3b3bc1adf4 Merge branch 'variable-buffer-thresholds' into 'preprod'
add variable thresholds parameters across devices

See merge request sminnovations/hpos!13
2023-11-16 10:03:07 +00:00
Pritimay Sarkar
a1206dbe0d Merge branch 'preprod' into 'variable-buffer-thresholds'
# Conflicts:
#   app/src/main/java/com/example/hpostesting/data/constant/Constants.kt
2023-11-16 10:00:22 +00:00
Pritimay Sarkar
6e9850c492 add variable thresholds paramters across devices 2023-11-16 15:26:53 +05:30
Pritimay Sarkar
5982ce822f Merge branch 'battery-instrumentation' into 'preprod'
Battery instrumentation

See merge request sminnovations/hpos!12
2023-11-16 06:50:50 +00:00
Pritimay Sarkar
5c32a17871 add battery instrumentation and fix classification msg 2023-11-16 12:19:29 +05:30
Pritimay Sarkar
16528bd165 fix device constant error 2023-11-16 12:18:01 +05:30
Pritimay Sarkar
f86caf0448 move if conditions outside apply 2023-11-16 07:04:51 +05:30
Pritimay Sarkar
a7a57c7ff4 Merge branch 'deoxy-check' into 'preprod'
Deoxy check

See merge request sminnovations/hpos!11
2023-11-15 12:17:18 +00:00
Pritimay Sarkar
3c70142c15 check deoxygenation and classify with abs 2023-11-15 14:18:01 +05:30
Pritimay Sarkar
467dde9a24 add fields in converter 2023-11-15 13:11:54 +05:30
Pritimay Sarkar
ae50d6a603 filter local data based on test status 2023-11-15 13:11:07 +05:30
Mariya
c0825a1c58 digital card fragment coding is finished, testing is pending 2023-11-15 11:41:29 +05:30
Pritimay Sarkar
78763d8624 Merge branch 'Develop_Offline_Incubation_and_Blood_Group_Feature' of https://gitlab.com/sminnovations/hpos into deoxy-check 2023-11-15 08:37:55 +05:30
Pritimay Sarkar
fcac603ce0 change user messages 2023-11-15 08:26:55 +05:30
Pritimay Sarkar
0a2f1ba2fd refactor 2023-11-15 06:16:30 +05:30
mohamedkaif356
dcc7a921a0 Offline Incubation time 2023-11-14 22:58:34 +05:30
Mariya
b6f8999078 Merge remote-tracking branch 'origin/preprod' into preprod
# Conflicts:
#	app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt
2023-11-14 11:55:49 +05:30
Mariya
84e2a4bed9 digital card fragment User Design is finished 2023-11-14 11:55:15 +05:30
Pritimay Sarkar
74ad03bf8b add buffer validation withn bounds 2023-11-14 00:22:40 +05:30
Mariya
f00a639028 digital card fragment 2023-11-13 10:53:44 +05:30
Pritimay Sarkar
d3083c8dbc add environment name in gradle 2023-11-13 08:06:24 +05:30
Pritimay Sarkar
29846ddf7d show result processing message 2023-11-09 08:14:38 +05:30
Pritimay Sarkar
9deac8e278 fix device ratio calc 2023-11-09 08:08:04 +05:30
Mariya
264c4ebe74 Merge remote-tracking branch 'origin/preprod' into preprod 2023-11-08 12:25:07 +05:30
Mariya
2a976caac5 committed changes 2023-11-08 12:24:29 +05:30
Pritimay Sarkar
fb61b89850 change display msg 2023-11-08 11:34:31 +05:30
Pritimay Sarkar
e42183099c add new device logins 2023-11-08 11:33:59 +05:30
Mariya
bf9288d0a1 committed 2023-11-08 10:45:12 +05:30
Mariya
d57bc713d1 Merge remote-tracking branch 'origin/preprod' into preprod
# Conflicts:
#	app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt
2023-11-07 17:25:42 +05:30
Mariya
f37cfb57e1 1.baud rate is added,
2. existing buffer popup is added,
3. submit button make visible
4.handlevalidresult function changes, added code for fetch ledbuffer1 to ledbuffer4 values and sample1 to sample4 values
2023-11-07 17:25:09 +05:30
Pritimay Sarkar
9d86d874af fix testing steps 2023-11-07 07:38:10 +05:30
Pritimay Sarkar
f0d0740cd7 firmware changes for 4 leds 2023-11-07 05:18:27 +05:30
Mariya
27949352dd 1.baud rate is added,
2. existing buffer popup is added,
3. submit button make visible
4.handlevalidresult function changes, added code for fetch ledbuffer1 to ledbuffer4 values and sample1 to sample4 values
2023-11-06 18:18:07 +05:30
Mariya
36eb659e3a baud rate is completed 2023-11-06 17:46:04 +05:30
Mariya
2d0f11cfb2 new arduino code Result work for molbio is pending 2023-11-06 17:35:57 +05:30
Mariya
3e8933de1b new arduino code Result calculation is pending 2023-11-06 13:37:57 +05:30
Pritimay Sarkar
edf1d70608 add 4 led in data class 2023-11-03 16:35:28 +05:30
Pritimay Sarkar
a6d57fb52a Merge branch 'prod' into preprod 2023-11-03 11:40:40 +05:30
Pritimay Sarkar
babb3dd364 Merge branch 'fix-kit-check' into 'Homocube'
fix diagnostics reading and kit check

See merge request sminnovations/hpos!10
2023-10-31 03:46:32 +00:00
Pritimay Sarkar
51f3e31f27 fix diagnostics reading
- show and hide start button
	- show toast message after db upload
	- fix deviceid blank
2023-10-31 01:57:49 +05:30
Pritimay Sarkar
044c5db161 add coefficients in models and save coeffs in db 2023-10-30 23:48:49 +05:30
Pritimay Sarkar
f4085545ea use calculated ratio for class and save coeffs 2023-10-30 23:25:45 +05:30
Pritimay Sarkar
8872e484a1 refactoring 2023-10-30 21:08:02 +05:30
Pritimay Sarkar
88aab7c527 negative abs warning 2023-10-29 15:23:00 +05:30
Pritimay Sarkar
81298f9634 Merge branch 'hc-deviceid' into 'Homocube'
device in diagnostics and warning for loginid mismatch

See merge request sminnovations/hpos!9
2023-10-29 08:22:02 +00:00
Pritimay Sarkar
8824fb6b11 run deviceid command and store deviceid in spref 2023-10-29 13:33:18 +05:30
Pritimay Sarkar
0e847bad0a show warning msg for loginid mismatch 2023-10-29 13:16:30 +05:30
Pritimay Sarkar
9d06a77091 clean 2023-10-29 12:17:00 +05:30
Pritimay Sarkar
7ece136cb5 add deviceid constant 2023-10-29 12:16:40 +05:30
Pritimay Sarkar
5f44666387 clean functions 2023-10-29 12:15:40 +05:30
Pritimay Sarkar
2cccfc6a63 add testing trace 2023-10-29 12:06:39 +05:30
Pritimay Sarkar
50bfd3f962 stringData in device log 2023-10-29 12:01:07 +05:30
Pritimay Sarkar
d750930b7a show toast if download is greater than 0 2023-10-29 11:00:27 +05:30
Pritimay Sarkar
4214c32829 hide app update success toast 2023-10-29 06:48:38 +05:30
Pritimay Sarkar
481169a181 add diag data model 2023-10-29 06:37:54 +05:30
Pritimay Sarkar
441e7d14b8 add device connection code in diag activity 2023-10-29 06:37:20 +05:30
Pritimay Sarkar
71f3169ee3 add diaggnostics run in diag fragment 2023-10-29 06:36:02 +05:30
Pritimay Sarkar
5edeef0021 change diag activity layout 2023-10-29 06:34:40 +05:30
Pritimay Sarkar
5f5037f300 change diagnostics fragment 2023-10-29 06:34:04 +05:30
Pritimay Sarkar
a99c24dd86 add diagnostics data log fun in viewmodel 2023-10-29 06:31:57 +05:30
Pritimay Sarkar
feabcebd92 add diagnostics fun in repository 2023-10-29 06:31:15 +05:30
Pritimay Sarkar
5df58a3630 fix calculatedRatio value in kit checks 2023-10-29 06:30:26 +05:30
Pritimay Sarkar
c6d2e2a7c5 add diagonistics activity 2023-10-29 03:40:32 +05:30
Mariya
e974637744 Diagnostics code added 2023-10-29 03:39:39 +05:30
Mariya
220fea4c2e Added code for diagnostics 2023-10-29 03:36:01 +05:30
Pritimay Sarkar
f67dc04916 call calculateRatio fun 2023-10-27 10:54:58 +05:30
Pritimay Sarkar
d90dfc0695 measure user search trace after success 2023-10-25 14:42:16 +05:30
Pritimay Sarkar
2b1f8a07ae fix display of name and user id in testing screen
- show name and sample id while testing
	- hide the same in buffer check
	- change bg color after classification
2023-10-23 05:04:03 +05:30
Pritimay Sarkar
26246cd902 add parition based search
- optimize user search based on partition and denormalization
2023-10-23 05:00:58 +05:30
Pritimay Sarkar
f2f927cd23 add user search trace 2023-10-22 18:28:33 +05:30
Pritimay Sarkar
3249811c0d hide testing instructions label 2023-10-22 18:27:42 +05:30
Pritimay Sarkar
c076da3bb4 hide labels in testing screen 2023-10-17 09:21:16 +05:30
Pritimay Sarkar
1f31b0bff0 refactor 2023-10-17 09:01:56 +05:30
Pritimay Sarkar
8b833ca02d fix calculated ratio= 0 and submit btn 2023-10-17 08:58:05 +05:30
Pritimay Sarkar
2c50890b0d add testtime 2023-10-17 08:39:25 +05:30
Kaif
0b52dc42b0 Fixed merge config 2023-10-16 14:03:28 +05:30
Pritimay Sarkar
137eb7dd55 compiler error 2023-10-16 13:21:47 +05:30
Pritimay Sarkar
12df83db7b Merge 'BuffercheckDatabaseUpload' into Homocube 2023-10-16 11:51:41 +05:30
Pritimay Sarkar
9849921833 Merge branch 'Homocube' of https://gitlab.com/sminnovations/hpos into Homocube 2023-10-15 13:06:01 +05:30
Pritimay Sarkar
8662e03dad activity finish on success 2023-10-15 13:05:14 +05:30
Kaif
ac2bb91648 Buffer result uploaded successfully 2023-10-15 12:30:27 +05:30
Kaif
0408ef3fbd Save Data in Local storage in ever condition 2023-10-13 19:42:34 +05:30
Mariya
9db8e962d7 BufferCheckData uploaded to database code pending 2023-10-13 18:50:57 +05:30
Pritimay Sarkar
7c4717ebb7 added view model, laytouts 2023-10-12 19:12:40 +05:30
Pritimay Sarkar
eb668c631c hide bloodgroup and incubate btn after action 2023-10-12 09:53:44 +05:30
Pritimay Sarkar
3e362a22fa add view model for buffer check 2023-10-12 07:19:24 +05:30
Pritimay Sarkar
e2c07d6252 Merge branch 'BuffercheckDatabaseUpload' into 'Homocube'
buffer precheck data upload to database

See merge request sminnovations/hpos!7
2023-10-12 01:38:09 +00:00
Pritimay Sarkar
497a61c16b Merge branch 'Homocube' into 'BuffercheckDatabaseUpload'
# Conflicts:
#   app/src/main/java/com/example/hpostesting/presentation/buffercheck/HemoCubeBufferCheckFragment.kt
2023-10-12 01:27:44 +00:00
Pritimay Sarkar
acd9262dfe incubate while bloodgrouping 2023-10-12 06:30:52 +05:30
Mariya
f8ac0e81ce Buffercheck data Database Upload 2023-10-11 23:22:11 +05:30
Mariya
5a7a09817f Buffercheck data Database Upload 2023-10-11 17:19:10 +05:30
Mariya
ab09c659b9 Blood Group Updation in database added , from user card successfully added 2023-10-11 15:17:16 +05:30
Mariya
14c15bb9ab Added Blood group pop up dialog in user card 2023-10-11 15:16:32 +05:30
Mariya
0ca4083c16 Database upload completed 2023-10-11 12:32:07 +05:30
Mariya
662e2644f2 Added Blood group pop up dialog in user card 2023-10-11 11:21:50 +05:30
Mariya
63aeebd4e1 spelling mistake got corrected 2023-10-05 15:30:27 +05:30
mohamedkaif356
315c46c014 Battery check 2023-10-05 10:56:09 +05:30
Mariya
27bf068df0 Displaying Name in the result screen 2023-10-04 13:20:40 +05:30
Mariya
23d382395f changes 2023-10-04 13:19:35 +05:30
Pritimay Sarkar
31d3458cd1 revert to old ratio for kit precheck 2023-10-04 00:40:59 +05:30
Pritimay Sarkar
1ec79853de release 2.1.20 2023-10-04 00:37:20 +05:30
Pritimay Sarkar
744735d7ba add download file size in MB and error code 2023-10-02 21:06:22 +05:30
Pritimay Sarkar
211429fb8f app distribution changes
- show progress update
	- show update success message
2023-10-02 18:57:50 +05:30
Pritimay Sarkar
8a56d0eb5f remove .idea/misc.xml 2023-10-02 18:33:01 +05:30
Pritimay Sarkar
ed6cb58b69 fit the long text of classification result 2023-10-02 18:29:23 +05:30
Pritimay Sarkar
67d8ffe502 change PDR in buffer check 2023-10-02 18:28:37 +05:30
Pritimay Sarkar
dadc24cb88 Merge branch 'Homocube' of https://gitlab.com/sminnovations/hpos into Homocube 2023-10-02 17:46:55 +05:30
mohamedkaif356
118b17bee1 Local upload, incubation time stamp and UI change 2023-10-02 17:28:24 +05:30
mohamedkaif356
d42f5e31e5 Fixed displaying name and id, changes results displaying logic 2023-10-02 16:24:35 +05:30
Pritimay Sarkar
f1f45fb958 decrease the lower bound for PDR 2023-10-02 12:51:15 +05:30
Pritimay Sarkar
8482de6aeb Merge branch 'Homocube' of https://gitlab.com/sminnovations/hpos into Homocube 2023-09-30 09:49:09 +05:30
Pritimay Sarkar
d6ffcba70a try catch for user data load 2023-09-30 09:48:00 +05:30
Pritimay Sarkar
381b351309 Merge branch 'updationPoints' into 'Homocube'
name of person, added in result screen

See merge request sminnovations/hpos!6
2023-09-29 08:49:17 +00:00
Mariya
c01676cc4f name of person, added in result screen 2023-09-29 12:50:36 +05:30
Pritimay Sarkar
a61aab377e Merge branch 'Homocube' of https://gitlab.com/sminnovations/hpos into Homocube 2023-09-27 02:55:18 +05:30
Pritimay Sarkar
e1dbfc9d89 add logiid in constants and userlist order 2023-09-27 02:55:09 +05:30
mohamedkaif356
3671dc9db8 Removed card color logic 2023-09-26 16:45:32 +05:30
Pritimay Sarkar
e613bbd12b change if check for exsting buffer 2023-09-26 16:41:49 +05:30
Mariya
1d017f0578 set the card color into green if the incubation time equals to 15. and it turns red if the incubation time equals 25, new push 2023-09-26 14:44:26 +05:30
Mariya
e34e7ada52 Merge remote-tracking branch 'origin/Homocube' into Homocube
# Conflicts:
#	app/src/main/java/com/example/hpostesting/presentation/adapter/UserListAdapter.kt
2023-09-26 14:43:08 +05:30
Mariya
9cd0ee21b6 set the card color into green if the incubation time equals to 15. and it turns red if the incubation time equals 25, 2023-09-26 14:41:39 +05:30
Mariya
f3598c9699 set the card color into green if the incubation time equals to 15. and it turns red if the incubation time equals 25, 2023-09-26 14:27:49 +05:30
mohamedkaif356
9b38a5dff7 Buffer check 2023-09-22 11:40:17 +05:30
mohamedkaif356
a7adb02593 Fixed buffer error and updated incubationTime on the user card 2023-09-20 16:09:34 +05:30
mohamedkaif356
5647340b90 Added New kit button to home screen 2023-09-20 10:29:42 +05:30
mohamedkaif356
94894f34a5 Added incubationTime check 2023-09-19 17:39:20 +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
198 changed files with 17583 additions and 1894 deletions

8
.gitignore vendored
View File

@@ -1,13 +1,7 @@
*.iml
.gradle
/local.properties
/.idea/misc.xml
/.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>

40
.idea/misc.xml generated
View File

@@ -1,40 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DesignSurface">
<option name="filePathToZoomLevelMap">
<map>
<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" />
<entry key="app/src/main/res/drawable/ic_baseline_file_download_24.xml" value="0.243" />
<entry key="app/src/main/res/drawable/ic_baseline_home_24.xml" value="0.243" />
<entry key="app/src/main/res/drawable/ic_baseline_new_label_24.xml" value="0.243" />
<entry key="app/src/main/res/drawable/ic_baseline_usb_24.xml" value="0.157" />
<entry key="app/src/main/res/drawable/ic_baseline_usb_off_24.xml" value="0.157" />
<entry key="app/src/main/res/drawable/progressbar_drawable.xml" value="0.1885" />
<entry key="app/src/main/res/drawable/result_background_green.xml" value="0.243" />
<entry key="app/src/main/res/drawable/result_background_red.xml" value="0.1785" />
<entry key="app/src/main/res/drawable/result_background_tellow.xml" value="0.1785" />
<entry key="app/src/main/res/font/inter_bold.xml" value="0.33487179487179486" />
<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_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_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/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" />
<entry key="app/src/main/res/mipmap-anydpi-v26/hpos_icon.xml" value="0.1505" />
<entry key="app/src/main/res/mipmap-anydpi-v26/hpos_icon_round.xml" value="0.1505" />
</map>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="Android Studio default JDK" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>

2
app/.gitignore vendored
View File

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

View File

@@ -2,19 +2,25 @@ 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'
// prod - production, preprod - preproduction, quality - qc,
defaultConfig {
applicationId "com.example.hpos"
applicationId "in.sminnovations.hpostesting"
minSdk 21
targetSdk 32
versionCode 1
versionName "1.0"
targetSdk 34
versionCode 44
versionName "2.1.44"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@@ -26,41 +32,105 @@ 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
}
packagingOptions {
exclude 'mockito-extensions/org.mockito.plugins.MockMaker'
}
}
dependencies {
implementation "com.google.dagger:hilt-android:2.46"
kapt "com.google.dagger:hilt-android-compiler:2.46"
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.10.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.2'
implementation 'androidx.fragment:fragment-ktx:1.6.2'
//firebase
implementation platform('com.google.firebase:firebase-bom:32.1.0')
implementation("com.google.firebase:firebase-perf-ktx")
implementation("com.google.firebase:firebase-crashlytics-ktx")
implementation("com.google.firebase:firebase-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-beta11'
implementation("com.google.firebase:firebase-appdistribution-api-ktx:16.0.0-beta11")
implementation 'androidx.preference:preference-ktx:1.2.1'
implementation 'androidx.preference:preference-ktx:1.2.1'
// Testing
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
// Mockito dependencies
testImplementation 'org.mockito:mockito-core:3.12.4'
androidTestImplementation 'org.mockito:mockito-android:3.12.4'
androidTestImplementation 'org.mockito:mockito-inline:3.12.4'
testImplementation "androidx.arch.core:core-testing:2.2.0"
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.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.2"
// 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"
implementation "androidx.room:room-runtime:2.6.0"
kapt ("androidx.room:room-compiler:2.6.0")
//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.5"
implementation "androidx.navigation:navigation-ui-ktx:2.7.5"
//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.1.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,28 @@
<?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-permission
android:name="android.permission.BATTERY_STATS"
tools:ignore="ProtectedPermissions" />
<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 +30,77 @@
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.DigitalCardActivity"
android:exported="false" />
<activity
android:name="com.example.hpostesting.presentation.diagnostics.DiagnosticsActivity"
android:exported="false" />
<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.buffercheck.HemocubeBufferCheckActivity"
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"
tools:ignore="MissingClass" />
<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 +108,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,122 @@
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",
"HC-V1-007",
"HC-V1-008",
"HC-V1-009",
"HC-V1-010",
"HC-V1-011",
"HC-V1-012",
"HC-V1-013",
"HC-V1-014",
"HC-V1-015",
"HC-V1-016",
"HC-V1-017",
"HC-V1-018",
"HC-V1-019",
"HC-V1-020",
"HCV-000-3001",
"HCV-000-3002",
)
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"
const val BUFFER_VALUE_3 = "BufferValue3"
const val BUFFER_VALUE_4 = "BufferValue4"
const val DEVICE_ID = "DEVICE_ID"
const val BUFFER_LED_LOWER_BOUND = 21000
const val BUFFER_LED_UPPER_BOUND = 24500
val DEVICE_CONFIGURATION: Map<String, List<List<Double>>> = mapOf<String, List<List<Double>>>(
"HCV-000-3001" to listOf(
listOf(1.313, -0.89), // LED1, 435nm
listOf(0.581462456, -0.58502), // LED2, 415nm
listOf(0.2012, 0.0092), // LED3, 555nm
listOf(1.0, 0.0) // LED4
),
"HCV-000-3002" to listOf(
listOf(0.723142, -0.09135), // LED1, 435nm
listOf(0.581462456, -0.58502), // LED2, 415nm
listOf(0.1964, 0.011565), // LED3, 555nm
listOf(1.0, 0.0) // LED4
),
)
const val INCUBATION_TIME_MIN = 0
const val INCUBATION_TIME_MAX = 1400
val BUFFER_INTENSITY_THRESHOLDS: Map<String, List<List<Int>>> = mapOf<String, List<List<Int>>>(
"HCV-000-3001" to listOf(
listOf(20000, 25074),
listOf(20000, 24596),
listOf(20000, 26065),
listOf(20000, 27093),
),
"HCV-000-3002" to listOf(
listOf(24500, 26250),
listOf(24500, 26250),
listOf(24500, 26250),
listOf(24500, 26250),
)
)
val COEFFICIENTS: Map<String, List<List<Double>>> = mapOf(
"HC-V1-005" to listOf(
listOf(1.5,0.0),
listOf(0.0,0.0)
)
)
}

View File

@@ -0,0 +1,9 @@
package com.example.hpostesting.data.constant
enum class HemoCubeCommands(val command: String) {
startBuffer("B\r"),
runDiagnostics("D\r"),
startSample("S\r"),
getSample("P\r"),
getDeviceId("I\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,26 @@
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)
@Query("UPDATE hemo_cube_test_table SET localFlag = :newValue WHERE _id = :id")
suspend fun updateFieldById(id: String, newValue: Boolean)
}

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 = 11, 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,9 @@
package com.example.hpostesting.data.model.diagnostics
data class DiagnosticsData (
var deviceId: String = "",
var appVersion: String? = "",
var deviceType: String = "HEMOCUBE",
var deviceData: String = "",
var runTime: String = ""
)

View File

@@ -0,0 +1,21 @@
package com.example.hpostesting.data.model.patient
data class BufferCheckData(
var kitno: String = "",
var deviceId: String? = "",
var appVersion:String? = "",
var deviceSerialNumber: String = "",
var deviceType: String = "HEMOCUBE",
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 coefficients: String? = "",
var classificationResult: String = "",
var testTime: String = ""
)

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,58 @@
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 incubationTime: String = "",
var bloodGroup: String = "",
var birthYear: String = "",
var state: String = "",
var abhaId: String = "",
var userImageURL: String = "",
var location: UserData.Location? = null,
var reportUploadTime: String? = "",
var testType: String? = "HEMOCUBE",
var testTime: String? = "",
var testStatus: Boolean? = false,
var gender: String = "",
var localFlag: Boolean = false,
var deviceId: String? = "",
var appVersion:String? = "",
var deviceSerialNumber: String = "",
var deviceType: String = "HEMOCUBE",
var kitSerial: String = "",
var resultData: String = "",
var led1Buffer: Double? = null,
var led2Buffer: Double? = null,
var led3Buffer: Double? = null,
var led4Buffer: Double? = null,
var led1Sample: Double? = null,
var led2Sample: Double? = null,
var led3Sample: Double? = null,
var led4Sample: Double? = null,
var led1Average: Double? = null,
var led2Average: Double? = null,
var led3Average: Double? = null,
var led4Average: Double? = null,
var abs1: Double? = null,
var abs2: Double? = null,
var abs3: Double? = null,
var abs4: Double? = null,
var deviceRatio: Double? = null,
var calculatedRatio: Double? = null,
var predictedDenovixRatio: Double? = null,
var coefficients: String? = "",
var classificationResult: String = "",
var prdClassification: String = "",
var errorMessages: String = "",
var batteryLevel: String = "",
var batteryCapacity: String = "",
var batteryMaxCapacity: String = "",
var batteryTemperature: String = "",
var batteryVoltage: 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,59 @@
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 incubationTime: String = "",
var birthYear: String = "",
var abhaId: String = "",
var bloodGroup: String = "",
var userImageURL: String = "",
var gender: 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 state: String = "",
var deviceSerialNumber: String = "",
var kitSerial: String = "",
var csvPath: String = "",
var reportPath: String = "",
var result: TestRightResultType? = null,
var resultRatio: Double? = null,
var prdClassification: String = ""
) {
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,
gender = gender,
state = state,
abhaId = abhaId,
bloodGroup = bloodGroup,
prdClassification = prdClassification,
testTime = testTime
)

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,142 @@
package com.example.hpostesting.data.repository
import android.net.Uri
import com.example.hpostesting.data.model.PendingUploads
import com.example.hpostesting.data.model.Response
import com.example.hpostesting.data.model.diagnostics.DiagnosticsData
import com.example.hpostesting.data.model.patient.BufferCheckData
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.UserData
import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.firestore.ktx.firestore
import com.google.firebase.ktx.Firebase
import com.google.firebase.storage.ktx.storage
import kotlinx.coroutines.tasks.await
import java.io.File
import javax.inject.Inject
class DatabaseRepository @Inject constructor() : Repository {
private val db: FirebaseFirestore = Firebase.firestore
private val storage = Firebase.storage
override 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)
}
}
override 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) {
Firebase.crashlytics.recordException(e)
Response.Error(e)
}
}
override suspend fun addTestToDatabaseforBufferCheck(data: BufferCheckData?): Response<String> {
return try {
db.collection("buffers").add(data!!).await()
Response.Success(data!!.kitno)
} catch (e: Exception) {
Firebase.crashlytics.recordException(e)
Response.Error(e)
}
}
override suspend fun addDiagnostics(data: DiagnosticsData?): Response<String> {
return try {
db.collection("diagnostics").add(data!!).await()
Response.Success(data!!.deviceId)
} catch (e: Exception) {
Firebase.crashlytics.recordException(e)
Response.Error(e)
}
}
override 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) {
Firebase.crashlytics.recordException(e)
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) {
Firebase.crashlytics.recordException(e)
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) {
Firebase.crashlytics.recordException(e)
pendingList
}
}
suspend fun removeFromPendingQueue(fileName: String): Response<Boolean> {
return try {
db.collection("pendingUploads").document(fileName).delete().await()
Response.Success(true)
} catch (e: Exception) {
Firebase.crashlytics.recordException(e)
Response.Error(e)
}
}
suspend fun getDeviceData(): List<DeviceData> {
return db.collection("devices").get().await().toObjects(DeviceData::class.java)
}
override 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,22 @@
package com.example.hpostesting.data.repository
import com.example.hpostesting.data.model.Response
import com.example.hpostesting.data.model.diagnostics.DiagnosticsData
import com.example.hpostesting.data.model.patient.BufferCheckData
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.UserData
interface Repository {
suspend fun addTestToDatabase(data: HemoCubeTestData?): Response<String>
suspend fun addTestToDatabase(data: UserData?): Response<String>
suspend fun addTestToDatabaseforBufferCheck(data: BufferCheckData?): Response<String>
suspend fun addDiagnostics(data: DiagnosticsData?): Response<String>
suspend fun uploadFileToStorage(patientID: String, filePath: String): Response<Boolean>
suspend fun getDeviceDataById(deviceId: String): DeviceData?
}

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,79 @@
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.data.repository.Repository
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()
}
@Provides
@Singleton
fun provideRepository(): Repository {
return DatabaseRepository()
}
}

View File

@@ -0,0 +1,224 @@
package com.example.hpostesting.presentation
import com.example.hpostesting.presentation.dashboard.DashboardActivity
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.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, R.string.cancelled_unable_scan, 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() && isSerialValid(serialNumber)) {
if (DataHolder.selectedTest == null) {
with(sharedPreference.edit()) {
putString(
Constants.KIT_NUMBER, binding.nameEditText.text.toString()
)
putInt(Constants.KIT_COUNT, 1)
apply()
}
Toast.makeText(
applicationContext,
R.string.kit_updated,
Toast.LENGTH_SHORT
).show()
val i = Intent(applicationContext, DashboardActivity::class.java)
startActivity(i)
finish()
} else {
DataHolder.kitSerial = binding.nameEditText.text.toString()
DataHolder.selectedTest?.kitSerial = binding.nameEditText.text.toString()
with(sharedPreference.edit()) {
putString(Constants.KIT_NUMBER, binding.nameEditText.text.toString())
putInt(Constants.KIT_COUNT, 1)
apply()
}
moveToNext()
}
} else {
Toast.makeText(this, R.string.invalid_kit_number, Toast.LENGTH_LONG).show()
return@setOnClickListener
}
if (serialNumber.isNotEmpty() && checkDataNotNull() && isSerialValid(
serialNumber
)
) {
DataHolder.kitSerial = binding.nameEditText.text.toString()
DataHolder.selectedTest?.kitSerial = binding.nameEditText.text.toString()
with(sharedPreference.edit()) {
putString(Constants.KIT_NUMBER, binding.nameEditText.text.toString())
putInt(Constants.KIT_COUNT, 1)
apply()
}
moveToNext()
} else {
Toast.makeText(this, R.string.invalid_kit_number, Toast.LENGTH_LONG).show()
}
}
}
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, R.string.select_patient, Toast.LENGTH_SHORT
).show()
val i = Intent(applicationContext, DashboardActivity::class.java)
startActivity(i)
false
} else {
true
}
}
}

View File

@@ -0,0 +1,331 @@
package com.example.hpostesting.presentation
import com.example.hpostesting.presentation.dashboard.DashboardActivity
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.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.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()
}
}
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, R.string.device_not, 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, R.string.enable_location, 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, R.string.coarse_location_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, R.string.location_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,159 @@
package com.example.hpostesting.presentation
import com.example.hpostesting.presentation.dashboard.DashboardActivity
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.util.MyUtils
import `in`.sminnovations.hpostesting.R
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,
R.string.permission_grant,
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, R.string.permission_required, 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,147 @@
package com.example.hpostesting.presentation.adapter
import android.annotation.SuppressLint
import android.content.Context
import android.content.res.Resources
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.navigation.findNavController
import androidx.recyclerview.widget.AsyncListDiffer
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
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 `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.OfflineUserListViewBinding
import org.apache.commons.collections4.MapUtils.getString
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import java.util.Locale
class OfflineUserListAdapter(private val view: View, private val batLevel: Int) :
RecyclerView.Adapter<OfflineUserListAdapter.OfflineUserListViewHolder>() {
inner class OfflineUserListViewHolder(val binding: OfflineUserListViewBinding) :
RecyclerView.ViewHolder(binding.root) {
}
private val differCallback = object : DiffUtil.ItemCallback<HemoCubeTestData>() {
override fun areItemsTheSame(
oldItem: HemoCubeTestData, newItem: HemoCubeTestData
): Boolean {
return oldItem._id == newItem._id
}
override fun areContentsTheSame(
oldItem: HemoCubeTestData, newItem: HemoCubeTestData
): Boolean {
return oldItem == newItem
}
}
val differ = AsyncListDiffer(this, differCallback)
private val context: Context? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OfflineUserListViewHolder {
return OfflineUserListViewHolder(
OfflineUserListViewBinding.inflate(LayoutInflater.from(parent.context), parent, false)
)
}
override fun getItemCount(): Int {
return differ.currentList.size
}
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: OfflineUserListViewHolder, position: Int) {
val userList = differ.currentList[position]
holder.binding.apply {
userID.text = "User ID: ${userList._id}"
bloodGroup.text = "Blood group: ${userList.bloodGroup}"
time.text = "Time: ${isBetween15And30Minutes(userList.incubationTime)} \n Started at: ${
SimpleDateFormat("HH:mm:ss").format(
SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).parse(userList.incubationTime)!!
)
}"
if (userList.testStatus!!) {
teststatus.text = view.context.getString(R.string.test_concluded)
} else {
teststatus.text = view.context.getString(R.string.test_pending)
}
userCard.setOnClickListener {
if (batLevel < 40) {
showWarningToast(R.string.low_battery_warning)
} else {
if (userList.testStatus != null) {
if (userList.testStatus!!) {
showWarningToast(R.string.test_already_conducted)
} else {
if (userList.incubationTime != "") {
val incubationTimeDiff = isBetween15And30Minutes(userList.incubationTime)
if (incubationTimeDiff < 15) {
showWarningToast(R.string.incubation_not_completed)
} else if (incubationTimeDiff > 30) {
showWarningToast(R.string.incubation_crossed_30_minutes)
} else {
DataHolder.selectedTest = UserData(
_id = userList._id,
bloodGroup = userList.bloodGroup,
incubationTime = userList.incubationTime
)
view.findNavController()
.navigate(R.id.action_nav_home_to_mainActivity)
}
} else {
showWarningToast(R.string.incubation_not_started)
}
}
}
}
}
}
}
private fun isBetween15And30Minutes(createdAt: String): Long {
val formatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
val createdAtDate: Date = formatter.parse(createdAt)!!
val currentTime = Calendar.getInstance().time
val diffMillis = currentTime.time - createdAtDate.time
return diffMillis / (60 * 1000)
}
private fun showWarningToast(resId: Int) {
val contextToUse = view.context ?: return
val message = try {
contextToUse.getString(resId)
} catch (e: Resources.NotFoundException) {
"Resource not found for ID: $resId"
}
Toast.makeText(
contextToUse,
message,
Toast.LENGTH_SHORT
).show()
}
}

View File

@@ -0,0 +1,258 @@
package com.example.hpostesting.presentation.adapter
import android.annotation.SuppressLint
import android.app.AlertDialog
import android.content.Context
import android.content.Context.INPUT_METHOD_SERVICE
import android.view.inputmethod.InputMethodManager
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.firebase.ui.firestore.FirestoreRecyclerAdapter
import com.firebase.ui.firestore.FirestoreRecyclerOptions
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.UserItemViewBinding
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import java.util.Locale
import android.widget.AutoCompleteTextView
import androidx.core.content.ContextCompat.getSystemService
import androidx.core.content.getSystemService
import androidx.fragment.app.FragmentActivity
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.google.firebase.firestore.FirebaseFirestore
class UserListAdapter(
private val context: Context,
private val hemoCubeViewModel: HemoCubeViewModel,
options: FirestoreRecyclerOptions<UserData>,
private val view: View,
private val batLevel: Int,
private val requireActivity: FragmentActivity
) : 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}"
if (model.incubationTime == "") {
btnBlood.visibility = View.VISIBLE
} else {
userId.text =
"User ID:${model._id} \n Time: ${isBetween15And30Minutes(model.incubationTime)} \n Started at: ${
SimpleDateFormat("HH:mm:ss").format(
SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).parse(model.incubationTime)!!
)
}"
btnBlood.visibility = View.GONE
}
Glide.with(view).load(model.userImageURL).into(userImage)
if (model.testStatus!!) {
teststatus.text = view.context.getString(R.string.test_concluded)
} else {
teststatus.text = view.context.getString(R.string.test_pending)
}
holder.binding.btnBlood.setOnClickListener {
val view: View? = requireActivity.currentFocus
// on below line checking if view is not null.
if (view != null) {
// on below line we are creating a variable
// for input manager and initializing it.
val inputMethodManager =
context.getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
// on below line hiding our keyboard.
inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0)
}
val inflater = LayoutInflater.from(context)
val dialogView = inflater.inflate(R.layout.dialog_custom, null)
val builder = AlertDialog.Builder(context)
.setView(dialogView)
.setTitle("Add Blood Group")
val etBloodGroup = dialogView.findViewById<AutoCompleteTextView>(R.id.et_blood_group)
builder.setPositiveButton("OK") { dialog, which ->
val bloodGroup = etBloodGroup.text.toString()
if (bloodGroup.equals("Select Blood Group") || bloodGroup.isNullOrBlank()) {
if (view != null) {
etBloodGroup.error =view.context.getString(R.string.blood_group_error)
}
if (view != null) {
Toast.makeText(context, view.context.getString(R.string.blood_group_toast), Toast.LENGTH_SHORT).show()
}
} else {
// Check if hemoCubeViewModel and testDetails are not null
val db: FirebaseFirestore = FirebaseFirestore.getInstance()
db.collection("patientData")
.whereEqualTo("_id", model._id)
.get()
.addOnSuccessListener { userdata ->
try {
val document = userdata.documents[0]
db.collection("patientData")
.document(document.id)
.update("bloodGroup", bloodGroup,
"incubationTime", SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time).toString()
)
.addOnSuccessListener {
if (view != null) {
Toast.makeText(
view.context,
context?.getString(R.string.blood_group_updated_successfully),
Toast.LENGTH_SHORT
).show()
}
btnBlood.visibility = View.GONE
}
.addOnFailureListener { e ->
if (view != null) {
Toast.makeText(
view.context,
context?.getString(R.string.failed_to_update_blood_group),
Toast.LENGTH_SHORT
).show()
}
}
} catch (e: IndexOutOfBoundsException) {
// Handle the case where no documents are found for the specified ID
if (view != null) {
Toast.makeText(
view.context,
context?.getString(R.string.no_user_data_found),
Toast.LENGTH_SHORT
).show()
}
}
}
.addOnFailureListener { e ->
Toast.makeText(
context,
"Error fetching user data: ${e.message}",
Toast.LENGTH_SHORT
).show()
}
}
// Handle the selected blood group here
}
builder.setNegativeButton("Cancel") { dialog, which ->
dialog.dismiss()
}
val alertDialog = builder.create()
alertDialog.show()
}
btnStartIncubation.setOnClickListener {
// it.visibility = View.GONE
// Firebase.firestore.collection("patientData").whereEqualTo("_id", model._id).get()
// .addOnSuccessListener { data ->
// if (data.documents.isNotEmpty()) {
// data.documents.forEach { userData ->
// Firebase.firestore.collection("patientData").document(userData.id)
// .update(
// "incubationTime", SimpleDateFormat(
// "yyyy-MM-dd HH:mm:ss", Locale.getDefault()
// ).format(Calendar.getInstance().time).toString()
// ).addOnSuccessListener {
// Toast.makeText(
// view.context, "Incubation started", Toast.LENGTH_SHORT
// ).show()
// startListening()
// }
// }
// }
// }
}
userCard.setOnClickListener {
if (batLevel < 40) {
Toast.makeText(
view.context,
context?.getString(R.string.low_battery_warning),
Toast.LENGTH_SHORT
).show()
return@setOnClickListener
}
if (model.testStatus != null) {
if (model.testStatus!!) {
Toast.makeText(
view.context,
context?.getString(R.string.test_already_conducted),
Toast.LENGTH_SHORT
).show()
} else {
if (model.incubationTime != "") {
if (isBetween15And30Minutes(model.incubationTime) < 15) {
Toast.makeText(
view.context,
context?.getString(R.string.incubation_not_completed),
Toast.LENGTH_SHORT
).show()
} else if (isBetween15And30Minutes(model.incubationTime) > 30) {
Toast.makeText(
view.context,
context?.getString(R.string.incubation_crossed_30_minutes),
Toast.LENGTH_SHORT
).show()
} else {
DataHolder.selectedTest = model
view.findNavController()
.navigate(R.id.action_nav_home_to_mainActivity)
}
} else {
Toast.makeText(
view.context,
context?.getString(R.string.incubation_not_started),
Toast.LENGTH_SHORT
).show()
}
}
}
}
}
}
private fun isBetween15And30Minutes(createdAt: String): Long {
val formatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
val createdAtDate: Date = formatter.parse(createdAt)!!
val currentTime = Calendar.getInstance().time
val diffMillis = currentTime.time - createdAtDate.time
return diffMillis / (60 * 1000)
}
}

View File

@@ -0,0 +1,354 @@
package com.example.hpostesting.presentation.buffercheck
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.view.inputmethod.InputMethodManager
import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.MutableLiveData
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.BufferCheckData
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.toHemoCubeTestData
import com.example.hpostesting.presentation.UsbServiceListener
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
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.ktx.Firebase
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentHemoCubeReferenceBinding
import kotlin.math.log10
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
class HemoCubeBufferCheckFragment : Fragment() {
private lateinit var binding: FragmentHemoCubeReferenceBinding
private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels()
private lateinit var sharedPreferences: SharedPreferences
private var currentDeviceData: DeviceData? = null
private var resultData: String = ""
private var kitno: String = ""
private var isOnline = false
private val messages = MutableLiveData<String>()
private var isTestOngoing = false
private var startListening = MutableLiveData(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()
}
private fun initViews() {
binding.nameEditText.setText("SMI/SC/")
binding.tvTitle.visibility = View.GONE
binding.tvName.visibility = View.GONE
binding.btnGo.setOnClickListener {
val serialNumber = binding.nameEditText.text.toString().trim()
if (serialNumber.isNotEmpty() && isSerialValid(serialNumber)) {
kitno = serialNumber
listenToHemoCube()
startBufferProcess()
} else {
Toast.makeText(context, R.string.invalid_kit_number, Toast.LENGTH_LONG).show()
return@setOnClickListener
}
activity?.runOnUiThread {
binding.tvSubtitle2.visibility = View.GONE
binding.etAbhaId.visibility = View.GONE
binding.tvTitle.visibility = View.GONE
binding.tvTitle2.visibility = View.GONE
binding.btnGo.visibility = View.GONE
}
}
activity?.runOnUiThread {
binding.btnSubmit.isEnabled = true
binding.btnSubmit.isClickable = true
}
binding.btnSubmit.setOnClickListener {
}
binding.btnSubmit.isEnabled = false
binding.btnSubmit.isClickable = false
}
private fun observeViewModel() {
hemoCubeViewModel.deviceData.observe(viewLifecycleOwner) {
currentDeviceData = it
}
hemoCubeViewModel.networkStatusLiveData.observe(viewLifecycleOwner) { isNetworkAvailable ->
if (isNetworkAvailable) {
hemoCubeViewModel.getDeviceData(sharedPreferences.getString(Constants.USER_ID, ""))
} else {
Toast.makeText(
requireContext(), R.string.internt_not, Toast.LENGTH_SHORT
).show()
}
isOnline = isNetworkAvailable
}
hemoCubeViewModel.fireBaseUpload.observe(viewLifecycleOwner) { result ->
if (result == "Success") {
showToast(R.string.kit_uploaded)
}
if (result == "Local") {
showToast(R.string.kit_upload_failed)
}
binding.progressBar.visibility = View.GONE
}
messages.observe(viewLifecycleOwner) {
binding.tvSubtitle4.text = it
}
}
private fun listenToHemoCube() {
if (DataHolder.hemoCubeTestData == null) {
DataHolder.hemoCubeTestData = DataHolder.selectedTest?.toHemoCubeTestData()
}
val fullReadOutput = StringBuilder()
startListening.postValue(true)
try {
(activity as HemocubeBufferCheckActivity).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?) {
}
})
} catch (e: Exception) {
showToast(R.string.test_ongoing)
Firebase.crashlytics.recordException(e)
}
}
private fun handleUsbData(stringData: String, fullReadOutput: StringBuilder) {
if (stringData.contains("#")) {
messages.postValue(stringData)
isTestOngoing = true
}
resultData += fullReadOutput.toString()
when {
stringData.contains("#Buffer Completed") -> showStartSampleDialog()
stringData.contains("#Sample Completed") -> {
activity?.runOnUiThread {
binding.btnSubmit.isEnabled = true
binding.btnSubmit.isClickable = true
}
fetchResult()
}
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)
}
}
}
}
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) {
try {
val result = validString.split(" ")
if (result.size == 8) {
val deviceId = result[2]
val led1BufferForDevice = result[3].toDoubleOrNull()
val led2BufferForDevice = result[4].toDoubleOrNull()
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
val calculateRatio = calculateRatio(deviceRatio)
val classificationResult = findResult(calculateRatio)
messages.postValue(classificationResult)
val bufferData = BufferCheckData(
deviceId= deviceId,
kitno = kitno,
led1Buffer = led1BufferForDevice,
led2Buffer = led2BufferForDevice,
led1Average = led1Average,
led2Average = led2Average,
led1Sample = led1Sample,
led2Sample = led2Sample,
deviceRatio = deviceRatio,
calculatedRatio = calculateRatio,
coefficients = currentDeviceData?.coefficients?.get(0).toString() + ", " + currentDeviceData?.coefficients?.get(1).toString(),
classificationResult = classificationResult,
deviceSerialNumber = sharedPreferences.getString(Constants.USER_ID, "").toString(),
testTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
)
hemoCubeViewModel.uploadHemoCubeResultToDatabaseforbuffercheckN(bufferData)
}
} 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 "Kit Failed"
if (calculatedRatio in 0.085..0.155) return "Kit Passed"
if (calculatedRatio in 0.155..0.175) return "Kit Failed"
if (calculatedRatio in 0.175..0.22) return "Kit Failed"
if (calculatedRatio in 0.22..0.25) return "Kit Failed"
if (calculatedRatio in 0.25..0.35) return "Kit Failed"
if (calculatedRatio > 0.35) return "Kit Failed"
} else {
return "NULL"
}
} catch (e: Exception) {
showToast(R.string.error_classification)
Firebase.crashlytics.recordException(e)
return "ERROR"
}
return "NULL"
}
private fun showToast(messageResId: Int) {
Toast.makeText(requireContext(), getString(messageResId), Toast.LENGTH_SHORT).show()
}
private fun startBufferProcess() {
(activity as HemocubeBufferCheckActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.startBuffer,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {}
override fun onUsbError(e: Exception?) {
}
})
}
private fun startSampleProcess() {
(activity as HemocubeBufferCheckActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.startSample,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {}
override fun onUsbError(e: Exception?) {
}
})
}
private fun fetchResult() {
(activity as HemocubeBufferCheckActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.getSample,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {}
override fun onUsbError(e: Exception?) {
}
})
}
private fun calculateRatio(ratio: Double): Double {
val coefficient1 = currentDeviceData?.coefficients?.get(0) ?: 0.0
val coefficient2 = currentDeviceData?.coefficients?.get(1) ?: 1.0
return coefficient1 * ratio + coefficient2
}
private fun 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 isSerialValid(s: String): Boolean {
if (s.length != 17) {
binding.nameEditText.error = getString(R.string.invalid_kit)
return false
}
return true
}
private fun isValidResult(line: String): String {
return if (line.contains("RESULT") && line.split(" ").size == 8) {
line
} else {
""
}
}
}

View File

@@ -0,0 +1,164 @@
package com.example.hpostesting.presentation.buffercheck
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.hemocube.HemoCubeViewModel
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 HemocubeBufferCheckActivity : 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 {
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, R.string.device_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()) {
Toast.makeText(this, R.string.no_device_found, Toast.LENGTH_SHORT).show()
} 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) {
PendingIntent.getBroadcast(
this, 0, Intent(Constants.HOMOCUBE_USB_PERMISSION), PendingIntent.FLAG_MUTABLE
)
} else {
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)
}
private fun setupService() {
val intent = Intent(this, UsbService::class.java)
bindService(intent, connection, Context.BIND_AUTO_CREATE)
}
private fun moveToNext() {
if (supportFragmentManager.isDestroyed) return
supportFragmentManager.beginTransaction().replace(binding.fghemocube.id, HemoCubeBufferCheckFragment())
.commit()
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.my_menu, menu)
return true
}
override fun onDestroy() {
super.onDestroy()
if (viewModel.isServiceConnected) {
mService.disconnect()
unbindService(connection)
viewModel.isServiceConnected = false
}
}
}

View File

@@ -0,0 +1,98 @@
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 com.google.firebase.crashlytics.FirebaseCrashlytics
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()
val firebaseAppDistribution = FirebaseAppDistribution.getInstance()
firebaseAppDistribution.updateIfNewReleaseAvailable()
.addOnProgressListener { updateProgress ->
if (updateProgress.apkBytesDownloaded > 0) {
Toast.makeText(
this,
"${updateProgress.updateStatus}. ${updateProgress.apkBytesDownloaded / 1048576} /${updateProgress.apkFileTotalBytes / 1048576} MB",
Toast.LENGTH_SHORT
).show()
}
}
.addOnFailureListener { e ->
// (Optional) Handle errors.
if (e is FirebaseAppDistributionException) {
when (e.errorCode) {
FirebaseAppDistributionException.Status.NOT_IMPLEMENTED -> {
// SDK did nothing. This is expected when building for Play.
}
else -> {
// Handle other errors.
Toast.makeText(
this,
"AppDistribution error, status: ${e.errorCode}",
Toast.LENGTH_SHORT
).show()
}
}
FirebaseCrashlytics.getInstance().recordException(e)
}
}
.addOnSuccessListener {
// Toast.makeText(this, "App Update: Success!", Toast.LENGTH_SHORT).show()
}
}
}

View File

@@ -0,0 +1,52 @@
package com.example.hpostesting.presentation.dashboard
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.example.hpostesting.presentation.buffercheck.HemocubeBufferCheckActivity
import com.example.hpostesting.presentation.diagnostics.DiagnosticsActivity
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
// }
binding.btnSubmit.setOnClickListener {
startActivity(Intent(requireContext(), HemocubeBufferCheckActivity::class.java))
}
binding.btnDiagnostics.setOnClickListener {
startActivity(Intent(requireContext(), DiagnosticsActivity::class.java))
}
return root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View File

@@ -0,0 +1,381 @@
package com.example.hpostesting.presentation.dashboard
import android.app.AlertDialog
import android.content.Context
import android.content.Context.BATTERY_SERVICE
import android.content.DialogInterface
import android.content.Intent
import android.content.SharedPreferences
import android.os.BatteryManager
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.KitScanActivity
import com.example.hpostesting.presentation.adapter.OfflineUserListAdapter
import com.example.hpostesting.presentation.adapter.UserListAdapter
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.example.hpostesting.presentation.testRight.TestRightViewModel
import com.firebase.ui.firestore.FirestoreRecyclerOptions
import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.firestore.Query
import com.google.firebase.firestore.ktx.firestore
import com.google.firebase.ktx.Firebase
import com.google.firebase.perf.ktx.performance
import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentHomeBinding
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
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 var batLevel: Int =
0 // Initialize with a default value, or obtain the actual battery level
private lateinit var adapter: OfflineUserListAdapter
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 ->
deleteIncompleteRegistrations(userData)
}
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userData ->
deleteHemoCubeIncompleteRegistrations(userData)
if (userData.isNotEmpty()) {
val userList = mutableListOf<HemoCubeTestData>()
userData.forEach {
if (it.testStatus == false) {
userList.add(it)
}
}
val bm = requireContext().getSystemService(BATTERY_SERVICE) as BatteryManager
val batLevel: Int = bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
adapter = OfflineUserListAdapter(binding.root, batLevel)
adapter.differ.submitList(userList)
binding.rvOrderOffline.adapter = adapter
}
}
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()
}
}
hemoCubeViewModel.fireBaseBulkUpload.observe(viewLifecycleOwner) { result ->
if (result == "Success") {
Toast.makeText(
requireContext(),
R.string.test_upload,
Toast.LENGTH_SHORT
).show()
}
if (result == "Error") {
Toast.makeText(requireContext(), R.string.test_upload_failed, Toast.LENGTH_SHORT)
.show()
}
}
binding.btnLogout.setOnClickListener {
logoutUser(requireContext())
}
binding.uploadData.setOnClickListener {
showUploadDialog(requireContext())
}
binding.btnNewKit.setOnClickListener {
with(sharedPreference.edit()) {
putString(Constants.KIT_NUMBER, "")
putInt(Constants.KIT_COUNT, 0)
apply()
}
startActivity(Intent(requireContext(), KitScanActivity::class.java))
requireActivity().finish()
}
}
private fun setUserId() {
binding.btnSubmit.setOnClickListener {
val userId = binding.userId.text.toString()
val bloodGroup = binding.etBloodGroup.text
if (userId.length >= 18 && !bloodGroup.equals("Select Blood Group") || !bloodGroup.isNullOrBlank()) {
hemoCubeViewModel.addUser(
HemoCubeTestData(
_id = userId, bloodGroup = bloodGroup.toString(), incubationTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time).toString()
)
)
// 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() {
try {
val dateFormat = SimpleDateFormat("yyyy-MM-dd")
val currentDate = Date()
val formattedDate = dateFormat.format(currentDate)
// val query = Firebase.firestore.collection("patientData")
// .whereGreaterThanOrEqualTo("createdAt", formattedDate)
// .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()
val bm = requireContext().getSystemService(BATTERY_SERVICE) as BatteryManager
val batLevel: Int = bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
rvAdapter = view?.let {
UserListAdapter(
requireContext(), hemoCubeViewModel, recyclerViewOptions,
it, batLevel, requireActivity()
)
}!!
binding.rvOrder.adapter = rvAdapter
rvAdapter.startListening()
} catch (e: Exception) {
Firebase.crashlytics.recordException(e)
}
}
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(R.string.log_out)
builder.setMessage(R.string.do_log_out)
builder.setPositiveButton(R.string.yes) { dialog, _ ->
saveUserId("")
findNavController().navigate(R.id.action_nav_home_to_loginFragment)
dialog.dismiss()
}
builder.setNegativeButton(R.string.no) { dialog, _ ->
dialog.dismiss()
}
val dialog = builder.create()
dialog.show()
}
private fun getData(search: String?, field: String) {
val userSearchTrace = Firebase.performance.newTrace("user_search_trace")
userSearchTrace.start()
search?.replaceFirstChar {
if (search.lowercase()
.startsWith(it.lowercase())
) it.titlecase(Locale.getDefault()) else it.toString()
}
val currentDate = Date()
val dateFormat = SimpleDateFormat("yyyyMMdd")
val partition = dateFormat.format(currentDate)
val searchTerm = partition + search
val searchField = field + "Search"
val query =
Firebase.firestore.collection("patientData").orderBy(searchField).startAt(searchTerm)
.endAt(searchTerm + "\uf8ff")
query.get().addOnSuccessListener {
userSearchTrace.stop()
}
val recyclerViewOptions =
FirestoreRecyclerOptions.Builder<UserData>().setQuery(query, UserData::class.java)
.build()
val bm = requireContext().getSystemService(BATTERY_SERVICE) as BatteryManager
batLevel = bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
rvAdapter = view?.let {
UserListAdapter(
requireContext(),
hemoCubeViewModel,
recyclerViewOptions,
it,
batLevel,
requireActivity()
)
}!!
binding.rvOrder.adapter = rvAdapter
rvAdapter.startListening()
userSearchTrace.stop()
}
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.any { !it.localFlag && it.testStatus == true}) View.VISIBLE else View.GONE
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 ->
userDataList.forEach { userData ->
if (!userData.localFlag) {
userData.localFlag = true
hemoCubeViewModel.bulkAddResultTestToDb(userData)
}
}
dialog.dismiss()
}
}
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._id.isEmpty()) {
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,47 @@
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 = R.string.enter_proper_login_id.toString()
}
if (password.isBlank()) {
binding.password.error = R.string.enter_proper_password.toString()
}
}
}
}
private fun isUserLoggedIn(): Boolean {
return sharedPreference.getString(Constants.USER_ID, "")?.isNotBlank() == true
}
private fun navigateToHomeFragment() {
findNavController().navigate(R.id.action_loginFragment_to_homeFragment)
}
private fun performLogin(loginId: String, password: String) {
val matchingId = Constants.STATICID.firstOrNull { it == loginId }
if (matchingId != null) {
if (password == Constants.password) {
saveUserId(loginId)
navigateToHomeFragment()
return
} else {
Toast.makeText(requireContext(), R.string.wrong_password, Toast.LENGTH_SHORT).show()
}
}
Toast.makeText(requireContext(), R.string.wrong_user_id, Toast.LENGTH_SHORT).show()
}
private fun saveUserId(userId: String) {
with(sharedPreference.edit()) {
putString(Constants.USER_ID, userId)
apply()
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View File

@@ -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,176 @@
package com.example.hpostesting.presentation.diagnostics
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 androidx.appcompat.app.AppCompatActivity
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.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.hemocube.HemoCubeFragment
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
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.ActivityDiagnosticsBinding
@AndroidEntryPoint
class DiagnosticsActivity : AppCompatActivity() {
private lateinit var binding: ActivityDiagnosticsBinding
val viewModel: DiagnosticsViewModel by viewModels()
private var myMenu: Menu? = null
private lateinit var mDriver: UsbSerialDriver
private var mConnection: UsbDeviceConnection? = null
lateinit var mService: UsbService
private val TAG = "HemoCube"
private val broadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
synchronized(this) {
val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
device?.apply {
connectUsb(true)
DataHolder.usbConnected.postValue(true)
}
} else {
onErrorReported("permission denied for device")
DataHolder.usbConnected.postValue(true)
}
}
}
}
private val connection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) {
val binder = service as UsbService.UsbServiceBinder
mService = binder.getService()
viewModel.isServiceConnected = true
mConnection.let { mService.connect(mDriver, mConnection!!) }
moveToNext()
}
override fun onServiceDisconnected(arg0: ComponentName) {
viewModel.isServiceConnected = false
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityDiagnosticsBinding.inflate(layoutInflater)
setContentView(binding.root)
// setSupportActionBar(binding.myToolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
setupListener()
connectUsb(false)
}
private fun setupListener() {
DataHolder.usbConnected.observe(this) {
Log.d("USB OBSERVE", "HemoCube called -> $it")
if (it) {
myMenu?.get(0)?.icon =
ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_24)
} else {
myMenu?.get(0)?.icon =
ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_off_24)
Toast.makeText(this, "Device is Disconnected", Toast.LENGTH_SHORT).show()
}
}
}
open fun connectUsb(permissionGranted: Boolean) {
Log.d(TAG, "connectUsb() called, permission variable = $permissionGranted")
val manager = getSystemService(Context.USB_SERVICE) as UsbManager
val availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager)
if (availableDrivers.isEmpty()) {
onErrorReported("No Device is Connected")
} else {
mDriver = availableDrivers[0]
mConnection = manager.openDevice(mDriver.device)
if (mConnection == null) {
requestUserPermission(manager, mDriver.device)
} else {
setupService()
}
}
}
fun onErrorReported(msg: String) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
if (!isFinishing) onBackPressed()
}
private fun moveToNext() {
if (supportFragmentManager.isDestroyed) return
supportFragmentManager.beginTransaction().replace(binding.fgDiagnostics.id, DiagnosticsFragment())
.commit()
}
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)
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.my_menu, menu)
return true
}
override fun onDestroy() {
super.onDestroy()
if (viewModel.isServiceConnected) {
mService.disconnect()
unbindService(connection)
viewModel.isServiceConnected = false
}
}
}

View File

@@ -0,0 +1,197 @@
package com.example.hpostesting.presentation.diagnostics
import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.MutableLiveData
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.model.diagnostics.DiagnosticsData
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.presentation.UsbServiceListener
import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.ktx.Firebase
import `in`.sminnovations.hpostesting.databinding.FragmentDiagnosticsBinding
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
class DiagnosticsFragment : Fragment() {
private lateinit var binding: FragmentDiagnosticsBinding
private val diagnosticsViewModel: DiagnosticsViewModel by activityViewModels()
private lateinit var sharedPreferences: SharedPreferences
private var currentDeviceData: DeviceData? = null
private var resultData: String = ""
private val messages = MutableLiveData<String>()
private var startListening = MutableLiveData(false)
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
): View {
binding = FragmentDiagnosticsBinding.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()
}
private fun initViews() {
binding.btnSubmit.visibility = View.GONE
listenToHemoCube()
getDeviceId()
binding.btnSubmit.setOnClickListener {
binding.btnSubmit.visibility = View.GONE
runDeviceDiagnostics()
}
}
private fun observeViewModel() {
diagnosticsViewModel.deviceData.observe(viewLifecycleOwner) {
currentDeviceData = it
}
messages.observe(viewLifecycleOwner) {
binding.tvSubtitle4.text = it
Log.e("diagnostics",binding.tvSubtitle4.text.toString())
}
diagnosticsViewModel.fireBaseUpload.observe(viewLifecycleOwner) { result ->
if (result == "Success") {
showToast("Diagnostics data uploaded successfully")
}
if (result == "Local") {
showToast("Diagnostics uploading failed, note it down manually")
}
binding.progressBar.visibility = View.GONE
}
}
private fun getDeviceId() {
diagnosticsViewModel.progressBar.postValue(true)
(activity as DiagnosticsActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.getDeviceId,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
data?.let {
val stringData = String(it)
diagnosticsViewModel.messages.postValue(stringData)
binding.tvSubtitle4.text = stringData
}
}
override fun onUsbError(e: Exception?) {
diagnosticsViewModel.progressBar.postValue(false)
}
})
}
private fun runDeviceDiagnostics() {
diagnosticsViewModel.progressBar.postValue(true)
(activity as DiagnosticsActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.runDiagnostics,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
}
override fun onUsbError(e: Exception?) {
diagnosticsViewModel.progressBar.postValue(false)
}
})
}
private fun listenToHemoCube() {
val fullReadOutput = StringBuilder()
startListening.postValue(true)
try {
(activity as DiagnosticsActivity).mService.listenToHemoCube(object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
data?.let {
val stringData = String(it)
diagnosticsViewModel.messages.postValue(stringData)
fullReadOutput.append(stringData)
resultData += stringData
binding.tvSubtitle4.text = resultData
if (stringData.contains("SN")) {
val slData = stringData.split(" ")
if (slData.size > 1) {
val hardwareId = slData[1].trim()
with(sharedPreferences.edit()) {
putString(Constants.DEVICE_ID, hardwareId)
apply()
}
}
activity?.runOnUiThread {
binding.btnSubmit.visibility = View.VISIBLE
}
}
}
if (resultData.contains("END") || fullReadOutput.contains("END")) {
diagnosticsViewModel.addDiagnosticsDataToDb(DiagnosticsData(
deviceId = sharedPreferences.getString(Constants.DEVICE_ID, "").toString(),
deviceData = resultData,
runTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
))
}
// val inputData = mutableListOf<String>()
// while (true) {
// if (fullReadOutput.toString().lowercase() == "end") {
// break
// }
// inputData.add(fullReadOutput.toString())
// }
//
// val parsedData = parseData(inputData)
// Log.i("D-Data", parsedData.toString())
}
override fun onUsbError(e: Exception?) {
diagnosticsViewModel.progressBar.postValue(false)
}
})
} catch (e: Exception) {
Firebase.crashlytics.recordException(e)
}
}
fun parseData(inputData: List<String>): List<Pair<String, String>> {
val pattern = Regex("([A-Z]+)\\s(\\d+)")
val parsedData = mutableListOf<Pair<String, String>>()
for (item in inputData) {
val matchResult = pattern.find(item)
if (matchResult != null) {
val (letters, numbers) = matchResult.destructured
parsedData.add(Pair(letters, numbers))
}
}
return parsedData
}
private fun showToast(message: String) {
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
}
}

View File

@@ -0,0 +1,65 @@
package com.example.hpostesting.presentation.diagnostics
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.diagnostics.DiagnosticsData
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 DiagnosticsViewModel @Inject constructor(
private val hemoCubeDao: HemoCubeDao,
private val repository: DatabaseRepository,
context: Context
) : ViewModel() {
var isServiceConnected = false
val progressBar = MutableLiveData(false)
val messages = MutableLiveData<String>()
private val sharedPreference: SharedPreferences =
context.getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE)
private val _networkStatusLiveData = NetworkStatusLiveData(context)
val allUserData = hemoCubeDao.getAll()
val deviceData = MutableLiveData<DeviceData?>()
val networkStatusLiveData: LiveData<Boolean>
get() = _networkStatusLiveData
val fireBaseUpload = MutableLiveData<String>()
fun addDiagnosticsDataToDb(data: DiagnosticsData) {
viewModelScope.launch {
try {
when (val response = repository.addDiagnostics(data)) {
is Response.Success -> {
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")
}
}
}
}

View File

@@ -0,0 +1,39 @@
package com.example.hpostesting.presentation.hemocube
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbDeviceConnection
import android.hardware.usb.UsbManager
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.IBinder
import android.view.Menu
import androidx.activity.viewModels
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.presentation.testRight.UsbService
import com.hoho.android.usbserial.driver.UsbSerialDriver
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityDigitalCardBinding
import `in`.sminnovations.hpostesting.databinding.ActivityHemocubeBinding
class DigitalCardActivity : AppCompatActivity() {
private lateinit var binding: ActivityDigitalCardBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityDigitalCardBinding.inflate(layoutInflater)
setContentView(binding.root)
moveToNext()
}
private fun moveToNext() {
if (supportFragmentManager.isDestroyed) return
supportFragmentManager.beginTransaction().replace(binding.fghemocube.id, DigitalCardFragment())
.commit()
}
}

View File

@@ -0,0 +1,83 @@
package com.example.hpostesting.presentation.hemocube
import android.annotation.SuppressLint
import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.activityViewModels
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.model.patient.toHemoCubeTestData
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentDigitalCardBinding
import `in`.sminnovations.hpostesting.databinding.FragmentHemoCubeReferenceBinding
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import java.util.Locale
class DigitalCardFragment : Fragment() {
private lateinit var binding: FragmentDigitalCardBinding
private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels()
private lateinit var sharedPreferences: SharedPreferences
private val testDetails = DataHolder.selectedTest?.toHemoCubeTestData()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
): View {
binding = FragmentDigitalCardBinding.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()
}
@SuppressLint("SetTextI18n")
private fun initViews() {
activity?.runOnUiThread {
binding.progressBar.visibility = View.VISIBLE
}
Log.d("DigitalCardFragment", "Name: ${DataHolder.hemoCubeTestData?.name}")
Log.d("DigitalCardFragment", "DOB: ${testDetails?.birthYear}")
Log.d("DigitalCardFragment", "Gender: ${testDetails?.gender}")
Log.d("DigitalCardFragment", "State: ${testDetails?.state}")
Log.d("DigitalCardFragment", "ABHA ID: ${testDetails?.abhaId}")
Log.d("DigitalCardFragment", "Blood Group: ${testDetails?.bloodGroup}")
Log.d("DigitalCardFragment", "Sickle-Cell: ${testDetails?.classificationResult}")
// Log.d("DigitalCardFragment", "Issue Date: $formattedDate")
activity?.runOnUiThread {
binding.progressBar.visibility = View.GONE
binding.name.text = "Name: ${DataHolder.hemoCubeTestData?.name}"
binding.dob.text = "DOB: ${testDetails?.birthYear}"
binding.gender.text = "Gender: ${testDetails?.gender}"
binding.State.text = "State: ${testDetails?.state}"
binding.abhaid.text = "ABHA ID: ${testDetails?.abhaId}"
binding.blood.text = "Blood Group: ${testDetails?.bloodGroup}"
binding.sicklecell.text = "Sickle-Cell: ${DataHolder.hemoCubeTestData?.prdClassification.toString()}"
}
// Update the UI with the fetched details
val originalDateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
val originalDate: Date? = originalDateFormat.parse(SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time))
// Format the parsed date to "mm date, year"
val desiredDateFormat = SimpleDateFormat("MMM dd, yyyy", Locale.getDefault())
val formattedDate: String = originalDate?.let { desiredDateFormat.format(it) } ?: "N/A"
activity?.runOnUiThread {
binding.issueDate.text = "Issue Date: ${formattedDate}"
}
}
}

View File

@@ -0,0 +1,532 @@
package com.example.hpostesting.presentation.hemocube
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.graphics.Color
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 androidx.lifecycle.MutableLiveData
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.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.ktx.Firebase
import com.google.firebase.perf.ktx.performance
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentHemoCubeReferenceBinding
import kotlin.math.log10
class HemoCubeFragment : Fragment() {
private lateinit var binding: FragmentHemoCubeReferenceBinding
private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels()
private lateinit var sharedPreferences: SharedPreferences
val testDetails = DataHolder.selectedTest?.toHemoCubeTestData()
private var isOnline = false
private var currentDeviceData: DeviceData? = null
private var resultData: String = ""
private var deviceSerialNo: String = ""
private var coefficient: String? = ""
private var isUsingExistingBuffer = false
private var isTestOngoing = false
private var startListening = MutableLiveData<Boolean>(false)
val testingTrace = Firebase.performance.newTrace("testing_trace")
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 {
activity?.runOnUiThread {
binding.progressBar.visibility = View.VISIBLE
}
hemoCubeViewModel.uploadHemoCubeResultToDatabase(
isOnline, true, sharedPreferences.getString(Constants.KIT_NUMBER, "")
)
}
if (isTestOngoing) {
// binding.btnKit.visibility = View.GONE
// binding.btnKit.isEnabled = false
// binding.btnKit.isClickable = false
}
binding.tvTitle2.visibility = View.GONE
binding.etAbhaId.visibility = View.GONE
binding.nameEditText.visibility = View.GONE
binding.tvTitle.visibility = View.GONE
binding.btnGo.visibility = View.GONE
// binding.btnSubmit.isEnabled = false
// binding.btnSubmit.isClickable = false
binding.tvName.text = "Name: ${testDetails?.name}\n ID: ${testDetails?._id}"
Log.e("nametext", binding.tvName.text.toString())
}
private fun observeViewModel() {
hemoCubeViewModel.fireBaseUpload.observe(viewLifecycleOwner) { result ->
if (result == "Success") {
showToast("Test Results Uploaded Successfully")
val i = Intent(
requireContext().applicationContext, DashboardActivity::class.java
)
startActivity(i)
(activity as HemocubeActivity).finish()
}
if (result == "Local") {
showToast("Internet not available, test details stored locally")
startActivity(Intent(requireActivity(), DashboardActivity::class.java))
}
if (result == "Error") {
showToast("Error uploading data, 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 {
// if (isNetworkAvailable) {
// Online mode
DataHolder.hemoCubeTestData?.let {
currentDeviceData?.coefficients?.let { coefficients ->
val coefficient1 = coefficients[0]
val coefficient2 = coefficients[1]
val result = coefficient1 * coefficient2
// Process result in online mode
}
}
// } else {
// // Offline mode
// val coefficient1 = Constants.COEFFICIENTS[deviceSerialNo]?.get(0)?.get(0).toString().toDoubleOrNull() ?: 0.0
// val coefficient2 = Constants.COEFFICIENTS[deviceSerialNo]?.get(1)?.get(0).toString().toDoubleOrNull() ?: 0.0
// val result = coefficient1 * coefficient2
//
// // Process result in offline mode
// }
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 += stringData
when {
stringData.contains("#Buffer Completed") -> showStartSampleDialog()
stringData.contains("#Sample Completed") -> {
fetchResult()
testingTrace.stop()
}
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))
}
})
}
}
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 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()
}
})
}
}
fun handleValidResult(validString: String, fullReadOutput: String) {
try {
val result = validString.split(" ")
val deviceLog = resultData
if (result.size == 8) {
val deviceSerialNo = result[2]
with(sharedPreferences.edit()) {
putString(Constants.DEVICE_ID, deviceSerialNo)
apply()
}
val loginId = sharedPreferences.getString(Constants.USER_ID, "").toString()
if (checkDeviceIdMismatch(deviceSerialNo, loginId)) {
activity?.runOnUiThread {
binding.errorMessage.text = "Warning: Login Id is different"
binding.errorMessage.visibility = View.VISIBLE
}
}
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
val coefficientsList = Constants.COEFFICIENTS[deviceSerialNo]
// if (coefficientsList != null) {
val coefficient1 = coefficientsList?.get(0)?.get(0).toString()
val coefficient2 = coefficientsList?.get(1)?.get(0).toString()
val coefficientsString = "$coefficient1,$coefficient2"
// 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) {
//
// }
// }
// }
// }
if (led1Average < 0 || led2Average < 0) {
activity?.runOnUiThread{
binding.errorMessage.text = "Warning: Negative Abs. Retake Blank Reading"
binding.errorMessage.visibility = View.VISIBLE
}
}
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.coefficients = currentDeviceData?.coefficients?.get(0).toString() + ", " + currentDeviceData?.coefficients?.get(1).toString()
this.coefficients = coefficientsString
this.classificationResult = findResult(calculatedRatio)
hemoCubeViewModel.messages.postValue(this.classificationResult)
this.resultData = deviceLog
if (!isUsingExistingBuffer) {
with(sharedPreferences.edit()) {
putString(Constants.BUFFER_VALUE_1, led1Buffer.toString())
putString(Constants.BUFFER_VALUE_2, led2Buffer.toString())
apply()
}
}
activity?.runOnUiThread {
binding.btnSubmit.visibility = View.VISIBLE
binding.btnSubmit.isEnabled = true
binding.btnSubmit.isClickable = true
binding.clParent.setBackgroundColor(Color.parseColor("#edfffd"))
}
}
}
} 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.05)
return "Inconclusive. Very low Absorbance - Repeat test with Higher Blood Volume"
if (calculatedRatio in 0.05..0.155)
return "Normal"
if (calculatedRatio in 0.155..0.175)
return "Negative Borderline. Repeat Test"
if (calculatedRatio in 0.175..0.22)
return "Sickle Cell Trait"
if (calculatedRatio in 0.22..0.25)
return "Positive for Sickle Cell. HPLC for Confirmation"
if (calculatedRatio in 0.25..0.35)
return "Sickle Cell Disease"
if (calculatedRatio > 0.35)
return "Inconclusive. Repeat with test with lower volume of blood"
} else {
return "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() {
testingTrace.start()
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: Double = (Constants.COEFFICIENTS[deviceSerialNo]?.get(0) ?: 0.0) as Double
val coefficient2: Double = (Constants.COEFFICIENTS[deviceSerialNo]?.get(1) ?: 0.0) as Double
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 checkDeviceIdMismatch(deviceId: String, loginId: String): Boolean {
if (!deviceId.isNullOrEmpty() && !loginId.isNullOrEmpty() && deviceId.last() != loginId.last())
return true
return false
}
}

View File

@@ -0,0 +1,283 @@
package com.example.hpostesting.presentation.hemocube
import android.app.Application
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.SharedPreferences
import android.os.BatteryManager
import android.util.Log
import androidx.lifecycle.AndroidViewModel
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.BufferCheckData
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.example.hpostesting.data.model.patient.toHemoCubeTestData
import com.example.hpostesting.data.repository.DatabaseRepository
import com.example.hpostesting.data.repository.Repository
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: Repository,
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>()
val fireBaseBulkUpload = MutableLiveData<String>()
private val batteryStatus: Intent? =
IntentFilter(Intent.ACTION_BATTERY_CHANGED).let { ifilter ->
context.registerReceiver(null, ifilter)
}
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 uploadHemoCubeResultToDatabaseforbuffercheckN(bufferCheckData: BufferCheckData) =
viewModelScope.launch {
addResultTestToDbforbuffercheck(bufferCheckData)
}
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?.led3Buffer = DataHolder.hemoCubeTestData?.led3Buffer
testDetails?.led4Buffer = DataHolder.hemoCubeTestData?.led4Buffer
testDetails?.led1Sample = DataHolder.hemoCubeTestData?.led1Sample
testDetails?.led2Sample = DataHolder.hemoCubeTestData?.led2Sample
testDetails?.led3Sample = DataHolder.hemoCubeTestData?.led3Sample
testDetails?.led4Sample = DataHolder.hemoCubeTestData?.led4Sample
testDetails?.led1Average = DataHolder.hemoCubeTestData?.led1Average
testDetails?.led2Average = DataHolder.hemoCubeTestData?.led2Average
testDetails?.led3Average = DataHolder.hemoCubeTestData?.led3Average
testDetails?.led4Average = DataHolder.hemoCubeTestData?.led4Average
testDetails?.abs1 = DataHolder.hemoCubeTestData?.abs1
testDetails?.abs2 = DataHolder.hemoCubeTestData?.abs2
testDetails?.abs3 = DataHolder.hemoCubeTestData?.abs3
testDetails?.abs4 = DataHolder.hemoCubeTestData?.abs4
testDetails?.deviceRatio = DataHolder.hemoCubeTestData?.deviceRatio
testDetails?.predictedDenovixRatio = DataHolder.hemoCubeTestData?.predictedDenovixRatio
testDetails?.calculatedRatio = DataHolder.hemoCubeTestData?.calculatedRatio
testDetails?.coefficients = DataHolder.hemoCubeTestData?.coefficients
testDetails?.classificationResult = DataHolder.hemoCubeTestData?.classificationResult!!
testDetails?.prdClassification =
DataHolder.hemoCubeTestData?.prdClassification.toString()
testDetails?.batteryLevel = DataHolder.hemoCubeTestData?.batteryLevel.toString()
testDetails?.batteryCapacity = DataHolder.hemoCubeTestData?.batteryCapacity.toString()
testDetails?.batteryMaxCapacity =
DataHolder.hemoCubeTestData?.batteryMaxCapacity.toString()
testDetails?.batteryTemperature =
DataHolder.hemoCubeTestData?.batteryTemperature.toString()
testDetails?.batteryVoltage = DataHolder.hemoCubeTestData?.batteryVoltage.toString()
}
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")
testDetails.localFlag = true
hemoCubeDao.insertAll(testDetails)
}
is Response.Error -> {
Log.e("Testdb", "Error uploading data to Firestore: $response")
fireBaseUpload.postValue("Error")
hemoCubeDao.insertAll(testDetails)
}
else -> {}
}
} catch (e: Exception) {
Log.e("Testdb", "Exception during data upload: ${e.message}")
fireBaseUpload.postValue("Error")
}
}
}
private fun addResultTestToDbforbuffercheck(bufferCheckData: BufferCheckData) {
viewModelScope.launch {
try {
when (val response =
repository.addTestToDatabaseforBufferCheck(bufferCheckData)) {
is Response.Success -> {
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")
}
else -> {}
}
} 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 -> {
fireBaseBulkUpload.postValue("Success")
updateLocalFlag(userData._id)
}
else -> {
fireBaseBulkUpload.postValue("Error")
}
}
}
}
private fun updateLocalFlag(userId: String) = viewModelScope.launch {
hemoCubeDao.updateFieldById(id = userId, true)
}
fun addUser(userData: HemoCubeTestData) = viewModelScope.launch {
hemoCubeDao.insertAll(userData)
}
fun deleteById(userId: String) = viewModelScope.launch {
hemoCubeDao.deleteById(id = userId)
}
fun getBatteryLevel(): Float? {
val batteryPct: Float? = batteryStatus?.let { intent ->
val level: Int = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
val scale: Int = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
level * 100 / scale.toFloat()
}
return batteryPct
}
fun getBatteryTemperature(): Float? {
val batteryTemp: Float? = batteryStatus?.let { intent ->
val temperature = intent?.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0) ?: 0
temperature.toFloat() / 10
}
return batteryTemp
}
fun getBatteryVoltage(context: Context): Float {
val batteryIntent =
context.registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
val voltage = batteryIntent?.getIntExtra(BatteryManager.EXTRA_VOLTAGE, 0) ?: 0
// milli-volts to volts
return voltage.toFloat() / 1000
}
fun getBatteryCapacity(context: Context): Int {
val batteryManager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
val currentCapacity =
batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER)
return currentCapacity
}
fun getBatteryMaxCapacity(context: Context): Float {
val batteryManager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
val designCapacity =
batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
val currentCapacity =
batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER)
// Calculate the estimated maximum battery capacity in mAh
val maxCapacity = currentCapacity.toFloat() / designCapacity.toFloat() * 100
return maxCapacity
}
}

View File

@@ -0,0 +1,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,65 +66,45 @@ class TestRightExpSample : Fragment() {
}
binding.btnSubmit.setOnClickListener {
val details = validateAndReturnPatientData()
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 validateAndReturnPatientData(): PatientData? {
val name = binding.etName.editText?.text?.trim()
if (name.isNullOrEmpty()) {
binding.etName.error = getString(R.string.name_error)
return null
} else {
val regex = Regex("[|\\\\?*<\":>+\\[\\]'/]")
if (regex.containsMatchIn(name)){
binding.etName.error = getString(R.string.name_error_2)
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()
}
@@ -148,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(
@@ -178,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?) {
@@ -185,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()
@@ -221,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) {
@@ -246,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 com.example.hpostesting.presentation.dashboard.DashboardActivity
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.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,68 @@
package com.example.hpos.presentation.testRight
package com.example.hpostesting.presentation.testRight
import android.content.Context
import android.util.Log
import android.net.Uri
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 +70,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 +86,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 +95,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 +108,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 +119,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 +132,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 +255,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 +268,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 +302,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 +330,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 +358,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 +399,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)
}
}
}

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