Compare commits

...

201 Commits

Author SHA1 Message Date
Kaif
2c2b4aa9c7 Result API, NATS and work manager 2024-01-06 16:32:00 +05:30
Mariya
ae42c96256 Toast Message is Added, if the device is connected 2024-01-03 15:31:58 +05:30
Kaif
d362a7fa86 Merge remote-tracking branch 'origin/preprod-temp' into preprod-temp 2024-01-03 12:53:45 +05:30
Kaif
e8b380a4c4 Added pending API calls, like upload log, result upload and device update 2024-01-03 12:52:27 +05:30
Mariya
4b205185d3 error resolved related to previous changing color of text if the result is normal 2023-12-29 11:10:38 +05:30
Kaif
00a3124fbf API call for DeviceProvision and Login is completed and tested 2023-12-26 14:16:19 +05:30
Mariya
0faf4adbd7 ADDED CODE FOR Changing Text color from red to green if the result is normal 2023-12-26 12:59:44 +05:30
Pritimay Sarkar
d1b5ca32bf fix msg fragmentation in app and add log dsiplay for admin 2023-12-18 12:48:07 +05:30
Pritimay Sarkar
3e690345c2 handle-msg-fragmentation 2023-12-15 14:37:41 +05:30
Pritimay Sarkar
4f7aa74314 Merge branch 'v2-hardware-config' into preprod 2023-12-15 10:32:56 +05:30
Pritimay Sarkar
590abb5c73 Merge branch 'preprod' 2023-12-15 10:29:48 +05:30
Pritimay Sarkar
7fe8202968 add config error msg and v2 usb config 2023-12-15 10:22:50 +05:30
Kaif
11d4c99e02 Changes for new Arduieno Device 2023-12-14 16:56:39 +05:30
Pritimay Sarkar
2e700601fe release 2.1.52 for qa 2023-12-14 14:53:53 +05:30
Mariya
41798aa37b Digital Card button removed 2023-12-14 13:07:15 +05:30
Mariya
e7600dafec gradle version changed 2023-12-14 12:43:10 +05:30
Mariya
d6b3df25f8 gradle version changed 2023-12-13 20:53:34 +05:30
Mariya
0d7e8b0cd0 Merge remote-tracking branch 'origin/preprod' into preprod 2023-12-13 18:57:03 +05:30
Mariya
3c8570c46b gradle version changed 2023-12-13 18:56:40 +05:30
Pritimay Sarkar
96f9d4d6da coeffs for dev4 2023-12-13 18:55:41 +05:30
Mariya
e7505077ce Merge remote-tracking branch 'origin/preprod' into preprod
# Conflicts:
#	app/src/main/java/com/example/hpostesting/presentation/dashboard/DashboardActivity.kt
2023-12-12 12:21:52 +05:30
Kaif
41e30cf178 Incremented the version number for giving testing release 2023-12-08 13:59:07 +05:30
Pritimay Sarkar
a34c095fde Merge remote-tracking branch 'origin/Feature_Develop_the_feature_to_shift_between_multiple_languages_in_testing_app' into preprod 2023-12-08 13:55:07 +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
a3a5c0d6fb pending strings added 2023-12-04 15:49:39 +05:30
Kaif
fb5e6f3b49 Fixed string error 2023-12-01 16:22:13 +05:30
Kaif
8a22b44496 Added app version 2023-12-01 16:10:15 +05:30
Kaif
10d822c5d6 Kannada and Hindi language support added 2023-12-01 15:55:49 +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
110 changed files with 5995 additions and 866 deletions

2
.idea/gradle.xml generated
View File

@@ -5,7 +5,6 @@
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<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">
@@ -14,6 +13,7 @@
<option value="$PROJECT_DIR$/app" />
</set>
</option>
<option name="resolveExternalAnnotations" value="false" />
</GradleProjectSettings>
</option>
</component>

43
.idea/misc.xml generated
View File

@@ -1,43 +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_auto_graph_24.xml" value="0.1555" />
<entry key="app/src/main/res/drawable/ic_baseline_cancel_24.xml" value="0.1965" />
<entry key="app/src/main/res/drawable/ic_baseline_check_circle_24.xml" value="0.243" />
<entry key="app/src/main/res/drawable/ic_baseline_dot_24.xml" value="0.1785" />
<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_graph.xml" value="0.19791666666666666" />
<entry key="app/src/main/res/layout/fragment_test_right_exp_reference.xml" value="0.25" />
<entry key="app/src/main/res/layout/fragment_test_right_exp_sample.xml" value="0.24583333333333332" />
<entry key="app/src/main/res/layout/fragment_test_right_exp_scanner.xml" value="0.24583333333333332" />
<entry key="app/src/main/res/layout/fragment_test_right_process.xml" value="0.24375" />
<entry key="app/src/main/res/layout/fragment_test_right_results.xml" value="0.30512820512820515" />
<entry key="app/src/main/res/layout/table_item.xml" value="0.22407407407407406" />
<entry key="app/src/main/res/menu/menu.xml" value="0.25" />
<entry key="app/src/main/res/menu/my_menu.xml" value="0.25" />
<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_17" project-jdk-name="jbr-17" 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

@@ -14,12 +14,13 @@ android {
compileSdk 34
namespace 'in.sminnovations.hpostesting'
// prod - production, preprod - preproduction, quality - qc
defaultConfig {
applicationId "in.sminnovations.hpostesting"
minSdk 21
targetSdk 34
versionCode 2
versionName "2.0.1"
versionCode 56
versionName "2.1.56"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@@ -48,43 +49,64 @@ android {
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.10.1'
implementation 'androidx.core:core-ktx:1.12.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.9.0'
implementation 'com.google.android.material:material:1.11.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.1'
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.6.0'
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'
implementation 'com.google.android.play:core:1.10.3'
// 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.6.1"
implementation 'com.opencsv:opencsv:4.6'
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2"
implementation 'com.opencsv:opencsv:5.5'
implementation 'com.github.mik3y:usb-serial-for-android:3.5.1'
implementation "androidx.fragment:fragment-ktx:1.6.1"
implementation "androidx.fragment:fragment-ktx:1.6.2"
// CSV read, write
implementation 'com.opencsv:opencsv:4.6'
implementation 'com.opencsv:opencsv:5.5'
// Barcode scanner
implementation 'com.journeyapps:zxing-android-embedded:4.3.0'
@@ -93,25 +115,32 @@ dependencies {
implementation 'com.google.android.gms:play-services-code-scanner:16.1.0'
//Room
implementation "androidx.room:room-ktx:2.6.0-beta01"
implementation "androidx.room:room-runtime:2.6.0-beta01"
kapt ("androidx.room:room-compiler:2.6.0-beta01")
implementation "androidx.room:room-ktx:2.6.1"
implementation "androidx.room:room-runtime:2.6.1"
kapt ("androidx.room:room-compiler:2.6.1")
//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.1"
implementation "androidx.navigation:navigation-ui-ktx:2.7.1"
implementation "androidx.navigation:navigation-fragment-ktx:2.7.6"
implementation "androidx.navigation:navigation-ui-ktx:2.7.6"
//Dagger - Hilt
implementation "com.google.dagger:hilt-android:2.46"
kapt "com.google.dagger:hilt-android-compiler:2.46"
kapt "androidx.hilt:hilt-compiler:1.0.0"
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"
implementation("com.squareup.okhttp3:okhttp:4.9.3")
implementation "androidx.preference:preference-ktx:1.2.1"
implementation 'io.nats:jnats:2.11.2'
implementation("androidx.work:work-runtime-ktx:2.9.0")
implementation("io.nats:jnats:2.11.2")
}

View File

@@ -5,6 +5,9 @@
<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" />
@@ -13,8 +16,11 @@
<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"
@@ -26,6 +32,12 @@
android:supportsRtl="true"
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"
@@ -33,6 +45,13 @@
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"
@@ -42,7 +61,8 @@
android:name="com.example.hpostesting.presentation.dashboard.DashboardActivity"
android:exported="false"
android:label="@string/title_activity_dashboard"
android:theme="@style/Theme.HPOS.NoActionBar" />
android:theme="@style/Theme.HPOS.NoActionBar"
tools:ignore="MissingClass" />
<service
android:name="com.example.hpostesting.presentation.testRight.UsbService"

View File

@@ -0,0 +1 @@
BASE_URL= https://datacollection.micropcr.com/api/

View File

@@ -5,6 +5,8 @@ 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
@@ -15,5 +17,14 @@ import javax.inject.Singleton
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

@@ -1,46 +0,0 @@
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,7 @@
package com.example.hpostesting.data
sealed class Result<out T : Any> {
data class Success<out T : Any>(val data: T) : Result<T>()
data class Error(val exception: Exception) : Result<Nothing>()
class Loading<T : Any> : Result<T>()
}

View File

@@ -0,0 +1,21 @@
package com.example.hpostesting.data.api
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionRequest
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionResponse
import com.example.hpostesting.data.model.login.LoginRequest
import com.example.hpostesting.data.model.login.LoginResponse
import retrofit2.http.Body
import retrofit2.http.POST
interface MolbioAuthApi {
@POST("deviceManagement/device/provision")
suspend fun deviceProvision(
@Body deviceProvisionRequest: DeviceProvisionRequest
): DeviceProvisionResponse
@POST("deviceService/device/login")
suspend fun login(
@Body loginRequest: LoginRequest
): LoginResponse
}

View File

@@ -0,0 +1,39 @@
package com.example.hpostesting.data.api
import com.example.hpostesting.data.model.log.UploadLogsResponse
import com.example.hpostesting.data.model.molbioresult.MolbioV2ResultRequest
import com.example.hpostesting.data.model.molbioresult.MolbioV2ResultResponse
import com.example.hpostesting.data.model.updates.CheckUpdateRequest
import com.example.hpostesting.data.model.updates.CheckUpdateResponse
import com.example.hpostesting.data.model.updates.DeviceUpdateRequest
import okhttp3.MultipartBody
import okhttp3.ResponseBody
import retrofit2.http.Body
import retrofit2.http.Multipart
import retrofit2.http.POST
import retrofit2.http.PUT
import retrofit2.http.Part
interface MolbioResultApi {
@PUT("deviceService/results/HPOS")
suspend fun uploadResults(
@Body molbioV2ResultRequest: MolbioV2ResultRequest
): MolbioV2ResultResponse
@POST("deviceService/device/checkUpdate")
suspend fun checkUpdate(
@Body checkUpdateRequest: CheckUpdateRequest
): CheckUpdateResponse
@POST("deviceService/device/getUpdate")
suspend fun deviceUpdate(
@Body deviceUpdateRequest: DeviceUpdateRequest
): ResponseBody
@Multipart
@POST("deviceService/device/uploadLogs")
suspend fun uploadLogs(
@Part logFile: MultipartBody.Part
): UploadLogsResponse
}

View File

@@ -0,0 +1,6 @@
package com.example.hpostesting.data.api
interface PropertyProvider {
fun getProperty(key: String): String
}

View File

@@ -4,8 +4,22 @@ 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 BASE_URL = "www.google.com"
const val ABHA_APP_PACKAGE = "in.ndhm.phr"
const val serialNumber = "NKH5555AH"
const val deviceTypeName = "HPOS"
const val uid = "NKH5555AH"
const val deviceProvisionEmail = "HPOS_provisioner@bigtec.co.in"
const val deviceProvisionPassword = "f2ab0e7f9d69"
const val deviceID = "HCV-000-3001"
const val devicePassword = "810516d8f4c7"
const val ACCESS_TOKEN = "accessToken"
const val NATS_TOKEN = "natsToken"
const val NATS_TOKEN_EXPIRE_DATE = "natsTokenExpireDate"
const val WRITE_TIMEOUT_MILLIS = 30000 // 30 sec
const val READ_TIMEOUT_MILLIS = 60000 // 1 min
const val DELAY_BETWEEN_COMMANDS: Long = 1000
@@ -29,6 +43,8 @@ object Constants {
const val DEVICE_VENDOR_ID = 1027
const val HOMO_CUBE_ID = 29987
const val VENDOR_ID = 6790
const val HEMO_CUBE_V2_PRODUCT_ID = 24577
const val HEMO_CUBE_V2_VENDOR_ID = 1027
const val ERROR_NORMAL = 400
const val ERROR_CRITICAL = 401
@@ -38,6 +54,7 @@ object Constants {
const val USER_ID = "usernameId"
val STATICID = listOf(
"ADMIN",
"VIZ-1000-0004",
"VIZ-1000-0005",
"VIZ-1000-0006",
@@ -47,6 +64,30 @@ object Constants {
"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",
"HCV-000-3003",
"HCV-000-3004",
"HCV-000-3005",
"HCV-000-3006",
"HCV-000-3007",
"HCV-000-3008",
"HCV-000-3009",
"HCV-000-3010"
)
const val password = "SMI@12345"
@@ -55,4 +96,153 @@ object Constants {
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
const val TEST_STATUS_CODE_TEST_STARTED = 1.0
const val TEST_STATUS_CODE_CONFIG_STARTED = 2.0
const val TEST_STATUS_CODE_CONFIG_COMPLETED = 3.0
const val TEST_STATUS_CODE_BUFFER_STARTED = 4.0
const val TEST_STATUS_CODE_BUFFER_COMPLETED = 5.0
const val TEST_STATUS_CODE_BUFFER_PRINT_STARTED = 6.0
const val TEST_STATUS_CODE_BUFFER_PRINT_COMPLETED = 7.0
const val TEST_STATUS_CODE_SAMPLE_STARTED = 8.0
const val TEST_STATUS_CODE_SAMPLE_COMPLETED = 9.0
const val TEST_STATUS_CODE_SAMPLE_PRINT_STARTED = 10.0
const val TEST_STATUS_CODE_SAMPLE_PRINT_COMPLETED = 11.0
const val TEST_STATUS_CODE_TEST_COMPLETED = 12.0
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
),
"HCV-000-3003" 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
),
"HCV-000-3004" to listOf(
listOf(1.7272, -1.1977), // LED1, 435nm
listOf(0.581462456, -0.58502), // LED2, 415nm
listOf(0.2304, -0.0145), // LED3, 555nm
listOf(1.0, 0.0) // LED4
),
"HCV-000-3005" to listOf(
listOf(1.7272, -1.1977), // LED1, 435nm
listOf(0.581462456, -0.58502), // LED2, 415nm
listOf(0.2304, -0.0145), // LED3, 555nm
listOf(1.0, 0.0) // LED4
),
"HCV-000-3006" to listOf(
listOf(1.7272, -1.1977), // LED1, 435nm
listOf(0.581462456, -0.58502), // LED2, 415nm
listOf(0.2304, -0.0145), // LED3, 555nm
listOf(1.0, 0.0) // LED4
),
"HCV-000-3007" to listOf(
listOf(1.7272, -1.1977), // LED1, 435nm
listOf(0.581462456, -0.58502), // LED2, 415nm
listOf(0.2304, -0.0145), // LED3, 555nm
listOf(1.0, 0.0) // LED4
),
"HCV-000-3008" to listOf(
listOf(1.7272, -1.1977), // LED1, 435nm
listOf(0.581462456, -0.58502), // LED2, 415nm
listOf(0.2304, -0.0145), // LED3, 555nm
listOf(1.0, 0.0) // LED4
),
"HCV-000-3009" to listOf(
listOf(1.7272, -1.1977), // LED1, 435nm
listOf(0.581462456, -0.58502), // LED2, 415nm
listOf(0.2304, -0.0145), // LED3, 555nm
listOf(1.0, 0.0) // LED4
),
"HCV-000-3010" to listOf(
listOf(1.7272, -1.1977), // LED1, 435nm
listOf(0.581462456, -0.58502), // LED2, 415nm
listOf(0.2304, -0.0145), // LED3, 555nm
listOf(1.0, 0.0) // LED4
),
)
const val INCUBATION_TIME_MIN = 0
const val INCUBATION_TIME_MAX = 1400
const val BATTERY_LEVEL_MIN = 0
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),
),
"HCV-000-3003" to listOf(
listOf(24500, 26250),
listOf(24500, 26250),
listOf(24500, 26250),
listOf(24500, 26250),
),
"HCV-000-3004" to listOf(
listOf(24500, 26250),
listOf(24500, 26250),
listOf(24500, 26250),
listOf(24500, 26250),
),
"HCV-000-3005" to listOf(
listOf(24500, 26250),
listOf(24500, 26250),
listOf(24500, 26250),
listOf(24500, 26250),
),
"HCV-000-3006" to listOf(
listOf(24500, 26250),
listOf(24500, 26250),
listOf(24500, 26250),
listOf(24500, 26250),
),
"HCV-000-3007" to listOf(
listOf(24500, 26250),
listOf(24500, 26250),
listOf(24500, 26250),
listOf(24500, 26250),
),
"HCV-000-3008" to listOf(
listOf(24500, 26250),
listOf(24500, 26250),
listOf(24500, 26250),
listOf(24500, 26250),
),
"HCV-000-3009" to listOf(
listOf(24500, 26250),
listOf(24500, 26250),
listOf(24500, 26250),
listOf(24500, 26250),
),
"HCV-000-3010" to listOf(
listOf(24500, 26250),
listOf(24500, 26250),
listOf(24500, 26250),
listOf(24500, 26250),
)
)
}

View File

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

View File

@@ -0,0 +1,30 @@
package com.example.hpostesting.data.constant
import android.content.Context
import android.content.SharedPreferences
import java.util.Locale
object LanguageManager {
private const val LANGUAGE_PREF_KEY = "language_pref"
fun setLocale(context: Context, languageCode: String) {
val locale = Locale(languageCode)
Locale.setDefault(locale)
val resources = context.resources
val configuration = resources.configuration
configuration.setLocale(locale)
context.createConfigurationContext(configuration)
}
fun persistLanguagePreference(context: Context, languageCode: String) {
val prefs: SharedPreferences = context.getSharedPreferences("AppPrefs", Context.MODE_PRIVATE)
prefs.edit().putString(LANGUAGE_PREF_KEY, languageCode).apply()
}
fun getSavedLanguage(context: Context): String {
val prefs: SharedPreferences = context.getSharedPreferences("AppPrefs", Context.MODE_PRIVATE)
return prefs.getString(LANGUAGE_PREF_KEY, "en") ?: "en"
}
}

View File

@@ -9,15 +9,21 @@ import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.UserData
@Dao
interface HemoCubeDao {
@Query("SELECT * from HemocubeTest_table")
@Query("SELECT * from hemo_cube_test_table")
fun getAll(): LiveData<List<HemoCubeTestData>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAll(hemoCubeTestData: HemoCubeTestData)
@Query("SELECT * FROM hemocubetest_table WHERE _id = :id")
@Query("SELECT * FROM hemo_cube_test_table WHERE _id = :id")
suspend fun getUserByID(id: String): HemoCubeTestData
@Query("DELETE FROM hemocubetest_table WHERE _id = :id")
@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)
@Query("UPDATE hemo_cube_test_table SET molbioFlag = :newValue WHERE _id = :id")
suspend fun updateMolbioFlag(id: String, newValue: Boolean)
}

View File

@@ -11,7 +11,7 @@ import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.google.android.datatransport.runtime.dagger.Provides
import javax.inject.Singleton
@Database(entities = [UserData::class, HemoCubeTestData::class, DeviceData::class], version = 3, exportSchema = false)
@Database(entities = [UserData::class, HemoCubeTestData::class, DeviceData::class], version = 15, exportSchema = false)
@TypeConverters(Converters::class)
abstract class MyDatabase : RoomDatabase() {
abstract fun userDao(): UserDao

View File

@@ -0,0 +1,6 @@
package com.example.hpostesting.data.model.deviceprovision
data class Credentials(
val password: String? = "",
val username: String? = ""
)

View File

@@ -0,0 +1,17 @@
package com.example.hpostesting.data.model.deviceprovision
data class Device(
val assigned: Boolean? = false,
val createdAt: String? = "",
val createdBy: Int? = 0,
val deviceType: DeviceType? = DeviceType(),
val deviceTypeId: Int? = 0,
val deviceUser: DeviceUser? = DeviceUser(),
val enabled: Boolean? = false,
val id: Int? = 0,
val name: String? = "",
val serialNumber: String? = "",
val uid: String? = "",
val updatedAt: String? = "",
val updatedBy: Int? = 0
)

View File

@@ -0,0 +1,6 @@
package com.example.hpostesting.data.model.deviceprovision
data class DeviceProvisionData(
val credentials: Credentials? = Credentials(),
val device: Device? = Device()
)

View File

@@ -0,0 +1,9 @@
package com.example.hpostesting.data.model.deviceprovision
data class DeviceProvisionRequest(
val deviceTypeName: String? = "",
val email: String? = "",
val password: String? = "",
val serialNumber: String? = "",
val uid: String? = ""
)

View File

@@ -0,0 +1,12 @@
package com.example.hpostesting.data.model.deviceprovision
import com.google.gson.annotations.SerializedName
data class DeviceProvisionResponse(
@SerializedName("Data")
val data: DeviceProvisionData? = DeviceProvisionData(),
@SerializedName("Message")
val message: String? = "",
@SerializedName("Result")
val result: String? = ""
)

View File

@@ -0,0 +1,12 @@
package com.example.hpostesting.data.model.deviceprovision
data class DeviceType(
val createdAt: String? = "",
val createdBy: Int? = 0,
val description: String? = "",
val enabled: Boolean? = false,
val id: Int? = 0,
val name: String? = "",
val updatedAt: String? = "",
val updatedBy: Int? = 0
)

View File

@@ -0,0 +1,15 @@
package com.example.hpostesting.data.model.deviceprovision
data class DeviceUser(
val createdAt: String? = "",
val createdBy: Int? = 0,
val deviceId: Int? = 0,
val enabled: Boolean? = false,
val id: Int? = 0,
val lastLogin: Any? = Any(),
val natsToken: String? = "",
val natsTokenExpiry: String? = "",
val updatedAt: String? = "",
val updatedBy: Int? = 0,
val username: String? = ""
)

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,5 @@
package com.example.hpostesting.data.model.log
data class UploadLogsData(
val filename: String? = ""
)

View File

@@ -0,0 +1,12 @@
package com.example.hpostesting.data.model.log
import com.google.gson.annotations.SerializedName
data class UploadLogsResponse(
@SerializedName("Data")
val data: UploadLogsData? = UploadLogsData(),
@SerializedName("Message")
val message: String? = "",
@SerializedName("Result")
val result: String? = ""
)

View File

@@ -0,0 +1,16 @@
package com.example.hpostesting.data.model.login
data class Device(
val assigned: Boolean? = false,
val createdAt: String? = "",
val createdBy: Int? = 0,
val deviceType: DeviceType? = DeviceType(),
val deviceTypeId: Int? = 0,
val enabled: Boolean? = false,
val id: Int? = 0,
val name: String? = "",
val serialNumber: String? = "",
val uid: String? = "",
val updatedAt: String? = "",
val updatedBy: Int? = 0
)

View File

@@ -0,0 +1,12 @@
package com.example.hpostesting.data.model.login
data class DeviceType(
val createdAt: String? = "",
val createdBy: Int? = 0,
val description: String? = "",
val enabled: Boolean? = false,
val id: Int? = 0,
val name: String? = "",
val updatedAt: String? = "",
val updatedBy: Int? = 0
)

View File

@@ -0,0 +1,16 @@
package com.example.hpostesting.data.model.login
data class DeviceUser(
val createdAt: String? = "",
val createdBy: Int? = 0,
val device: Device? = Device(),
val deviceId: Int? = 0,
val enabled: Boolean? = false,
val id: Int? = 0,
val lastLogin: String? = "",
val natsToken: String? = "",
val natsTokenExpiry: String? = "",
val updatedAt: String? = "",
val updatedBy: Int? = 0,
val username: String? = ""
)

View File

@@ -0,0 +1,6 @@
package com.example.hpostesting.data.model.login
data class LoginData(
val accessToken: String? = "",
val deviceUser: DeviceUser? = DeviceUser()
)

View File

@@ -0,0 +1,12 @@
package com.example.hpostesting.data.model.login
data class LoginRequest(
val lab: String? = "",
val latitude: String? = "",
val location: String? = "",
val longitude: String? = "",
val mode: String? = "",
val password: String? = "",
val serialNumber: String? = "",
val username: String? = ""
)

View File

@@ -0,0 +1,12 @@
package com.example.hpostesting.data.model.login
import com.google.gson.annotations.SerializedName
data class LoginResponse(
@SerializedName("Data")
val data: LoginData? = LoginData(),
@SerializedName("Message")
val message: String? = "",
@SerializedName("Result")
val result: String? = ""
)

View File

@@ -0,0 +1,38 @@
package com.example.hpostesting.data.model.molbioresult
import com.example.hpostesting.data.model.patient.HemoCubeTestData
data class MolbioV2Result(
val age: Int? = 31,
val analysisDate: String? = "",
val analysisId: String? = "",
val analysisStatus: String? = "",
val analysisType: String? = "HPOS",
val analysisTypeMethod: String? = "",
val bloodGroup: String? = "",
val coefficients: List<Int>? = listOf(22, 22),
val collectionLocation: List<Any>? = listOf(),
val collectionTime: String? = "",
val collector: String? = "",
val curveFitting: String? = "Linear",
val deviceName: String? = "HPOS",
val expiryTime: String? = "",
val gender: String? = "",
val interpretation: String? = "",
val `operator`: String? = "",
val patientId: Int? = 4545,
val pregnancy: Boolean? = false,
val rawData: HemoCubeTestData? = HemoCubeTestData(),
val recommendation: String? = "NA",
val sampleId: String? = "",
val sampleType: String? = "",
val sickleCellHistory: Boolean? = false,
val testId: String? = "",
val testResult: String? = "",
val testStatus: String? = "",
val testTime: String? = "",
val testType: String? = "",
val thresholds: String? = "",
val underMedication: Boolean? = false,
val volume: Int? = 2
)

View File

@@ -0,0 +1,42 @@
package com.example.hpostesting.data.model.molbioresult
import com.example.hpostesting.data.model.patient.HemoCubeTestData
data class MolbioV2ResultData(
val age: Int? = 0,
val analysisDate: String? = "",
val analysisStatus: String? = "",
val analysisType: String? = "",
val analysisTypeMethod: String? = "",
val bloodGroup: String? = "",
val coefficients: List<Int>? = listOf(),
val collectionLocation: List<Any>? = listOf(),
val collectionTime: String? = "",
val collector: String? = "",
val createdAt: String? = "",
val createdBy: Int? = 0,
val curveFitting: String? = "",
val deviceId: Int? = 0,
val expiryTime: String? = "",
val gender: String? = "",
val id: Int? = 0,
val interpretation: String? = "",
val `operator`: String? = "",
val patientId: Int? = 0,
val pregnancy: Boolean? = false,
val rawData: HemoCubeTestData? = HemoCubeTestData(),
val recommendation: String? = "",
val sampleId: String? = "",
val sampleType: String? = "",
val sickleCellHistory: Boolean? = false,
val testId: String? = "",
val testResult: String? = "",
val testStatus: String? = "",
val testTime: String? = "",
val testType: String? = "",
val thresholds: String? = "",
val underMedication: Boolean? = false,
val updatedAt: String? = "",
val updatedBy: Int? = 0,
val volume: Int? = 0
)

View File

@@ -0,0 +1,5 @@
package com.example.hpostesting.data.model.molbioresult
data class MolbioV2ResultRequest(
val results: List<MolbioV2Result>? = listOf()
)

View File

@@ -0,0 +1,12 @@
package com.example.hpostesting.data.model.molbioresult
import com.google.gson.annotations.SerializedName
data class MolbioV2ResultResponse(
@SerializedName("Data")
val data: List<MolbioV2ResultData>? = listOf(),
@SerializedName("Message")
val message: String? = "",
@SerializedName("Result")
val result: String? = ""
)

View File

@@ -0,0 +1,55 @@
package com.example.hpostesting.data.model.molbioresult
import com.example.hpostesting.data.model.patient.UserData
data class RawData(
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,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

@@ -3,18 +3,23 @@ package com.example.hpostesting.data.model.patient
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "HemocubeTest_table")
@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? = "",
@@ -24,10 +29,31 @@ data class HemoCubeTestData(
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 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 = "",
var molbioFlag: Boolean = false
)

View File

@@ -9,8 +9,12 @@ 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? = "",
@@ -18,12 +22,14 @@ data class UserData(
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 resultRatio: Double? = null,
var prdClassification: String = ""
) {
enum class Gender {
MALE,
@@ -43,5 +49,11 @@ fun UserData.toHemoCubeTestData() = HemoCubeTestData(
birthYear = birthYear,
userImageURL = userImageURL,
testStatus = testStatus,
location = location
location = location,
gender = gender,
state = state,
abhaId = abhaId,
bloodGroup = bloodGroup,
prdClassification = prdClassification,
testTime = testTime
)

View File

@@ -1,55 +0,0 @@
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,11 +0,0 @@
package com.example.hpostesting.data.model.test
data class TestInfo(
val value: String,
val number1: String,
val number2: String,
val result: String,
val resultConfirmatory: String,
val directoryPath: String,
val fullPath: String
)

View File

@@ -0,0 +1,5 @@
package com.example.hpostesting.data.model.updates
data class CheckUpdateData(
val version: String? = ""
)

View File

@@ -0,0 +1,5 @@
package com.example.hpostesting.data.model.updates
data class CheckUpdateRequest(
val currentVersion: String? = ""
)

View File

@@ -0,0 +1,12 @@
package com.example.hpostesting.data.model.updates
import com.google.gson.annotations.SerializedName
data class CheckUpdateResponse(
@SerializedName("Data")
val data: CheckUpdateData? = CheckUpdateData(),
@SerializedName("Message")
val message: String? = "",
@SerializedName("Result")
val result: String? = ""
)

View File

@@ -0,0 +1,5 @@
package com.example.hpostesting.data.model.updates
data class DeviceUpdateRequest(
val serial_no: String? = ""
)

View File

@@ -1,75 +1,150 @@
package com.example.hpostesting.data.repository
import android.content.Context
import android.net.Uri
import androidx.room.Room
import com.example.hpostesting.data.dao.MyDatabase
import com.example.hpostesting.data.Result
import com.example.hpostesting.data.api.MolbioAuthApi
import com.example.hpostesting.data.api.MolbioResultApi
import com.example.hpostesting.data.model.PendingUploads
import com.example.hpostesting.data.model.Response
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionRequest
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionResponse
import com.example.hpostesting.data.model.diagnostics.DiagnosticsData
import com.example.hpostesting.data.model.log.UploadLogsResponse
import com.example.hpostesting.data.model.login.LoginRequest
import com.example.hpostesting.data.model.login.LoginResponse
import com.example.hpostesting.data.model.molbioresult.MolbioV2ResultRequest
import com.example.hpostesting.data.model.molbioresult.MolbioV2ResultResponse
import com.example.hpostesting.data.model.patient.BufferCheckData
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.UserData
import com.google.android.datatransport.runtime.dagger.Provides
import com.example.hpostesting.data.model.updates.CheckUpdateRequest
import com.example.hpostesting.data.model.updates.CheckUpdateResponse
import com.example.hpostesting.data.model.updates.DeviceUpdateRequest
import com.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.Dispatchers
import kotlinx.coroutines.tasks.await
import kotlinx.coroutines.withContext
import okhttp3.MultipartBody
import okhttp3.ResponseBody
import java.io.File
import javax.inject.Singleton
import java.net.ConnectException
import java.net.SocketTimeoutException
import javax.inject.Inject
import javax.inject.Named
class DatabaseRepository : Repository {
class NetworkException(message: String, cause: Throwable) : Exception(message, cause)
class DatabaseRepository @Inject constructor(
@Named("Auth")private val molbioAuthApi: MolbioAuthApi,
private val molbioResultApi: MolbioResultApi
) : Repository {
private val db: FirebaseFirestore = Firebase.firestore
private val storage = Firebase.storage
suspend fun addTestToDatabase(data: HemoCubeTestData?): Response<String> {
private suspend fun <T : Any> safeApiCall(apiCall: suspend () -> T): Result<T> {
return try {
val userdata = db.collection("patientData").whereEqualTo("_id", data!!._id).get().await()
val response = apiCall.invoke()
Result.Success(response)
} catch (e: SocketTimeoutException) {
Result.Error(NetworkException("Network timeout", e))
} catch (e: ConnectException) {
Result.Error(NetworkException("Network connection failed", e))
} catch (e: Exception) {
Result.Error(e)
}
}
suspend fun deviceProvision(deviceProvisionRequest: DeviceProvisionRequest): Result<DeviceProvisionResponse> {
return safeApiCall { molbioAuthApi.deviceProvision(deviceProvisionRequest) }
}
suspend fun login(loginRequest: LoginRequest): Result<LoginResponse> {
return safeApiCall { molbioAuthApi.login(loginRequest) }
}
suspend fun uploadResults(molbioV2ResultRequest: MolbioV2ResultRequest): Result<MolbioV2ResultResponse> {
return safeApiCall { molbioResultApi.uploadResults(molbioV2ResultRequest) }
}
suspend fun checkUpdate(checkUpdateRequest: CheckUpdateRequest): Result<CheckUpdateResponse> {
return safeApiCall { molbioResultApi.checkUpdate(checkUpdateRequest) }
}
suspend fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest): Result<ResponseBody> {
return safeApiCall { molbioResultApi.deviceUpdate(deviceUpdateRequest) }
}
suspend fun uploadLogs(logFile: MultipartBody.Part): Result<UploadLogsResponse> {
return safeApiCall { molbioResultApi.uploadLogs(logFile) }
}
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)
db.collection("testData").add(data).await()
Response.Success(data._id)
} catch (e: Exception) {
Response.Error(e)
}
}
suspend fun addTestToDatabase(data: UserData?): Response<String> {
override suspend fun addTestToDatabase(data: UserData?): Response<String> {
return try {
val userdata = db.collection("patientData").whereEqualTo("_id", data!!._id).get().await()
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)
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)
}
}
suspend fun uploadFileToStorage(patientID: String, filePath: String): Response<Boolean> {
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) {
e.printStackTrace()
Firebase.crashlytics.recordException(e)
return Response.Error(e)
}
}
@@ -81,7 +156,7 @@ class DatabaseRepository : Repository {
Response.Success(true)
} catch (e: Exception) {
e.printStackTrace()
Firebase.crashlytics.recordException(e)
Response.Error(e)
}
}
@@ -100,7 +175,7 @@ class DatabaseRepository : Repository {
pendingList
} catch (e: Exception) {
e.printStackTrace()
Firebase.crashlytics.recordException(e)
pendingList
}
}
@@ -111,7 +186,7 @@ class DatabaseRepository : Repository {
Response.Success(true)
} catch (e: Exception) {
e.printStackTrace()
Firebase.crashlytics.recordException(e)
Response.Error(e)
}
}
@@ -120,15 +195,11 @@ class DatabaseRepository : Repository {
return db.collection("devices").get().await().toObjects(DeviceData::class.java)
}
suspend fun getDeviceDataById(deviceId: String): DeviceData? {
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

@@ -1,5 +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 addToDatabase(data: PatientDetails)
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

@@ -0,0 +1,23 @@
package com.example.hpostesting.domain
import android.content.SharedPreferences
import com.example.hpostesting.data.constant.Constants
import okhttp3.Interceptor
import okhttp3.Response
class AuthInterceptor(private val sharedPreferences: SharedPreferences) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
var request = chain.request()
val token = sharedPreferences.getString(Constants.ACCESS_TOKEN, null)
if (token != null) {
request = request.newBuilder()
.addHeader("Authorization", "Bearer $token")
.build()
}
return chain.proceed(request)
}
}

View File

@@ -0,0 +1,28 @@
package com.example.hpostesting.domain
import android.content.Context
import android.util.Log
import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.withContext
class CheckUpdateWorker(
context: Context,
workerParams: WorkerParameters
) : CoroutineWorker(context, workerParams) {
override suspend fun doWork(): Result = withContext(Dispatchers.IO) {
try {
for (i in 1..900){
delay(1000)
Log.d("Work for every second", "doWork: Running")
}
Result.success()
} catch (e: Exception) {
Result.failure()
}
}
}

View File

@@ -0,0 +1,38 @@
package com.example.hpostesting.domain
import android.content.Context
import android.util.Log
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
class LogFileManager(private val context: Context) {
fun createLogFile(): File? {
val unixTime = System.currentTimeMillis() / 1000L
val logFileName = "hpos_$unixTime.log"
return try {
val process = Runtime.getRuntime().exec("logcat -d -v threadtime")
val logBuilder = StringBuilder()
val input = process.inputStream
val bufferedReader = input.bufferedReader()
bufferedReader.forEachLine { line ->
logBuilder.append(line).append("\n")
}
val logContent = logBuilder.toString()
val file = File(context.filesDir, logFileName)
val fileOutputStream = FileOutputStream(file)
fileOutputStream.write(logContent.toByteArray())
fileOutputStream.close()
file
} catch (e: IOException) {
Log.e("LogFileManager", "Error creating log file: ${e.message}")
null
}
}
}

View File

@@ -2,20 +2,34 @@ package com.example.hpostesting.domain.di
import android.app.Application
import android.content.Context
import android.content.SharedPreferences
import android.content.res.AssetManager
import androidx.room.Room
import com.example.hpostesting.data.api.MolbioAuthApi
import com.example.hpostesting.data.api.MolbioResultApi
import com.example.hpostesting.data.api.PropertyProvider
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.AuthInterceptor
import com.example.hpostesting.domain.LogFileManager
import com.example.hpostesting.domain.SaveRawData
import com.example.hpostesting.domain.SaveRawDataTest
import com.example.hpostesting.util.PropertyProviderImpl
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit
import javax.inject.Named
import javax.inject.Singleton
@Module
@@ -27,9 +41,7 @@ object AppModule {
fun provideMyDatabase(@ApplicationContext context: Context): MyDatabase {
return Room.databaseBuilder(
context, MyDatabase::class.java, "my_database"
)
.fallbackToDestructiveMigration()
.build()
).fallbackToDestructiveMigration().build()
}
@Provides
@@ -66,7 +78,89 @@ object AppModule {
@Provides
@Singleton
fun provideDatabaseRepository(): DatabaseRepository {
return DatabaseRepository()
fun provideDatabaseRepository(
@Named("Auth") molbioAuthApi: MolbioAuthApi,
molbioResultApi: MolbioResultApi
): DatabaseRepository {
return DatabaseRepository(molbioAuthApi = molbioAuthApi, molbioResultApi = molbioResultApi)
}
@Provides
@Singleton
fun provideRepository(
@Named("Auth") molbioAuthApi: MolbioAuthApi,
molbioResultApi: MolbioResultApi
): Repository {
return DatabaseRepository(molbioAuthApi, molbioResultApi)
}
@Provides
@Singleton
fun provideAssetManager(@ApplicationContext context: Context): AssetManager {
return context.assets
}
@Provides
@Singleton
fun providePropertyProvider(assetManager: AssetManager): PropertyProvider {
return PropertyProviderImpl(assetManager)
}
@Provides
@Singleton
fun provideSharedPreferences(@ApplicationContext context: Context): SharedPreferences {
return context.getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE)
}
@Provides
@Singleton
fun provideAuthInterceptor(sharedPreferences: SharedPreferences): AuthInterceptor {
return AuthInterceptor(sharedPreferences)
}
@Provides
@Singleton
@Named("Auth")
fun provideAuthOkHttpClient(authInterceptor: AuthInterceptor): OkHttpClient {
return OkHttpClient.Builder().addInterceptor(authInterceptor)
.connectTimeout(30, TimeUnit.SECONDS).readTimeout(30, TimeUnit.SECONDS).build()
}
@Provides
@Singleton
fun provideOkHttpClient(): OkHttpClient =
OkHttpClient.Builder().connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS).build()
@Provides
@Singleton
fun provideRetrofit(
propertyProvider: PropertyProvider,@Named("Auth") client: OkHttpClient
): Retrofit {
return Retrofit.Builder().baseUrl(propertyProvider.getProperty("BASE_URL")).client(client)
.addConverterFactory(GsonConverterFactory.create()).build()
}
@Provides
@Singleton
@Named("Auth")
fun provideAuthRetrofit(propertyProvider: PropertyProvider, client: OkHttpClient): Retrofit {
return Retrofit.Builder().baseUrl(propertyProvider.getProperty("BASE_URL")).client(client)
.addConverterFactory(GsonConverterFactory.create()).build()
}
@Provides
@Singleton
@Named("Auth")
fun provideAuthApi(@Named("Auth") retrofit: Retrofit): MolbioAuthApi =
retrofit.create(MolbioAuthApi::class.java)
@Provides
@Singleton
fun provideResultApi(retrofit: Retrofit): MolbioResultApi =
retrofit.create(MolbioResultApi::class.java)
@Provides
@Singleton
fun provideLogFileManager(context: Context): LogFileManager = LogFileManager(context)
}

View File

@@ -1,17 +1,22 @@
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.dashboard.DashboardActivity
import com.example.hpostesting.data.constant.LanguageManager
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
@@ -29,7 +34,7 @@ class KitScanActivity : AppCompatActivity() {
ScanContract()
) { result: ScanIntentResult ->
if (result.contents.isNullOrEmpty()) {
Toast.makeText(this, "Cancelled: Unable to scan, Try Again!!", Toast.LENGTH_LONG).show()
Toast.makeText(this, R.string.cancelled_unable_scan, Toast.LENGTH_LONG).show()
} else {
Log.d(TAG, result.contents)
processScannedData(result.contents)
@@ -40,6 +45,12 @@ class KitScanActivity : AppCompatActivity() {
binding.nameEditText.setText(contents)
}
override fun attachBaseContext(newBase: Context?) {
val languageCode = LanguageManager.getSavedLanguage(newBase!!)
LanguageManager.setLocale(newBase, languageCode)
super.attachBaseContext(newBase)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -52,11 +63,28 @@ class KitScanActivity : AppCompatActivity() {
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)
@@ -65,6 +93,17 @@ class KitScanActivity : AppCompatActivity() {
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/")
@@ -77,7 +116,42 @@ class KitScanActivity : AppCompatActivity() {
binding.btnGo.setOnClickListener {
val serialNumber = binding.nameEditText.text.toString().trim()
if (serialNumber.isNotEmpty() && checkDataNotNull() && isSerialValid(serialNumber)) {
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()) {
@@ -87,15 +161,16 @@ class KitScanActivity : AppCompatActivity() {
}
moveToNext()
} else {
Toast.makeText(this, "Invalid KIT Number", Toast.LENGTH_LONG).show()
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
?.isNotBlank() == true && sharedPreference.getInt(
Constants.KIT_COUNT, 0
) > 0 && sharedPreference.getInt(Constants.KIT_COUNT, 0) < 35
}
private fun isSerialValid(s: String): Boolean {
@@ -142,7 +217,7 @@ class KitScanActivity : AppCompatActivity() {
private fun checkDataNotNull(): Boolean {
return if (DataHolder.selectedTest?._id == null) {
Toast.makeText(
applicationContext, "Please Select patient before starting test", Toast.LENGTH_SHORT
applicationContext, R.string.select_patient, Toast.LENGTH_SHORT
).show()
val i = Intent(applicationContext, DashboardActivity::class.java)

View File

@@ -1,5 +1,6 @@
package com.example.hpostesting.presentation
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import android.Manifest
import android.content.*
import android.content.pm.PackageManager
@@ -9,8 +10,6 @@ import android.os.Bundle
import android.util.Log
import android.view.Menu
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
@@ -18,9 +17,12 @@ 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.constant.LanguageManager
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
@@ -43,6 +45,12 @@ class MainActivity : AppCompatActivity() {
}
}
override fun attachBaseContext(newBase: Context?) {
val languageCode = LanguageManager.getSavedLanguage(newBase!!)
LanguageManager.setLocale(newBase, languageCode)
super.attachBaseContext(newBase)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
@@ -83,17 +91,10 @@ class MainActivity : AppCompatActivity() {
}
}
// val crashButton = Button(this)
// crashButton.text = "Test Crash"
// crashButton.setOnClickListener {
// throw RuntimeException("Test Crash") // Force a crash
// }
//
// addContentView(crashButton, ViewGroup.LayoutParams(
// ViewGroup.LayoutParams.MATCH_PARENT,
// ViewGroup.LayoutParams.WRAP_CONTENT))
if (DataHolder.selectedTest == null) {
startActivity(Intent(this, DashboardActivity::class.java))
finish()
}
}
private fun checkAndUpdateUsbConnection() {
@@ -103,6 +104,7 @@ class MainActivity : AppCompatActivity() {
val deviceType = when {
availableDrivers.isNotEmpty() -> {
val device = availableDrivers[0].device
Toast.makeText(this, R.string.device, Toast.LENGTH_SHORT).show()
when {
device.productId == Constants.HOMO_CUBE_ID && device.vendorId == Constants.VENDOR_ID -> {
binding.cvItem1.visibility = View.VISIBLE
@@ -113,6 +115,15 @@ class MainActivity : AppCompatActivity() {
Constants.DEVICE_TYPE_HOMOCUBE
}
device.productId == Constants.HEMO_CUBE_V2_PRODUCT_ID && device.vendorId == Constants.HEMO_CUBE_V2_VENDOR_ID -> {
binding.cvItem1.visibility = View.VISIBLE
binding.cvItem3.visibility = View.VISIBLE
binding.cvItem2.visibility = View.GONE
binding.cvItem4.visibility = View.GONE
DataHolder.deviceType.postValue(Constants.DEVICE_TYPE_HOMOCUBE)
Constants.DEVICE_TYPE_HOMOCUBE
}
device.productId == Constants.DEVICE_PRODUCT_ID && device.vendorId == Constants.DEVICE_VENDOR_ID -> {
Log.d(
TAG,
@@ -142,7 +153,7 @@ class MainActivity : AppCompatActivity() {
else -> {
Log.d(TAG, "Device NOT Connected")
Toast.makeText(this, "Device Not Connected", Toast.LENGTH_SHORT).show()
Toast.makeText(this, R.string.device_not, Toast.LENGTH_SHORT).show()
DataHolder.usbConnected.value = false
null
}
@@ -159,12 +170,14 @@ class MainActivity : AppCompatActivity() {
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) {
@@ -228,24 +241,52 @@ class MainActivity : AppCompatActivity() {
) != PackageManager.PERMISSION_GRANTED
) {
// Handle location permission request if needed
Toast.makeText(this, "Please enable location services", Toast.LENGTH_SHORT).show()
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() {
@@ -287,7 +328,7 @@ class MainActivity : AppCompatActivity() {
requestFineLocationPermission()
} else {
// Coarse location permission denied
Toast.makeText(this, "Coarse location permission denied", Toast.LENGTH_SHORT)
Toast.makeText(this, R.string.coarse_location_denied, Toast.LENGTH_SHORT)
.show()
}
}
@@ -298,7 +339,7 @@ class MainActivity : AppCompatActivity() {
getLocation()
} else {
// Fine location permission denied
Toast.makeText(this, "Fine location permission denied", Toast.LENGTH_SHORT)
Toast.makeText(this, R.string.location_denied, Toast.LENGTH_SHORT)
.show()
}
}

View File

@@ -0,0 +1,134 @@
package com.example.hpostesting.presentation
import android.util.Log
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import io.nats.client.AuthHandler
import io.nats.client.Connection
import io.nats.client.Message
import io.nats.client.NKey
import io.nats.client.Nats
import io.nats.client.Options
import java.io.IOException
import java.nio.charset.StandardCharsets
import java.security.GeneralSecurityException
class NatsManager(datacollector: DashboardActivity) {
val TAG = "Nats Service"
var nc: Connection? = null
val datacollector = datacollector
var connect = false
fun connect() {
Log.d(TAG, "TRY TO CONNECT")
Thread {
val seedString = "SUAK5IDCMHY4T2WA2LHNXGICGHKR3TPJFNSP6AUQP523RLANO4PSR6IEYA"
val seedBytes = seedString.toCharArray()
val theNKey = NKey.fromSeed(seedBytes) // really should load from somewhere
val options = Options.Builder()
.server("nats://192.168.10.117:4222")
.authHandler(object : AuthHandler {
override fun getID(): CharArray? {
return try {
theNKey?.publicKey
} catch (ex: GeneralSecurityException) {
null
} catch (ex: IOException) {
null
} catch (ex: NullPointerException) {
null
}
}
override fun sign(nonce: ByteArray): ByteArray? {
return try {
theNKey?.sign(nonce)
} catch (ex: GeneralSecurityException) {
null
} catch (ex: IOException) {
null
} catch (ex: NullPointerException) {
null
}
}
override fun getJWT(): CharArray? {
return null
}
})
.build()
try {
nc = Nats.connect(options)
Log.d(TAG, "Connected to Nats server ${options.servers.first()}")
connect = true
datacollector.setConnect(true)
nc?.publish(
"server.hpos.HCV-000-3001.ping",
"ALIVE".toByteArray(StandardCharsets.UTF_8)
)
nc?.publish(
"server.hpos.HCV-000-3001.health",
"ALIVE".toByteArray(StandardCharsets.UTF_8)
)
Log.d(TAG, "Published msg server.hpos.HCV-000-3001.ping on topic Testing")
val d = nc?.createDispatcher { msg: Message? ->
println("PRITIMOI SARKAR $msg")
}
d?.subscribe("device.hpos.HCV-000-3001.update") { msg ->
val response = String(msg.data, StandardCharsets.UTF_8)
datacollector. setResponse(response)
println("Message received (up to 100 times): $response")
}
d?.subscribe("device.hpos.HCV-000-3001.uploadlogs") { msg ->
val response = String(msg.data, StandardCharsets.UTF_8)
datacollector.setResponse(response + "uPLOAD")
println("Message received (up to 100 times): $response")
}
d?.subscribe("device.hpos.HCV-000-3001.disable") { msg ->
val response = String(msg.data, StandardCharsets.UTF_8)
datacollector.setResponse(response)
println("Message received (up to 100 times): $response")
}
d?.subscribe("device.hpos.HCV-000-3001.updatecustomer") { msg ->
val response = String(msg.data, StandardCharsets.UTF_8)
datacollector.setResponse(response)
println("Message received (up to 100 times): $response")
}
d?.subscribe("device.hpos.HCV-000-3001.checkupdate") { msg ->
val response = String(msg.data, StandardCharsets.UTF_8)
datacollector.setResponse(response)
println("Message received (up to 100 times): $response")
}
} catch (exp: Exception) {
println(exp.printStackTrace())
connect = false
datacollector.setConnect(true)
}
}.start()
}
fun pub(topic: String, msg: String) {
nc?.publish(topic, msg.toByteArray(StandardCharsets.UTF_8))
Log.d(TAG, "Published msg ${msg} on topic ${topic}")
}
fun close() {
nc?.close()
Log.d(TAG, "Nats connection close")
}
}

View File

@@ -1,6 +1,8 @@
package com.example.hpostesting.presentation
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import android.Manifest
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
@@ -13,11 +15,9 @@ import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.util.MyUtils
import com.google.firebase.firestore.FirebaseFirestoreSettings
import com.google.firebase.firestore.ktx.firestore
import com.google.firebase.ktx.Firebase
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivitySplashBinding
class SplashActivity : AppCompatActivity() {
@@ -34,12 +34,18 @@ class SplashActivity : AppCompatActivity() {
private var allPermissionsGranted = false
override fun attachBaseContext(newBase: Context?) {
val languageCode = LanguageManager.getSavedLanguage(newBase!!)
LanguageManager.setLocale(newBase, languageCode)
super.attachBaseContext(newBase)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivitySplashBinding.inflate(layoutInflater)
setContentView(binding.root)
setupFirestoreCache()
// setupFirestoreCache()
setupStaticConstants()
requestPermissions()
@@ -50,12 +56,12 @@ class SplashActivity : AppCompatActivity() {
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 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) {
@@ -77,7 +83,7 @@ class SplashActivity : AppCompatActivity() {
} else {
Toast.makeText(
this,
"You must grant permission to access all files to use the app",
R.string.permission_grant,
Toast.LENGTH_SHORT
).show()
finish()
@@ -139,7 +145,7 @@ class SplashActivity : AppCompatActivity() {
if (allGranted) {
moveToLandingPage()
} else {
Toast.makeText(this, "All permissions are required to use the app.", Toast.LENGTH_SHORT).show()
Toast.makeText(this, R.string.permission_required, Toast.LENGTH_SHORT).show()
finish()
}
}

View File

@@ -0,0 +1,125 @@
package com.example.hpostesting.presentation.adapter
import android.content.Context
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
}
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: ${userList.incubationTime}"
userCard.setOnClickListener {
if (batLevel < 40) {
Toast.makeText(
view.context,
context?.getString(R.string.low_battery_warning),
Toast.LENGTH_SHORT
).show()
return@setOnClickListener
}
if (userList.testStatus != null) {
if (userList.testStatus!!) {
Toast.makeText(
view.context,
context?.getString(R.string.test_already_conducted),
Toast.LENGTH_SHORT
).show()
} else {
if (userList.incubationTime != "") {
if (isBetween15And30Minutes(userList.incubationTime) < Constants.INCUBATION_TIME_MIN) {
Toast.makeText(
view.context,
context?.getString(R.string.incubation_not_completed),
Toast.LENGTH_SHORT
).show()
} else if (isBetween15And30Minutes(userList.incubationTime) > Constants.INCUBATION_TIME_MAX) {
Toast.makeText(
view.context,
context?.getString(R.string.incubation_crossed_30_minutes),
Toast.LENGTH_SHORT
).show()
} else {
DataHolder.selectedTest = UserData(
_id = userList._id,
bloodGroup = userList.bloodGroup,
incubationTime = userList.incubationTime
)
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

@@ -1,6 +1,10 @@
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
@@ -10,17 +14,31 @@ import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.presentation.testRight.TestRightViewModel
import com.firebase.ui.firestore.FirestoreRecyclerAdapter
import com.firebase.ui.firestore.FirestoreRecyclerOptions
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.UserItemViewBinding
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.data.constant.Constants
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
) :
FirestoreRecyclerAdapter<UserData, UserListAdapter.OrderItemViewHolder>(options) {
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)
@@ -36,27 +54,206 @@ class UserListAdapter(
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 = "Test concluded"
teststatus.text = view.context.getString(R.string.test_concluded)
} else {
teststatus.text = "Test is Pending"
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(R.string.blood_group)
val etBloodGroup = dialogView.findViewById<AutoCompleteTextView>(R.id.et_blood_group)
builder.setPositiveButton(R.string.ok) { dialog, which ->
val bloodGroup = etBloodGroup.text.toString()
if (bloodGroup.equals("Select Blood Group") ||bloodGroup.equals("ರಕ್ತ ಗುಂಪು ಆಯ್ಕೆಮಾಡಿ") || bloodGroup.isNullOrBlank()) {
if (view != null) {
etBloodGroup.error =view.context.getString(R.string.blood_group_error)
}
if (view != null) {
Toast.makeText(context, view.context.getString(R.string.blood_group_toast), Toast.LENGTH_SHORT).show()
}
} else {
// Check if hemoCubeViewModel and testDetails are not null
val db: FirebaseFirestore = FirebaseFirestore.getInstance()
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(R.string.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 (false) {
Toast.makeText(
view.context,
context?.getString(R.string.low_battery_warning),
Toast.LENGTH_SHORT
).show()
return@setOnClickListener
}
if (model.testStatus != null) {
if (model.testStatus!!) {
Toast.makeText(
view.context,
"Test has been already conducted for this user",
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)
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,171 @@
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.data.constant.LanguageManager
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 attachBaseContext(newBase: Context?) {
val languageCode = LanguageManager.getSavedLanguage(newBase!!)
LanguageManager.setLocale(newBase, languageCode)
super.attachBaseContext(newBase)
}
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

@@ -1,7 +1,10 @@
package com.example.hpostesting.presentation.dashboard
import android.content.Context
import android.os.Bundle
import android.util.Log
import android.view.Menu
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.drawerlayout.widget.DrawerLayout
import androidx.navigation.findNavController
@@ -9,24 +12,45 @@ import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.navigateUp
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.presentation.NatsManager
import com.google.android.material.navigation.NavigationView
import com.google.android.material.progressindicator.LinearProgressIndicator
import com.google.android.play.core.appupdate.AppUpdateManager
import com.google.android.play.core.appupdate.AppUpdateManagerFactory
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
open interface IDataCollector {
fun setConnect(connect: Boolean)
fun setResponse(response: String)
}
@AndroidEntryPoint
class DashboardActivity : AppCompatActivity() {
class DashboardActivity : AppCompatActivity(), IDataCollector {
private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var binding: ActivityDashboardBinding
var responses: String = ""
lateinit var nats: NatsManager
override fun attachBaseContext(newBase: Context?) {
val languageCode = LanguageManager.getSavedLanguage(newBase!!)
LanguageManager.setLocale(newBase, languageCode)
super.attachBaseContext(newBase)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityDashboardBinding.inflate(layoutInflater)
setContentView(binding.root)
setSupportActionBar(binding.appBarDashboard.toolbar)
nats = NatsManager(this)
// nats.connect()
// nats.pub("server.hpos.HCV-000-3001.ping", "THIS IS A TEST MSG")
val drawerLayout: DrawerLayout = binding.drawerLayout
val navView: NavigationView = binding.navView
@@ -53,4 +77,55 @@ class DashboardActivity : AppCompatActivity() {
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()
}
}
override fun setConnect(connect: Boolean) {
if(connect){
Log.i("NATS Connection", connect.toString())
}
}
override fun setResponse(response: String) {
responses = responses+response+"\n"
println(responses)
}
}

View File

@@ -1,12 +1,13 @@
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 androidx.lifecycle.ViewModelProvider
//import com.example.hpostesting.presentation.dashboard.ui.gallery.GalleryViewModel
import com.example.hpostesting.presentation.buffercheck.HemocubeBufferCheckActivity
import com.example.hpostesting.presentation.diagnostics.DiagnosticsActivity
import `in`.sminnovations.hpostesting.databinding.FragmentGalleryBinding
class GalleryFragment : Fragment() {
@@ -25,13 +26,22 @@ class GalleryFragment : Fragment() {
// val galleryViewModel =
// ViewModelProvider(this).get(GalleryViewModel::class.java)
// _binding = FragmentGalleryBinding.inflate(inflater, container, false)
_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
}

View File

@@ -2,9 +2,13 @@ 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.util.Base64
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -13,18 +17,31 @@ 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.Result
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.model.login.LoginRequest
import com.example.hpostesting.data.model.login.LoginResponse
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.data.model.updates.CheckUpdateRequest
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 org.json.JSONObject
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import java.util.Locale
@AndroidEntryPoint
@@ -34,26 +51,51 @@ class HomeFragment : Fragment() {
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 {
): View? {
_binding = FragmentHomeBinding.inflate(inflater, container, false)
sharedPreference = requireContext().getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE)
// Check if _binding is null
if (_binding == null) {
// Handle the case where binding could not be initialized
// You may want to log an error or return a default view in this case
return super.onCreateView(inflater, container, savedInstanceState)
}
sharedPreference =
requireContext().getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE)
DataHolder.selectedTest = null
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.allUserData.observe(viewLifecycleOwner) { userData ->
if (userData.isNotEmpty()) {
}
deleteIncompleteRegistrations(userData)
}
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userData ->
deleteHemoCubeIncompleteRegistrations(userData)
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) {
@@ -62,26 +104,182 @@ class HomeFragment : Fragment() {
loadUserData()
setSearch()
checkForLocalDBData()
checkForTokenAndUpdate()
} 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 checkForTokenAndUpdate() {
val accessToken = sharedPreference.getString(Constants.ACCESS_TOKEN, "").toString()
val natsToken = sharedPreference.getString(Constants.NATS_TOKEN, "").toString()
val natsTokenExpireDate = sharedPreference.getString(Constants.NATS_TOKEN_EXPIRE_DATE, "").toString()
if (accessToken.isEmpty() && natsToken.isEmpty()) {
hemoCubeViewModel.login(createLoginRequestData())
} else {
if (isTokenExpired(accessToken)) {
hemoCubeViewModel.login(createLoginRequestData())
} else {
hemoCubeViewModel.checkUpdate(createCheckUpdateRequestData())
hemoCubeViewModel.uploadLogs()
hemoCubeViewModel.startPeriodicCheckUpdate()
}
}
hemoCubeViewModel.loginResponse.observe(viewLifecycleOwner) { response ->
when (response) {
is Result.Success -> {
updateTokens(response)
checkForTokenAndUpdate()
}
is Result.Error -> {
response.exception.let { message ->
Toast.makeText(activity, "An error occurred: $message", Toast.LENGTH_LONG)
.show()
}
}
is Result.Loading -> {
}
else -> {}
}
}
hemoCubeViewModel.checkUpdate.observe(viewLifecycleOwner) { response ->
when (response) {
is Result.Success -> {
Toast.makeText(
requireContext(), response.data.data?.version, Toast.LENGTH_SHORT
).show()
}
is Result.Error -> {
response.exception.let { message ->
Toast.makeText(activity, "An error occurred: $message", Toast.LENGTH_LONG)
.show()
}
}
is Result.Loading -> {
}
else -> {}
}
}
hemoCubeViewModel.uploadLogs.observe(viewLifecycleOwner) { response ->
when (response) {
is Result.Success -> {
Toast.makeText(
requireContext(),
"Log uploaded ${response.data.data?.filename}",
Toast.LENGTH_SHORT
).show()
}
is Result.Error -> {
response.exception.let { message ->
Toast.makeText(activity, "An error occurred: $message", Toast.LENGTH_LONG)
.show()
}
}
is Result.Loading -> {
}
else -> {}
}
}
}
fun isTokenExpired(token: String): Boolean {
val parts = token.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val decodedPayload = String(Base64.decode(parts[1], Base64.DEFAULT))
val jsonPayload = JSONObject(decodedPayload)
val exp = jsonPayload.optLong("exp", 0)
val currentTimeSeconds = System.currentTimeMillis() / 1000
return exp <= currentTimeSeconds
}
private fun updateTokens(response: Result.Success<LoginResponse>) {
with(sharedPreference.edit()) {
putString(Constants.ACCESS_TOKEN, response.data.data?.accessToken)
putString(Constants.NATS_TOKEN, response.data.data?.deviceUser?.natsToken)
putString(Constants.NATS_TOKEN_EXPIRE_DATE, response.data.data?.deviceUser?.natsTokenExpiry)
apply()
}
}
private fun createLoginRequestData(): LoginRequest {
return LoginRequest(
password = Constants.devicePassword,
serialNumber = Constants.deviceID,
username = Constants.deviceID
)
}
private fun createCheckUpdateRequestData(): CheckUpdateRequest {
val pInfo = requireActivity().packageManager.getPackageInfo(
requireActivity().packageName, 0
)
val version = pInfo.versionName
return CheckUpdateRequest(
currentVersion = version
)
}
private fun setUserId() {
binding.btnSubmit.setOnClickListener {
val userId = binding.userId.text.toString()
if (userId.length >= 18) {
val userData = UserData(_id = userId)
DataHolder.selectedTest = userData
findNavController().navigate(R.id.action_nav_home_to_mainActivity)
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()
@@ -89,8 +287,16 @@ class HomeFragment : Fragment() {
}
}
}
private fun loadUserData() {
val query = Firebase.firestore.collection("patientData").whereEqualTo("testStatus", false)
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
@@ -101,48 +307,95 @@ class HomeFragment : Fragment() {
val recyclerViewOptions =
FirestoreRecyclerOptions.Builder<UserData>().setQuery(query, UserData::class.java)
.build()
rvAdapter = UserListAdapter(recyclerViewOptions, binding.root)
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("Log Out")
builder.setMessage("Do you want to LogOut the Application?")
builder.setPositiveButton("Yes") { dialog, _ ->
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("No") { dialog, _ ->
builder.setNegativeButton(R.string.no) { dialog, _ ->
dialog.dismiss()
}
val dialog = builder.create()
dialog.show()
}
private fun getData(search: String?, field: String) {
val capitalizedSearch = search?.replaceFirstChar {
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 query = Firebase.firestore.collection("patientData").orderBy(field).startAt(search)
.endAt(search + "\uf8ff")
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()
rvAdapter = UserListAdapter(recyclerViewOptions, binding.root)
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 {
@@ -154,13 +407,16 @@ class HomeFragment : Fragment() {
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 {
@@ -178,6 +434,7 @@ class HomeFragment : Fragment() {
}
})
}
private fun checkForLocalDBData() {
viewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
val uploadDataVisibility = if (userDataList.isEmpty()) View.GONE else View.VISIBLE
@@ -185,10 +442,12 @@ class HomeFragment : Fragment() {
}
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
val uploadDataVisibility = if (userDataList.isEmpty()) View.GONE else View.VISIBLE
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)
@@ -217,28 +476,19 @@ class HomeFragment : Fragment() {
}
dialog.dismiss()
Toast.makeText(
requireContext(),
R.string.upload_success_message,
Toast.LENGTH_SHORT
requireContext(), R.string.upload_success_message, Toast.LENGTH_SHORT
).show()
}
}
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
if (userDataList.isEmpty()) {
dialog.dismiss()
} else {
userDataList.forEach { userData ->
if (!userData.localFlag) {
userData.localFlag = true
hemoCubeViewModel.bulkAddResultTestToDb(userData)
}
dialog.dismiss()
Toast.makeText(
requireContext(),
R.string.upload_success_message,
Toast.LENGTH_SHORT
).show()
}
dialog.dismiss()
}
}
@@ -252,7 +502,7 @@ class HomeFragment : Fragment() {
private fun deleteHemoCubeIncompleteRegistrations(userDataList: List<HemoCubeTestData>) {
userDataList.forEach { userData ->
if (userData.testTime?.isEmpty() == false) {
if (userData._id.isEmpty()) {
hemoCubeViewModel.deleteById(userData._id)
}
}

View File

@@ -1,42 +1,66 @@
package com.example.hpostesting.presentation.dashboard
import android.content.Context
import android.content.pm.PackageManager
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
import android.widget.Toast
import androidx.preference.ListPreference
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import com.example.hpostesting.data.constant.LanguageManager
import `in`.sminnovations.hpostesting.R
class SlideshowFragment : Fragment() {
private var isLanguageChanged = false
private var _binding: FragmentSlideshowBinding? = null
class SlideshowFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
val preferenceScreen = preferenceManager.createPreferenceScreen(requireContext())
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
val languagePreference = ListPreference(requireContext())
languagePreference.key = "language_preference"
languagePreference.title = getString(R.string.app_language)
languagePreference.summary = getString(R.string.select_language)
languagePreference.entries = arrayOf("English", "Kannada", "Hindi")
languagePreference.entryValues = arrayOf("en", "kn", "hi")
languagePreference.setDefaultValue("en")
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 textView: TextView = binding.textSlideshow
// slideshowViewModel.text.observe(viewLifecycleOwner) {
// textView.text = it
// }
return root
languagePreference.onPreferenceChangeListener =
Preference.OnPreferenceChangeListener { _, newValue ->
val languageCode = newValue as String
updateLanguage(requireContext(), languageCode)
true
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
preferenceScreen.addPreference(languagePreference)
setPreferenceScreen(preferenceScreen)
// App Version Preference
val appVersionPreference = Preference(requireContext())
appVersionPreference.title = "App Version"
appVersionPreference.summary = getAppVersion(requireContext())
preferenceScreen.addPreference(languagePreference)
preferenceScreen.addPreference(appVersionPreference)
setPreferenceScreen(preferenceScreen)
if (isLanguageChanged) {
Toast.makeText(requireContext(), R.string.language_update, Toast.LENGTH_SHORT).show()
}
}
private fun updateLanguage(context: Context, languageCode: String) {
LanguageManager.persistLanguagePreference(context, languageCode)
LanguageManager.setLocale(context, languageCode)
requireActivity().recreate() // Recreate activity to apply language changes
isLanguageChanged = true
}
private fun getAppVersion(context: Context): String {
return try {
val pInfo = context.packageManager.getPackageInfo(context.packageName, 0)
pInfo.versionName
} catch (e: PackageManager.NameNotFoundException) {
"N/A"
}
}
}

View File

@@ -23,7 +23,8 @@ class LoginFragment : Fragment() {
savedInstanceState: Bundle?
): View {
_binding = FragmentLoginBinding.inflate(inflater, container, false)
sharedPreference = requireContext().getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE)
sharedPreference =
requireContext().getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE)
return binding.root
}
@@ -47,10 +48,10 @@ class LoginFragment : Fragment() {
performLogin(loginId, password)
} else {
if (loginId.isBlank()) {
binding.loginId.error = "Please enter a proper Login ID"
binding.loginId.error = R.string.enter_proper_login_id.toString()
}
if (password.isBlank()) {
binding.password.error = "Please enter a proper password"
binding.password.error = R.string.enter_proper_password.toString()
}
}
}
@@ -72,10 +73,10 @@ class LoginFragment : Fragment() {
navigateToHomeFragment()
return
} else {
Toast.makeText(requireContext(), "Wrong Password", Toast.LENGTH_SHORT).show()
Toast.makeText(requireContext(), R.string.wrong_password, Toast.LENGTH_SHORT).show()
}
}
Toast.makeText(requireContext(), "Wrong UserID", Toast.LENGTH_SHORT).show()
Toast.makeText(requireContext(), R.string.wrong_user_id, Toast.LENGTH_SHORT).show()
}
private fun saveUserId(userId: String) {

View File

@@ -0,0 +1,183 @@
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.data.constant.LanguageManager
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 attachBaseContext(newBase: Context?) {
val languageCode = LanguageManager.getSavedLanguage(newBase!!)
LanguageManager.setLocale(newBase, languageCode)
super.attachBaseContext(newBase)
}
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,47 @@
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.data.constant.LanguageManager
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 attachBaseContext(newBase: Context?) {
val languageCode = LanguageManager.getSavedLanguage(newBase!!)
LanguageManager.setLocale(newBase, languageCode)
super.attachBaseContext(newBase)
}
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

@@ -3,34 +3,31 @@ 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.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.MutableLiveData
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.Result
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.toHemoCubeTestData
import com.example.hpostesting.presentation.KitScanActivity
import com.example.hpostesting.presentation.UsbServiceListener
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.example.hpostesting.presentation.utils.MyDialogListener
import com.example.hpostesting.presentation.utils.UIUtils
import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.firestore.ktx.firestore
import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.ktx.Firebase
import `in`.sminnovations.hpostesting.BuildConfig
import com.google.firebase.perf.ktx.performance
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentHemoCubeReferenceBinding
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.tasks.await
import kotlinx.coroutines.withContext
import kotlin.math.log10
class HemoCubeFragment : Fragment() {
@@ -38,14 +35,34 @@ class HemoCubeFragment : Fragment() {
private lateinit var binding: FragmentHemoCubeReferenceBinding
private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels()
private lateinit var sharedPreferences: SharedPreferences
private val testDetails = DataHolder.selectedTest?.toHemoCubeTestData()
private var isOnline = false
private var currentDeviceData: DeviceData? = null
private var resultData: String = ""
private var isUsingExistingBuffer = false
private var isTestOngoing = false
private var bloodGroup: String = ""
private var startListening = MutableLiveData<Boolean>(false)
private val testingTrace = Firebase.performance.newTrace("testing_trace")
private var led1BufferForDevice = 0.0
private var led2BufferForDevice = 0.0
private var led3BufferForDevice = 0.0
private var led4BufferForDevice = 0.0
private var led1SampleForDevice = 0.0
private var led2SampleForDevice = 0.0
private var led3SampleForDevice = 0.0
private var led4SampleForDevice = 0.0
private var fittedAbs1 = 0.0
private var fittedAbs2 = 0.0
private var fittedAbs3 = 0.0
private var fittedAbs4 = 0.0
private var _predictedDenovixRatio = 0.0
private var validationError = false
private var deviceHardwareId = ""
private var allErrorMessages = ""
private var testStatusCode = 0.0
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
): View {
binding = FragmentHemoCubeReferenceBinding.inflate(inflater, container, false)
sharedPreferences =
@@ -56,76 +73,60 @@ class HemoCubeFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initViews()
listenToHemoCube()
getDeviceInfo()
observeViewModel()
checkAndStartProcess()
}
private fun initViews() {
binding.btnSubmit.setOnClickListener {
val bloodGroupText = binding.etBloodGroup.text.toString()
if (bloodGroupText.isEmpty()) {
binding.etBloodGroup.error = "Please enter your blood group"
} else {
fetchResult()
activity?.runOnUiThread {
binding.progressBar.visibility = View.VISIBLE
}
}
if (isTestOngoing) {
binding.btnKit.visibility = View.GONE
binding.btnKit.isEnabled = false
binding.btnKit.isClickable = false
}
binding.btnSubmit.isEnabled = false
binding.btnSubmit.isClickable = false
binding.btnKit.setOnClickListener {
if (isTestOngoing) {
val title = "WARNING"
val message = "There is a on going test, do you want to stop it"
val negativeText = getString(R.string.no)
val positiveText = "Yes"
UIUtils.createAlertDialog(requireContext(),
title,
message,
negativeText,
positiveText,
object : MyDialogListener {
override fun onClickNegativeButton() {
}
override fun onClickPositiveButton() {
resetKitCount()
val intent = Intent(context, KitScanActivity::class.java)
startActivity(intent)
(activity as HemocubeActivity).finish()
}
})
}
}
}
private suspend fun checkBloodGroup() {
binding.apply {
val bloodGroup = etBloodGroup.text.toString()
if (bloodGroup.isEmpty()) {
etBloodGroup.error = "Please enter your blood group"
} else {
val db: FirebaseFirestore = Firebase.firestore
val userdata = db.collection("patientData")
.whereEqualTo("_id", hemoCubeViewModel.testDetails?._id).get().await()
if (userdata.documents.isNotEmpty()) {
db.collection("patientData").document(userdata.documents[0].id)
.update("bloodGroup", bloodGroup)
withContext(Dispatchers.Main) {
val i = Intent(
requireContext().applicationContext, DashboardActivity::class.java
hemoCubeViewModel.uploadHemoCubeResultToDatabase(
isOnline, true, sharedPreferences.getString(Constants.KIT_NUMBER, "")
)
startActivity(i)
(activity as HemocubeActivity).finish()
}
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.btnPlacebuffer.visibility = View.GONE
binding.tvName.text = "Name: ${testDetails?.name}\n ID: ${testDetails?._id}"
binding.tvSubtitle4.text = "Config"
binding.btnSamplestart.setOnClickListener {
activity?.runOnUiThread {
binding.tvSubtitle4.visibility = View.VISIBLE
// binding.tvSubtitle4.text = "Sample Started"
}
startSampleProcess()
it.visibility = View.GONE
}
binding.btnPlacebuffer.setOnClickListener {
if (isBufferValueAvailable()) {
showBufferAlertDialog()
} else {
activity?.runOnUiThread {
binding.tvSubtitle4.visibility = View.VISIBLE
// binding.tvSubtitle4.text = "Buffer Started"
}
checkAndStartProcess()
it.visibility = View.GONE
}
}
if (sharedPreferences.getString(Constants.USER_ID, "").toString() == "ADMIN") {
activity?.runOnUiThread {
binding.tvDeviceMessages.visibility = View.VISIBLE
}
}
}
@@ -133,13 +134,41 @@ class HemoCubeFragment : Fragment() {
private fun observeViewModel() {
hemoCubeViewModel.fireBaseUpload.observe(viewLifecycleOwner) { result ->
if (result == "Success") {
showToast("Test Results Uploaded Successfully")
lifecycleScope.launch {
checkBloodGroup()
showToast(R.string.test_upload)
hemoCubeViewModel.resultUpload.observe(viewLifecycleOwner) {
when (it) {
is Result.Success -> {
it.data.data?.get(0)?.rawData?.let { it1 ->
hemoCubeViewModel.updateMolbioFlag(
it1._id)
activity?.runOnUiThread {
binding.btnSubmit.visibility = View.GONE
val i = Intent(
requireContext().applicationContext,
DashboardActivity::class.java
)
startActivity(i)
}
}
}
is Result.Error -> {
//Remove this line of code while deploying to IOCL
it.exception.let { message ->
Toast.makeText(activity, "An error occurred: $message", Toast.LENGTH_LONG)
.show()
}
}
else -> {}
}
}
}
if (result == "Local") {
showToast("Internet not available, test details stored locally")
showToast(R.string.internt_not_local)
startActivity(Intent(requireActivity(), DashboardActivity::class.java))
}
if (result == "Error") {
showToast(R.string.error_local)
startActivity(Intent(requireActivity(), DashboardActivity::class.java))
}
@@ -150,46 +179,70 @@ class HemoCubeFragment : Fragment() {
hemoCubeViewModel.deviceData.observe(viewLifecycleOwner) {
currentDeviceData = it
showToast(calculateRatio(0.17).toString())
}
hemoCubeViewModel.networkStatusLiveData.observe(viewLifecycleOwner) { isNetworkAvailable ->
apply {
DataHolder.hemoCubeTestData?.let {
currentDeviceData?.coefficients?.let { coefficients ->
val coefficient1 = coefficients[0]
val coefficient2 = coefficients[1]
val result = coefficient1 * coefficient2
}
}
isOnline = isNetworkAvailable
}
}
hemoCubeViewModel.messages.observe(viewLifecycleOwner) {
binding.tvSubtitle4.text = it
}
hemoCubeViewModel.deviceMessages.observe(viewLifecycleOwner) {
binding.tvDeviceMessages.text = it
}
}
private fun checkAndStartProcess() {
if (isBufferValueAvailable()) {
showBufferAlertDialog()
} else {
listenToHemoCube()
startBufferProcess()
}
}
private fun isBufferValueAvailable(): Boolean {
return if (sharedPreferences.getString(
return try {
if (sharedPreferences.getString(
Constants.BUFFER_VALUE_1, ""
) != "" && sharedPreferences.getString(Constants.BUFFER_VALUE_2, "") != ""
&& sharedPreferences.getString(Constants.BUFFER_VALUE_3, "") != ""
&& sharedPreferences.getString(Constants.BUFFER_VALUE_4, "") != ""
) {
sharedPreferences.getString(Constants.BUFFER_VALUE_1, "")
?.toDouble()!! > 0.0 && sharedPreferences.getString(Constants.BUFFER_VALUE_2, "")
?.toDouble()!! > 0.0 && sharedPreferences.getString(
Constants.BUFFER_VALUE_2,
""
)
?.toDouble()!! > 0.0 && sharedPreferences.getString(
Constants.BUFFER_VALUE_3,
""
)
?.toDouble()!! > 0.0 && sharedPreferences.getString(
Constants.BUFFER_VALUE_4,
""
)
?.toDouble()!! > 0.0
} else {
false
}
} catch (e: Exception) {
showToast(R.string.error_exist)
false
}
}
private fun showBufferAlertDialog() {
val title = "WARNING"
val message = "Do you want to continue with existing buffer?"
val message = getString(R.string.do_exist)
val negativeText = getString(R.string.no)
val positiveText = "Yes"
val positiveText = getString(R.string.yes)
UIUtils.createAlertDialog(requireContext(),
title,
@@ -198,13 +251,15 @@ class HemoCubeFragment : Fragment() {
positiveText,
object : MyDialogListener {
override fun onClickNegativeButton() {
listenToHemoCube()
startBufferProcess()
}
override fun onClickPositiveButton() {
listenToHemoCube()
startSampleProcess()
activity?.runOnUiThread {
binding.btnPlacebuffer.visibility = View.GONE
binding.btnSamplestart.visibility = View.VISIBLE
binding.tvSubtitle4.text = getString(R.string.place_sample)
}
isUsingExistingBuffer = true
}
})
@@ -218,12 +273,38 @@ class HemoCubeFragment : Fragment() {
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)
handleUsbData(stringData, testStatusCode)
}
}
override fun onUsbError(e: Exception?) {
hemoCubeViewModel.progressBar.postValue(false)
}
})
} catch (e: Exception) {
showToast(R.string.test_ongoing)
Firebase.crashlytics.recordException(e)
}
}
private fun getDeviceInfo() {
hemoCubeViewModel.progressBar.postValue(true)
(activity as HemocubeActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.getDeviceId,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
data?.let {
val stringData = String(it)
hemoCubeViewModel.messages.postValue(stringData)
binding.tvSubtitle4.text = stringData
}
}
@@ -233,162 +314,394 @@ class HemoCubeFragment : Fragment() {
})
}
private fun handleUsbData(stringData: String, fullReadOutput: StringBuilder) {
private fun handleUsbData(stringData: String, testStatusCode: Double) {
if (stringData.contains("#")) {
hemoCubeViewModel.messages.postValue(stringData)
isTestOngoing = true
}
resultData += fullReadOutput.toString()
resultData += stringData
hemoCubeViewModel.deviceMessages.postValue(resultData)
when {
stringData.contains("ERROR 500") -> showError500Dialog()
stringData.contains("ERROR 501") -> showError501Dialog()
stringData.contains("#Buffer Completed") -> showStartSampleDialog()
stringData.contains("#Sample Completed") -> {
resultData.contains("SNE") && this.testStatusCode < Constants.TEST_STATUS_CODE_CONFIG_COMPLETED -> {
val pattern = Regex("HCV-\\d{3}-\\d{4}")
val matchResult = pattern.find(resultData)
val hardwareId = matchResult?.value
if (hardwareId.toString().length == 12) {
deviceHardwareId += hardwareId
with(sharedPreferences.edit()) {
putString(Constants.DEVICE_ID, deviceHardwareId)
apply()
}
this.testStatusCode = Constants.TEST_STATUS_CODE_CONFIG_COMPLETED
} else {
hemoCubeViewModel.messages.postValue("Config error")
}
activity?.runOnUiThread {
binding.btnPlacebuffer.visibility = View.VISIBLE
}
hemoCubeViewModel.messages.postValue(getString(R.string.start))
}
resultData.contains("#BS") && this.testStatusCode < Constants.TEST_STATUS_CODE_BUFFER_STARTED -> {
hemoCubeViewModel.messages.postValue(getString(R.string.buffer_started))
this.testStatusCode = Constants.TEST_STATUS_CODE_BUFFER_STARTED
}
resultData.contains("#BC") && this.testStatusCode < Constants.TEST_STATUS_CODE_BUFFER_COMPLETED -> {
this.testStatusCode = Constants.TEST_STATUS_CODE_BUFFER_COMPLETED
activity?.runOnUiThread {
binding.tvSubtitle4.text = getString(R.string.buffer_completed)
binding.btnSamplestart.visibility = View.VISIBLE
}
}
resultData.contains("#SS") && this.testStatusCode < Constants.TEST_STATUS_CODE_SAMPLE_STARTED -> {
this.testStatusCode = Constants.TEST_STATUS_CODE_SAMPLE_STARTED
activity?.runOnUiThread {
binding.tvSubtitle4.text = getString(R.string.sample_started)
binding.btnSamplestart.visibility = View.GONE
}
}
resultData.contains("#SC") && this.testStatusCode < Constants.TEST_STATUS_CODE_SAMPLE_COMPLETED -> {
this.testStatusCode = Constants.TEST_STATUS_CODE_SAMPLE_COMPLETED
hemoCubeViewModel.messages.postValue(
getString(R.string.sample_completed) + "\n" + getString(R.string.gathering_data))
fetchResult()
testingTrace.stop()
}
resultData.contains("REND") && this.testStatusCode < Constants.TEST_STATUS_CODE_SAMPLE_PRINT_COMPLETED -> {
this.testStatusCode = Constants.TEST_STATUS_CODE_SAMPLE_PRINT_COMPLETED
hemoCubeViewModel.messages.postValue(
getString(R.string.data_collected_processing_data)
)
val resultLines = resultData.split("\\s+(?=LB|LS)".toRegex())
var bufferIntensity = resultLines[1].split(' ')[1].trim()
led1BufferForDevice = if (isUsingExistingBuffer) {
sharedPreferences.getString(Constants.BUFFER_VALUE_1, "")?.toDoubleOrNull()!!
} else {
bufferIntensity.toDoubleOrNull()!!
}
bufferIntensity = resultLines[2].split(' ')[1].trim()
led2BufferForDevice = if (isUsingExistingBuffer) {
sharedPreferences.getString(Constants.BUFFER_VALUE_2, "")?.toDoubleOrNull()!!
} else {
bufferIntensity.toDoubleOrNull()!!
}
bufferIntensity = resultLines[3].split(' ')[1].trim()
led3BufferForDevice = if (isUsingExistingBuffer) {
sharedPreferences.getString(Constants.BUFFER_VALUE_3, "")?.toDoubleOrNull()!!
} else {
bufferIntensity.toDoubleOrNull()!!
}
bufferIntensity = resultLines[4].split(' ')[1].trim()
led4BufferForDevice = if (isUsingExistingBuffer) {
sharedPreferences.getString(Constants.BUFFER_VALUE_4, "")?.toDoubleOrNull()!!
} else {
bufferIntensity.toDoubleOrNull()!!
}
var sampleIntensity = resultLines[5].split(' ')[1].trim()
led1SampleForDevice = resultLines[5].split(' ')[1].trim().toDoubleOrNull()!!
sampleIntensity = resultLines[6].split(' ')[1].trim()
led2SampleForDevice = resultLines[6].split(' ')[1].trim().toDoubleOrNull()!!
sampleIntensity = resultLines[7].split(' ')[1].trim()
led3SampleForDevice = resultLines[7].split(' ')[1].trim().toDoubleOrNull()!!
sampleIntensity = resultLines[8].split(' ')[1].split('\r')[0].trim()
led4SampleForDevice =
resultLines[8].split(' ')[1].split('\r')[0].trim().toDoubleOrNull()!!
processResult()
}
}
}
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(R.string.test_go_noback)
} else {
// If the test is not ongoing, you can trigger the back action of the hosting activity
activity?.onBackPressed()
}
}
private fun processResult() {
try {
hemoCubeViewModel.messages.postValue(getString(R.string.processing_result))
val deviceLog = resultData
val pInfo = requireActivity().packageManager.getPackageInfo(
requireActivity().packageName, 0
)
val version = pInfo.versionName
val led1Average = log10(led1BufferForDevice.div(led1SampleForDevice))
val led2Average = log10(led2BufferForDevice.div(led2SampleForDevice))
val led3Average = log10(led3BufferForDevice.div(led3SampleForDevice))
val led4Average = log10(led4BufferForDevice.div(led4SampleForDevice))
val deviceRatio = led3Average / led1Average
if (led1BufferForDevice < Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(0)
?.get(0)!!
|| led2BufferForDevice < Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(
1
)?.get(0)!!
|| led3BufferForDevice < Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(
2
)?.get(0)!!
|| led4BufferForDevice < Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(
3
)?.get(0)!!
) {
validationError = true
allErrorMessages += "Error: Invalid Test. Improper buffer reading (low)"
activity?.runOnUiThread {
binding.errorMessage.text = getString(R.string.error_improper_buffer_low)
binding.errorMessage.visibility = View.VISIBLE
}
}
if (led1BufferForDevice > Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(0)
?.get(1)!!
|| led2BufferForDevice > Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(
1
)?.get(1)!!
|| led3BufferForDevice > Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(
2
)?.get(1)!!
|| led4BufferForDevice > Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(
3
)?.get(1)!!
) {
validationError = true
allErrorMessages += "Error: Invalid Test. Improper buffer reading (high)" + "\n"
activity?.runOnUiThread {
binding.errorMessage.text =
getString(R.string.error_improper_buffer_high)
binding.errorMessage.visibility = View.VISIBLE
binding.btnSubmit.isEnabled = true
binding.btnSubmit.isClickable = true
}
}
stringData.contains("RESULT") || resultData.contains("REND") -> {
var validString: String
val results: List<String>
if (stringData.contains("RESULT")) {
validString = isValidResult(stringData)
if (validString.isEmpty()) {
results = resultData.split("\n")
validString = parseResult(results)
}
} else {
results = resultData.split("\n")
validString = parseResult(results)
}
if (validString.isNotEmpty()) {
handleValidResult(validString, resultData)
}
}
}
}
private fun showError500Dialog() {
UIUtils.createAlertDialog(requireContext(),
"BUFFER ERROR",
"Do you want to continue with existing buffer?",
getString(R.string.noo),
"Yes",
object : MyDialogListener {
override fun onClickNegativeButton() {}
override fun onClickPositiveButton() {
listenToHemoCube()
startBufferProcess()
}
})
}
var gradient = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(0)?.get(0)
var constant = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(0)?.get(1)
fittedAbs1 = gradient?.times(led1Average)?.plus(constant!!)!!
private fun showError501Dialog() {
UIUtils.createAlertDialog(requireContext(),
"SAMPLE ERROR",
"Do you want to continue with Sample?",
getString(R.string.noo),
"Yes",
object : MyDialogListener {
override fun onClickNegativeButton() {}
gradient = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(1)?.get(0)
constant = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(1)?.get(1)
fittedAbs2 = gradient?.times(led2Average)?.plus(constant!!)!!
override fun onClickPositiveButton() {
listenToHemoCube()
startSampleProcess()
}
})
}
gradient = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(2)?.get(0)
constant = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(2)?.get(1)
fittedAbs3 = gradient?.times(led3Average)?.plus(constant!!)!!
private fun showStartSampleDialog() {
gradient = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(3)?.get(0)
constant = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(3)?.get(1)
fittedAbs4 = gradient?.times(led4Average)?.plus(constant!!)!!
_predictedDenovixRatio = fittedAbs3.div(fittedAbs1)
if (fittedAbs1 <= fittedAbs2) {
validationError = true
allErrorMessages += "Error: Invalid Test. Problem with de-oxygenation" + "\n"
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() {
}
})
binding.errorMessage.text = getString(R.string.error_invalid_test)
binding.errorMessage.visibility = View.VISIBLE
}
}
private fun handleValidResult(validString: String, fullReadOutput: String) {
try {
val result = validString.split(" ")
if (result.size == 8) {
val deviceSerialNo = result[2]
val led1BufferForDevice = if (isUsingExistingBuffer) {
sharedPreferences.getString(Constants.BUFFER_VALUE_1, "")?.toDoubleOrNull()
} else {
result[3].toDoubleOrNull()
if (fittedAbs1 < 0 || fittedAbs2 < 0 || fittedAbs3 < 0 || fittedAbs4 < 0) {
validationError = true
activity?.runOnUiThread {
binding.errorMessage.text = getString(R.string.error_negative_abs)
binding.errorMessage.visibility = View.VISIBLE
}
val led2BufferForDevice = if (isUsingExistingBuffer) {
sharedPreferences.getString(Constants.BUFFER_VALUE_2, "")?.toDoubleOrNull()
} else {
result[4].toDoubleOrNull()
}
val version = BuildConfig.VERSION_NAME
val led1Sample = result[5].toDoubleOrNull()
val led2Sample = result[6].toDoubleOrNull()
val led1Average = log10(led1BufferForDevice?.div(led1Sample!!) ?: 0.0)
val led2Average = log10(led2BufferForDevice?.div(led2Sample!!) ?: 0.0)
val deviceRatio = led1Average / led2Average
if (led1BufferForDevice!! > 20000 && led1BufferForDevice < 24000 && led2BufferForDevice!! > 20000 && led2BufferForDevice < 24000) {
if (led1Sample!! < led1BufferForDevice && led1Sample < 24000 && led2Sample!! < led2BufferForDevice && led2Sample < 24000) {
if (deviceRatio < 0.08) {
if (deviceRatio > 1.07) {
if (fittedAbs3 < 0.1) {
validationError = true
allErrorMessages += "Error: Low Hb. Repeat test" + "\n"
activity?.runOnUiThread {
binding.errorMessage.text = "Error: Low Hb. Repeat test"
binding.errorMessage.visibility = View.VISIBLE
}
}
}
}
DataHolder.hemoCubeTestData?.apply {
deviceId = deviceSerialNo
deviceId = sharedPreferences.getString(Constants.DEVICE_ID, "").toString()
led1Buffer = led1BufferForDevice
led2Buffer = led2BufferForDevice
led3Buffer = led3BufferForDevice
led4Buffer = led4BufferForDevice
appVersion = version
this.led1Sample = led1Sample
this.led2Sample = led2Sample
this.led1Sample = led1SampleForDevice
this.led2Sample = led2SampleForDevice
this.led3Sample = led3SampleForDevice
this.led4Sample = led4SampleForDevice
this.led1Average = led1Average
this.led2Average = led2Average
this.led3Average = led3Average
this.led4Average = led4Average
this.abs1 = fittedAbs1
this.abs2 = fittedAbs2
this.abs3 = fittedAbs3
this.abs4 = fittedAbs4
this.deviceRatio = deviceRatio
this.calculatedRatio = calculateRatio(deviceRatio)
this.resultData = fullReadOutput
if (!isBufferValueAvailable()) {
this.predictedDenovixRatio = _predictedDenovixRatio
this.coefficients = currentDeviceData?.coefficients?.get(0)
.toString() + ", " + currentDeviceData?.coefficients?.get(1).toString()
this.classificationResult = findResult(calculatedRatio)
this.prdClassification = absorbanceBasedClassification(predictedDenovixRatio)
hemoCubeViewModel.messages.postValue(this.prdClassification)
this.errorMessages = allErrorMessages
this.resultData = deviceLog
this.batteryLevel = hemoCubeViewModel.getBatteryLevel().toString()
this.batteryCapacity =
hemoCubeViewModel.getBatteryCapacity(requireContext()).toString()
this.batteryMaxCapacity =
hemoCubeViewModel.getBatteryMaxCapacity(requireContext()).toString()
this.batteryTemperature = hemoCubeViewModel.getBatteryTemperature().toString()
this.batteryVoltage =
hemoCubeViewModel.getBatteryVoltage(requireContext()).toString()
}
if (!isUsingExistingBuffer) {
with(sharedPreferences.edit()) {
putString(Constants.BUFFER_VALUE_1, led1Buffer.toString())
putString(Constants.BUFFER_VALUE_2, led2Buffer.toString())
putString(Constants.BUFFER_VALUE_1, led1BufferForDevice.toString())
putString(Constants.BUFFER_VALUE_2, led2BufferForDevice.toString())
putString(Constants.BUFFER_VALUE_3, led3BufferForDevice.toString())
putString(Constants.BUFFER_VALUE_4, led4BufferForDevice.toString())
apply()
}
}
hemoCubeViewModel.uploadHemoCubeResultToDatabase(
isOnline, true, sharedPreferences.getString(Constants.KIT_NUMBER, "")
// if (!validationError) {
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(),
R.string.error_processing_device_data,
Toast.LENGTH_SHORT
).show()
Firebase.crashlytics.recordException(e)
}
}
fun findResult(calculatedRatio: Double?): String {
try {
hemoCubeViewModel.messages.postValue("result classification")
if (calculatedRatio != null) {
if (calculatedRatio < 0.05)
return getString(R.string.error_repeat_test_higher_volume)
if (calculatedRatio in 0.05..0.155) {
activity?.runOnUiThread {
binding.tvSubtitle4.setTextColor(
ContextCompat.getColor(
requireContext(),
R.color.brightGreen
)
)
}
return getString(R.string.normal)
}
if (calculatedRatio in 0.155..0.175)
return getString(R.string.negative_borderline)
if (calculatedRatio in 0.175..0.22)
return getString(R.string.sickle_cell_trait)
if (calculatedRatio in 0.22..0.25)
return getString(R.string.positive_for_sickle_cell)
if (calculatedRatio in 0.25..0.35)
return getString(R.string.sickle_cell_disease)
if (calculatedRatio > 0.35)
return getString(R.string.error_repeat_test_lower_volume)
} else {
return getString(R.string.invalid)
}
} catch (e: Exception) {
showToast(R.string.error_classification)
Firebase.crashlytics.recordException(e)
return getString(R.string.error)
}
return getString(R.string.invalid)
}
} catch (_: Exception) {
private fun absorbanceBasedClassification(predictedDenovixRatio: Double?): String {
try {
hemoCubeViewModel.messages.postValue("result classification")
if (predictedDenovixRatio != null) {
if (predictedDenovixRatio in 0.0..0.16) {
activity?.runOnUiThread {
binding.tvSubtitle4.setTextColor(
ContextCompat.getColor(
requireContext(),
R.color.brightGreen
)
)
}
return getString(R.string.normal)
}
if (predictedDenovixRatio in 0.16..0.165)
return getString(R.string.negative_borderline)
if (predictedDenovixRatio in 0.165..0.235)
return getString(R.string.sickle_cell_trait)
if (predictedDenovixRatio in 0.235..0.24)
return getString(R.string.positive_borderline)
if (predictedDenovixRatio in 0.24..1.0)
return getString(R.string.sickle_cell_disease)
} else {
return getString(R.string.invalid)
}
} catch (e: Exception) {
showToast(R.string.error_classification)
Firebase.crashlytics.recordException(e)
return getString(R.string.error)
}
return getString(R.string.invalid)
}
}
private fun showToast(message: String) {
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
private fun showToast(messageResId: Int) {
Toast.makeText(requireContext(), getString(messageResId), Toast.LENGTH_SHORT).show()
}
private fun startBufferProcess() {
hemoCubeViewModel.progressBar.postValue(true)
activity?.runOnUiThread {
binding.btnPlacebuffer.visibility = View.GONE
}
(activity as HemocubeActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.startBuffer,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {}
@@ -400,6 +713,7 @@ class HemoCubeFragment : Fragment() {
}
private fun startSampleProcess() {
testingTrace.start()
hemoCubeViewModel.progressBar.postValue(true)
(activity as HemocubeActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.startSample,
@@ -431,34 +745,9 @@ class HemoCubeFragment : Fragment() {
return coefficient1 * ratio + coefficient2
}
private fun parseResult(frames: List<String>): String {
val lines = mutableListOf<String>()
for (frame in frames.reversed()) {
if (frame.contains("REND") || frame.contains("RESULT")) lines += frame
if (frame.contains("RESULT")) {
break
}
}
val line = lines.reversed().joinToString("").trim()
if (line.contains("RESULT") && line.split(" ").size == 8) {
return line
}
return ""
}
private fun isValidResult(line: String): String {
return if (line.contains("RESULT") && line.split(" ").size == 8) {
line
} else {
""
}
}
private fun resetKitCount() {
with(sharedPreferences.edit()) {
putString(Constants.KIT_NUMBER, "")
putInt(Constants.KIT_COUNT, 0)
apply()
}
private fun checkDeviceIdMismatch(deviceId: String, loginId: String): Boolean {
if (!deviceId.isNullOrEmpty() && !loginId.isNullOrEmpty() && deviceId.last() != loginId.last())
return true
return false
}
}

View File

@@ -1,51 +1,110 @@
package com.example.hpostesting.presentation.hemocube
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.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.NetworkStatusLiveData
import com.example.hpostesting.data.Result
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.deviceprovision.DeviceProvisionRequest
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionResponse
import com.example.hpostesting.data.model.log.UploadLogsResponse
import com.example.hpostesting.data.model.login.LoginRequest
import com.example.hpostesting.data.model.login.LoginResponse
import com.example.hpostesting.data.model.molbioresult.MolbioV2Result
import com.example.hpostesting.data.model.molbioresult.MolbioV2ResultRequest
import com.example.hpostesting.data.model.molbioresult.MolbioV2ResultResponse
import com.example.hpostesting.data.model.patient.BufferCheckData
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.data.model.patient.toHemoCubeTestData
import com.example.hpostesting.data.model.updates.CheckUpdateRequest
import com.example.hpostesting.data.model.updates.CheckUpdateResponse
import com.example.hpostesting.data.model.updates.DeviceUpdateRequest
import com.example.hpostesting.data.repository.DatabaseRepository
import com.example.hpostesting.data.repository.Repository
import com.example.hpostesting.domain.CheckUpdateWorker
import com.example.hpostesting.domain.LogFileManager
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.RequestBody.Companion.asRequestBody
import okhttp3.ResponseBody
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import java.util.concurrent.TimeUnit
import javax.inject.Inject
@HiltViewModel
class HemoCubeViewModel @Inject constructor(
private val hemoCubeDao: HemoCubeDao,
private val repository: DatabaseRepository,
context: Context,
private val repository: Repository,
private val databaseRepository: DatabaseRepository,
private val logFileManager: LogFileManager,
context: Context
) : ViewModel() {
var isServiceConnected = false
val progressBar = MutableLiveData(false)
val testDetails = DataHolder.selectedTest?.toHemoCubeTestData()
private val testDetails = DataHolder.selectedTest?.toHemoCubeTestData()
val messages = MutableLiveData<String>()
private val sharedPreference: SharedPreferences = context.getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE)
private val sharedPreference: SharedPreferences =
context.getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE)
private val workManager = WorkManager.getInstance(context)
// init {
// startPeriodicCheckUpdate()
// }
val deviceProvisionResponse = MutableLiveData<Result<DeviceProvisionResponse>>()
val loginResponse = MutableLiveData<Result<LoginResponse>>()
val resultUpload = MutableLiveData<Result<MolbioV2ResultResponse>>()
val checkUpdate = MutableLiveData<Result<CheckUpdateResponse>>()
val deviceUpdate = MutableLiveData<Result<ResponseBody>>()
val uploadLogs = MutableLiveData<Result<UploadLogsResponse>?>()
// 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 deviceMessages = MutableLiveData<String?>()
val fireBaseUpload = MutableLiveData<String>()
fun uploadHemoCubeResultToDatabase(isOnline: Boolean, testStatus: Boolean, kitSerial: String?) =
viewModelScope.launch {
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
}
@@ -53,8 +112,10 @@ class HemoCubeViewModel @Inject constructor(
try {
if (isOnline) {
parseData()
addResultTestToDb()
} else {
parseData()
testDetails?.testTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
@@ -66,11 +127,75 @@ class HemoCubeViewModel @Inject constructor(
}
}
fun deviceProvision(deviceProvisionRequest: DeviceProvisionRequest) = viewModelScope.launch {
deviceProvisionResponse.postValue(Result.Loading())
databaseRepository.deviceProvision(deviceProvisionRequest).let {
deviceProvisionResponse.postValue(it)
}
}
fun login(loginRequest: LoginRequest) = viewModelScope.launch {
loginResponse.postValue(Result.Loading())
databaseRepository.login(loginRequest).let {
loginResponse.postValue(it)
}
}
fun uploadResult(molbioV2ResultRequest: MolbioV2ResultRequest) = viewModelScope.launch {
resultUpload.postValue(Result.Loading())
databaseRepository.uploadResults(molbioV2ResultRequest).let {
resultUpload.postValue(it)
}
}
fun checkUpdate(checkUpdateRequest: CheckUpdateRequest) = viewModelScope.launch {
checkUpdate.postValue(Result.Loading())
databaseRepository.checkUpdate(checkUpdateRequest).let {
checkUpdate.postValue(it)
}
}
fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest) = viewModelScope.launch {
deviceUpdate.postValue(Result.Loading())
databaseRepository.deviceUpdate(deviceUpdateRequest).let {
deviceUpdate.postValue(it)
}
}
fun startPeriodicCheckUpdate() {
val periodicRequest = PeriodicWorkRequestBuilder<CheckUpdateWorker>(
repeatInterval = 1, repeatIntervalTimeUnit = TimeUnit.MINUTES
).build()
workManager.enqueueUniquePeriodicWork(
"checkUpdateWorker", ExistingPeriodicWorkPolicy.KEEP, periodicRequest
)
}
fun uploadLogs() = viewModelScope.launch {
uploadLogs.postValue(Result.Loading())
val logFile = logFileManager.createLogFile().let { file ->
val requestBody = file?.asRequestBody("multipart/form-data".toMediaTypeOrNull())
val multipartFile =
requestBody?.let { MultipartBody.Part.createFormData("logFile", file.name, it) }
multipartFile?.let { partFile ->
databaseRepository.uploadLogs(partFile).let { result ->
uploadLogs.postValue(result)
}
}
}
}
fun uploadHemoCubeResultToDatabaseforbuffercheckN(bufferCheckData: BufferCheckData) =
viewModelScope.launch {
addResultTestToDbforbuffercheck(bufferCheckData)
}
fun getDeviceData(deviceId: String?) = viewModelScope.launch {
deviceData.postValue(deviceId?.let { repository.getDeviceDataById(it) })
}
private fun addResultTestToDb() {
private fun parseData() {
testDetails?.deviceRatio = DataHolder.hemocubeResult
testDetails?.resultData = DataHolder.hemoCubeTestData?.resultData.toString()
testDetails?.location = DataHolder.location
@@ -79,17 +204,39 @@ class HemoCubeViewModel @Inject constructor(
).format(Calendar.getInstance().time)
testDetails?.appVersion = DataHolder.hemoCubeTestData?.appVersion
testDetails?.deviceId = DataHolder.hemoCubeTestData?.deviceId
testDetails?.deviceSerialNumber = sharedPreference.getString(Constants.USER_ID, "").toString()
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(
@@ -100,22 +247,64 @@ class HemoCubeViewModel @Inject constructor(
is Response.Success -> {
val kitCount = sharedPreference.getInt(Constants.KIT_COUNT, 0)
with(sharedPreference.edit()) {
putInt(Constants.KIT_COUNT, kitCount.plus(1) ?: 0)
putInt(Constants.KIT_COUNT, kitCount.plus(1))
apply()
}
Log.i("Testdb", "Data uploaded to Firestore successfully")
fireBaseUpload.postValue("Success")
testDetails.localFlag = true
uploadResult(
MolbioV2ResultRequest(
listOf(
MolbioV2Result(
rawData = testDetails,
analysisId = testDetails._id,
analysisDate = testDetails.testTime,
analysisStatus = testDetails.classificationResult,
thresholds = Constants.BUFFER_INTENSITY_THRESHOLDS[testDetails.deviceId].toString(),
interpretation = testDetails.classificationResult,
testId = testDetails._id,
testTime = testDetails.testTime,
collectionTime = testDetails.testTime,
expiryTime = testDetails.testTime,
)
)
)
)
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}")
Log.e("Testdb", "Error uploading data to Firestore: $response")
fireBaseUpload.postValue("Error")
}
else -> {
Log.e("Testdb", "Unknown response from repository: $response")
fireBaseUpload.postValue("Unknown")
}
else -> {}
}
} catch (e: Exception) {
Log.e("Testdb", "Exception during data upload: ${e.message}")
@@ -131,15 +320,75 @@ class HemoCubeViewModel @Inject constructor(
).format(Calendar.getInstance().time)
when (repository.addTestToDatabase(userData)) {
is Response.Success -> {
fireBaseUpload.postValue("Success")
fireBaseBulkUpload.postValue("Success")
updateLocalFlag(userData._id)
}
else -> {}
else -> {
fireBaseBulkUpload.postValue("Error")
}
}
}
}
private fun updateLocalFlag(userId: String) = viewModelScope.launch {
hemoCubeDao.updateFieldById(id = userId, true)
}
fun updateMolbioFlag(userId: String) = viewModelScope.launch {
hemoCubeDao.updateMolbioFlag(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)
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
return batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER)
}
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
return currentCapacity.toFloat() / designCapacity.toFloat() * 100
}
}

View File

@@ -3,7 +3,6 @@ package com.example.hpostesting.presentation.hemocube
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.ContentValues.TAG
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
@@ -11,32 +10,27 @@ 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.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.TestRightExpReference
import com.example.hpostesting.presentation.testRight.TestRightExpSample
import com.example.hpostesting.presentation.testRight.TestRightViewModel
import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.presentation.testRight.UsbService
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationCallback
import com.hoho.android.usbserial.driver.UsbSerialDriver
import com.hoho.android.usbserial.driver.UsbSerialProber
import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityHemocubeBinding
import `in`.sminnovations.hpostesting.databinding.ActivityMainBinding
@AndroidEntryPoint
class HemocubeActivity : AppCompatActivity() {
open class HemocubeActivity : AppCompatActivity() {
private lateinit var binding: ActivityHemocubeBinding
private val viewModel by viewModels<HemoCubeViewModel>()
private var myMenu: Menu? = null
@@ -79,6 +73,12 @@ class HemocubeActivity : AppCompatActivity() {
viewModel.isServiceConnected = false
}
}
override fun attachBaseContext(newBase: Context?) {
val languageCode = LanguageManager.getSavedLanguage(newBase!!)
LanguageManager.setLocale(newBase, languageCode)
super.attachBaseContext(newBase)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -94,15 +94,17 @@ class HemocubeActivity : AppCompatActivity() {
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)
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)
myMenu?.get(0)?.icon =
ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_off_24)
Toast.makeText(this, "Device is Disconnected", Toast.LENGTH_SHORT).show()
}
}
}
private fun connectUsb(permissionGranted: Boolean) {
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)
@@ -126,10 +128,7 @@ class HemocubeActivity : AppCompatActivity() {
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
this, 0, Intent(Constants.HOMOCUBE_USB_PERMISSION), PendingIntent.FLAG_MUTABLE
)
} else {
mPendingIntent = PendingIntent.getBroadcast(
@@ -145,30 +144,46 @@ class HemocubeActivity : AppCompatActivity() {
manager.requestPermission(device, mPendingIntent)
}
private fun setupService() {
fun setupService() {
val intent = Intent(this, UsbService::class.java)
// startService(intent)
bindService(intent, connection, Context.BIND_AUTO_CREATE)
}
private fun moveToNext() {
if (supportFragmentManager.isDestroyed)
return
supportFragmentManager.beginTransaction()
.replace(binding.fghemocube.id, HemoCubeFragment()).commit()
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()
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) {

View File

@@ -1,5 +1,6 @@
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
@@ -14,7 +15,6 @@ import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.model.test.TestRightResultType
import com.example.hpostesting.data.model.test.TestType
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.example.hpostesting.util.MyUtils.calculateAgeFromYOB
import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.firestore.ktx.firestore

View File

@@ -2,7 +2,6 @@ package com.example.hpostesting.presentation.testRight
import android.content.Context
import android.net.Uri
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel

View File

@@ -34,7 +34,7 @@ class UsbService : Service() {
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)
mPort.setParameters(9600, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE)
isUsbConnected = true
Log.d(TAG, "My Usb Connected ${mPort.driver}")

View File

@@ -0,0 +1,15 @@
package com.example.hpostesting.util
import android.content.res.AssetManager
import com.example.hpostesting.data.api.PropertyProvider
import java.io.InputStream
import java.util.Properties
class PropertyProviderImpl (private val assetManager: AssetManager) : PropertyProvider {
override fun getProperty(key: String): String {
val inputStream: InputStream = assetManager.open("app.properties")
val properties = Properties()
properties.load(inputStream)
return properties.getProperty(key)
}
}

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_parent"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:id="@+id/my_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:titleTextColor="#FFFFFF"
android:elevation="4dp"
app:menu="@menu/my_menu"
android:theme="@style/ToolbarTheme"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<FrameLayout
android:id="@+id/fg_hc_buffer_check"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/my_toolbar"
app:layout_constraintBottom_toBottomOf="parent"
tools:context=".presentation.buffercheck.HemocubeBufferCheckActivity">
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_parent"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- <androidx.appcompat.widget.Toolbar-->
<!-- android:id="@+id/my_toolbar"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="?attr/actionBarSize"-->
<!-- android:background="?attr/colorPrimary"-->
<!-- app:titleTextColor="#FFFFFF"-->
<!-- android:elevation="4dp"-->
<!-- app:menu="@menu/my_menu"-->
<!-- android:theme="@style/ToolbarTheme"-->
<!-- app:popupTheme="@style/ThemeOverlay.AppCompat.Light"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toTopOf="parent"/>-->
<FrameLayout
android:id="@+id/fg_diagnostics"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
tools:context=".presentation.diagnostics.DiagnosticsActivity">
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_parent"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:visibility="gone"
android:id="@+id/my_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:titleTextColor="#FFFFFF"
android:elevation="4dp"
app:menu="@menu/my_menu"
android:theme="@style/ToolbarTheme"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<FrameLayout
android:id="@+id/fghemocube"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="@id/my_toolbar"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<!-- NavHostFragment for navigation -->
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@@ -1,10 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_parent"
android:layout_width="match_parent"
@@ -27,15 +25,11 @@
android:id="@+id/fghemocube"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/my_toolbar"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:context=".presentation.hemocube.HemocubeActivity">
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@@ -18,4 +18,6 @@
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/dashboard_navigation" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:padding="16dp">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/til_blood_group"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<AutoCompleteTextView
android:id="@+id/et_blood_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/select_blood_group"
android:inputType="none"
android:labelFor="@id/til_blood_group"
app:simpleItems="@array/blood_group" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>

View File

@@ -0,0 +1,102 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.hpostesting.presentation.diagnostics.DiagnosticsFragment">
<!-- <TextView-->
<!-- android:id="@+id/tv_title"-->
<!-- style="@style/title1"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_marginHorizontal="24dp"-->
<!-- android:text="@string/diagnostics"-->
<!-- android:layout_marginTop="16dp"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toTopOf="parent" />-->
<TextView
android:id="@+id/tv_subtitle2"
style="@style/title2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:text="@string/diagnostics"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_subtitle3"
style="@style/title2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle2" />
<TextView
android:id="@+id/tv_subtitle4"
style="@style/title1_1"
android:layout_width="0dp"
android:layout_height="380dp"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:gravity="center"
android:text="Start"
android:textColor="@color/red"
android:textSize="22sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle3" />
<Button
android:id="@+id/btn_submit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:gravity="center"
android:text="Start"
android:textColor="@color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle4" />
<!-- <Button-->
<!-- android:id="@+id/btn_read"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:text="@string/read"-->
<!-- android:layout_margin="16dp"-->
<!-- android:clickable="false"-->
<!-- app:layout_constraintTop_toBottomOf="@id/btn_set_reference"-->
<!-- app:layout_constraintStart_toStartOf="parent" />-->
<!-- </androidx.constraintlayout.widget.ConstraintLayout>-->
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:elevation="12dp"
android:indeterminate="true"
android:indeterminateDrawable="@drawable/progressbar_drawable"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,242 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.example.hpostesting.presentation.hemocube.DigitalCardFragment">
<androidx.cardview.widget.CardView
android:id="@+id/userCard"
android:layout_width="match_parent"
android:layout_height="350dp"
android:layout_marginTop="24dp"
app:cardBackgroundColor="#C0C0C0"
app:cardCornerRadius="25dp"
app:cardElevation="0dp"
app:layout_constraintTop_toTopOf="parent">
<FrameLayout
android:id="@+id/fragment_container_layout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="@android:color/background_light"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="22dp">
<ImageView
android:id="@+id/userImage"
android:layout_width="100dp"
android:layout_height="100dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:src="@drawable/karnataka" />
<ImageView
android:id="@+id/userName"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginStart="16dp"
app:layout_constraintTop_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/userImage"
app:layout_constraintTop_toTopOf="@+id/userImage"
android:src="@drawable/sickle_cell_gov_logo"/>
<ImageView
android:id="@+id/userImage3"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginStart="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/userName"
app:layout_constraintTop_toTopOf="@+id/userName"
android:src="@drawable/indianoil"/>
<androidx.cardview.widget.CardView
android:id="@+id/userdetails"
android:layout_width="150dp"
android:layout_height="120dp"
android:layout_marginTop="24dp"
app:cardBackgroundColor="#FFFFFF"
app:cardCornerRadius="5dp"
app:layout_constraintTop_toBottomOf="@id/userImage"
app:cardElevation="0dp"
tools:ignore="MissingConstraints">
<TextView
android:id="@+id/name"
style="@style/title1_1"
android:layout_width="80dp"
android:layout_height="20dp"
android:layout_marginStart="16dp"
android:layout_marginTop="10dp"
android:gravity="center"
android:textColor="@color/black"
android:textSize="10sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/userImage"
android:text="name: Mariya" />
<TextView
android:id="@+id/dob"
style="@style/title1_1"
android:layout_width="80dp"
android:layout_height="20dp"
android:layout_marginStart="16dp"
android:gravity="center"
android:layout_marginTop="30dp"
android:textColor="@color/black"
android:textSize="10sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/name"
app:layout_constraintTop_toBottomOf="@id/name"
android:text="DOB: 1998" />
<TextView
android:id="@+id/gender"
style="@style/title1_1"
android:layout_width="80dp"
android:layout_height="20dp"
android:layout_marginStart="16dp"
android:gravity="center"
android:layout_marginTop="50dp"
android:textColor="@color/black"
android:textSize="10sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/dob"
app:layout_constraintTop_toBottomOf="@id/dob"
android:text="gender: female" />
<TextView
android:id="@+id/State"
style="@style/title1_1"
android:layout_width="130dp"
android:layout_height="20dp"
android:gravity="center"
android:layout_marginTop="70dp"
android:textColor="@color/black"
android:textSize="10sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/gender"
app:layout_constraintTop_toBottomOf="@id/gender"
android:text="State: Kerala" />
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:id="@+id/userdetails2"
android:layout_width="150dp"
android:layout_marginStart="10dp"
android:layout_height="120dp"
android:layout_marginTop="24dp"
app:cardBackgroundColor="#FFFFFF"
app:cardCornerRadius="5dp"
app:layout_constraintTop_toBottomOf="@id/userImage3"
app:layout_constraintStart_toEndOf="@+id/userdetails"
app:cardElevation="0dp">
<TextView
android:id="@+id/abhaid"
style="@style/title1_1"
android:layout_width="wrap_content"
android:layout_height="20dp"
android:layout_marginStart="16dp"
android:layout_marginTop="10dp"
android:gravity="start"
android:textColor="@color/black"
android:textSize="10sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/userImage3"
android:text="ABHA-ID: XXXX-8734" />
<TextView
android:id="@+id/blood"
style="@style/title1_1"
android:layout_width="wrap_content"
android:layout_height="20dp"
android:layout_marginStart="16dp"
android:layout_marginTop="30dp"
android:gravity="start"
android:textColor="@color/black"
android:textSize="10sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/userImage3"
android:text="Blood Group: O +ve" />
<TextView
android:id="@+id/sicklecell"
style="@style/title1_1"
android:layout_width="wrap_content"
android:layout_height="20dp"
android:layout_marginStart="6dp"
android:layout_marginTop="50dp"
android:gravity="start"
android:textColor="@color/black"
android:textSize="10sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/userImage3"
android:text="Sickle-Cell: Normal (HbA)" />
<TextView
android:id="@+id/issueDate"
style="@style/title1_1"
android:layout_width="wrap_content"
android:layout_height="20dp"
android:layout_marginStart="16dp"
android:layout_marginTop="70dp"
android:gravity="start"
android:textColor="@color/black"
android:textSize="10sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/userImage3"
android:text="Issue Date: Oct 2,2023" />
</androidx.cardview.widget.CardView>
<Button
android:id="@+id/digitalcard"
android:backgroundTint="#00008B"
app:cardBackgroundColor="#00008B"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="20dp"
android:text="@string/digital_card"
android:textColor="@color/white"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/userdetails" />
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:elevation="12dp"
android:indeterminate="true"
android:indeterminateDrawable="@drawable/progressbar_drawable"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -4,19 +4,33 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".presentation.dashboard.GalleryFragment">
tools:context="com.example.hpostesting.presentation.dashboard.GalleryFragment">
<TextView
android:id="@+id/text_gallery"
style="@style/title1"
android:layout_width="match_parent"
<Button
android:id="@+id/btn_submit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="24dp"
android:textAlignment="center"
android:textSize="20sp"
android:text="@string/to_be_launched_in_next_version_of_the_app"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:text="@string/check_buffer"
android:textColor="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btn_diagnostics"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:text="@string/diagnostics"
android:textColor="@color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_submit" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,187 @@
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.example.hpostesting.presentation.buffercheck.HemoCubeBufferCheckFragment">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_parent"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_title"
style="@style/title1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:text="@string/Instructions"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_subtitle2"
style="@style/title2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:text="@string/step4"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_title" />
<!-- <TextView-->
<!-- android:id="@+id/tv_subtitle3"-->
<!-- style="@style/title2"-->
<!-- android:layout_width="0dp"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_marginHorizontal="24dp"-->
<!-- android:layout_marginTop="16dp"-->
<!-- android:text="@string/step5"-->
<!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toBottomOf="@id/tv_subtitle2" />-->
<TextView
android:id="@+id/tv_name"
style="@style/title2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_submit" />
<TextView
android:id="@+id/tv_subtitle4"
style="@style/title1_1"
android:layout_width="0dp"
android:layout_height="80dp"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:gravity="center"
android:textColor="@color/red"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle2" />
<!-- <Button-->
<!-- android:visibility="gone"-->
<!-- android:id="@+id/btn_samplestart"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_marginHorizontal="16dp"-->
<!-- android:layout_marginTop="24dp"-->
<!-- android:clickable="false"-->
<!-- android:text="@string/Start_Sample"-->
<!-- android:textColor="@color/white"-->
<!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toBottomOf="@id/til_blood_group" />-->
<!-- <Button-->
<!-- android:id="@+id/btn_placebuffer"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_marginHorizontal="16dp"-->
<!-- android:layout_marginTop="24dp"-->
<!-- android:clickable="false"-->
<!-- android:text="@string/place_buffer"-->
<!-- android:textColor="@color/white"-->
<!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toBottomOf="@id/btn_submit" />-->
<Button
android:id="@+id/btn_submit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:text="@string/submit"
android:textColor="@color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle4" />
<!-- <com.google.android.material.textfield.TextInputLayout-->
<!-- android:id="@+id/til_blood_group"-->
<!-- style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_marginHorizontal="24dp"-->
<!-- android:layout_marginTop="16dp"-->
<!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toBottomOf="@id/tv_subtitle4">-->
<!-- <AutoCompleteTextView-->
<!-- android:id="@+id/et_blood_group"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:hint="@string/select_blood_group"-->
<!-- android:inputType="none"-->
<!-- android:labelFor="@id/til_blood_group"-->
<!-- app:simpleItems="@array/blood_group" />-->
<!-- </com.google.android.material.textfield.TextInputLayout>-->
<!-- <Button-->
<!-- android:id="@+id/btn_kit"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_margin="10dp"-->
<!-- android:text="@string/new_kit"-->
<!-- android:textColor="@color/white"-->
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
<!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintStart_toStartOf="parent" />-->
<!-- <Button-->
<!-- android:id="@+id/btn_buffer"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:text="@string/new_buffer"-->
<!-- android:textColor="@color/white"-->
<!-- android:layout_margin="10dp"-->
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintEnd_toStartOf="@id/btn_kit"/>-->
<!-- <Button-->
<!-- android:id="@+id/btn_read"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:text="@string/read"-->
<!-- android:layout_margin="16dp"-->
<!-- android:clickable="false"-->
<!-- app:layout_constraintTop_toBottomOf="@id/btn_set_reference"-->
<!-- app:layout_constraintStart_toStartOf="parent" />-->
<!-- </androidx.constraintlayout.widget.ConstraintLayout>-->
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:elevation="12dp"
android:indeterminate="true"
android:indeterminateDrawable="@drawable/progressbar_drawable"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@@ -27,22 +27,36 @@
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:text="@string/step4"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_title" />
<!-- <TextView-->
<!-- android:id="@+id/tv_subtitle3"-->
<!-- style="@style/title2"-->
<!-- android:layout_width="0dp"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_marginHorizontal="24dp"-->
<!-- android:layout_marginTop="16dp"-->
<!-- android:text="@string/step5"-->
<!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toBottomOf="@id/tv_subtitle2" />-->
<TextView
android:id="@+id/tv_subtitle3"
android:id="@+id/tv_name"
style="@style/title2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:text="@string/step5"
android:gravity="center"
android:padding="12dp"
android:layout_marginTop="26dp"
android:textFontWeight="700"
android:text="Name: SMI\n ID: 1672282828"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle2" />
tools:ignore="MissingConstraints" />
<TextView
android:id="@+id/tv_subtitle4"
@@ -50,15 +64,120 @@
android:layout_width="0dp"
android:layout_height="80dp"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:layout_marginTop="72dp"
android:gravity="center"
android:textColor="@color/red"
android:textSize="22sp"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle3" />
app:layout_constraintTop_toBottomOf="@id/et_abha_id" />
<!-- <Button-->
<!-- android:visibility="gone"-->
<!-- android:id="@+id/btn_samplestart"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_marginHorizontal="16dp"-->
<!-- android:layout_marginTop="24dp"-->
<!-- android:clickable="false"-->
<!-- android:text="@string/Start_Sample"-->
<!-- android:textColor="@color/white"-->
<!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toBottomOf="@id/til_blood_group" />-->
<!-- <Button-->
<!-- android:id="@+id/btn_placebuffer"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_marginHorizontal="16dp"-->
<!-- android:layout_marginTop="24dp"-->
<!-- android:clickable="false"-->
<!-- android:text="@string/place_buffer"-->
<!-- android:textColor="@color/white"-->
<!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toBottomOf="@id/btn_submit" />-->
<TextView
android:id="@+id/tv_title2"
style="@style/title1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="48dp"
android:text="@string/enter_kit_serial_number_manually"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="MissingConstraints" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/et_abha_id"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="20dp"
app:layout_constraintEnd_toStartOf="@id/btn_go"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_title2">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/name_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLength="17"
android:inputType="text"
android:hint="@string/serial_number" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_go"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="24dp"
android:text="@string/go"
app:cornerRadius="16dp"
app:layout_constraintBottom_toBottomOf="@id/et_abha_id"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toEndOf="@id/et_abha_id"
app:layout_constraintTop_toTopOf="@id/et_abha_id" />
<Button
android:visibility="gone"
android:id="@+id/btn_samplestart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:text="@string/Start_Sample"
android:textColor="@color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_placebuffer" />
<Button
android:id="@+id/btn_placebuffer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:text="@string/place_buffer"
android:textColor="@color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_submit" />
<Button
android:visibility="gone"
android:id="@+id/btn_submit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -69,65 +188,51 @@
android:textColor="@color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/til_blood_group" />
app:layout_constraintTop_toBottomOf="@id/tv_subtitle4" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/til_blood_group"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
<TextView
android:id="@+id/error_message"
style="@style/title1_1"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="40dp"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:layout_marginTop="72dp"
android:gravity="center"
android:textColor="@color/red"
android:textSize="12sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle4">
app:layout_constraintTop_toBottomOf="@id/btn_submit" />
<AutoCompleteTextView
android:id="@+id/et_blood_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/select_blood_group"
android:inputType="none"
android:labelFor="@id/til_blood_group"
app:simpleItems="@array/blood_group" />
</com.google.android.material.textfield.TextInputLayout>
<TextView
android:id="@+id/tv_device_messages"
style="@style/title1_1"
android:visibility="gone"
android:layout_width="0dp"
android:layout_height="180dp"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="72dp"
android:gravity="center"
android:textColor="@color/black"
android:textSize="11sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/error_message" />
<Button
android:id="@+id/btn_kit"
android:visibility="gone"
android:id="@+id/btn_digitalCard"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="@string/new_kit"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:text="DigitalCard View"
android:textColor="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<!-- <Button-->
<!-- android:id="@+id/btn_buffer"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:text="@string/new_buffer"-->
<!-- android:textColor="@color/white"-->
<!-- android:layout_margin="10dp"-->
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintEnd_toStartOf="@id/btn_kit"/>-->
<!-- <Button-->
<!-- android:id="@+id/btn_read"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:text="@string/read"-->
<!-- android:layout_margin="16dp"-->
<!-- android:clickable="false"-->
<!-- app:layout_constraintTop_toBottomOf="@id/btn_set_reference"-->
<!-- app:layout_constraintStart_toStartOf="parent" />-->
<!-- </androidx.constraintlayout.widget.ConstraintLayout>-->
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/error_message" />
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
@@ -142,7 +247,6 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@@ -22,7 +22,7 @@
android:id="@+id/internetNotAvailableCL"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:visibility="visible"
android:padding="24dp">
<TextView
@@ -57,6 +57,27 @@
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/til_blood_group"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/til_name">
<AutoCompleteTextView
android:id="@+id/et_blood_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/select_blood_group"
android:inputType="none"
android:labelFor="@id/til_blood_group"
app:simpleItems="@array/blood_group" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_submit"
android:layout_width="match_parent"
@@ -66,7 +87,18 @@
app:cornerRadius="100dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/til_name" />
app:layout_constraintTop_toBottomOf="@+id/til_blood_group" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_order_offline"
android:layout_width="0dp"
android:layout_height="0dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_submit"
tools:listitem="@layout/offline_user_list_view" />
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -74,7 +106,7 @@
android:id="@+id/internetAvailableCL"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible"
android:visibility="gone"
android:padding="24dp">
<TextView
@@ -194,6 +226,27 @@
app:layout_constraintTop_toBottomOf="@+id/radioGroup"
tools:listitem="@layout/user_item_view"/>
<TextView
android:id="@+id/label"
style="@style/title1_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/new_kit"
app:layout_constraintBottom_toTopOf="@+id/btnNewKit"
app:layout_constraintEnd_toEndOf="parent" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/btnNewKit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:backgroundTint="@color/primary"
android:contentDescription="@string/new_kit"
android:src="@drawable/ic_add"
app:elevation="1dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -4,19 +4,6 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".presentation.dashboard.SlideshowFragment">
tools:context="com.example.hpostesting.presentation.dashboard.SlideshowFragment">
<TextView
android:id="@+id/text_slideshow"
style="@style/title1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="24dp"
android:textAlignment="center"
android:textSize="20sp"
android:text="@string/to_be_launched_in_next_version_of_the_app"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,23 @@
<!-- language_spinner_preference.xml -->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!-- Select Language -->
<TextView
android:id="@+id/textSelectLanguage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Select Language"
android:textStyle="bold"
android:textSize="18sp"/>
<!-- Language Spinner -->
<Spinner
android:id="@+id/languageSpinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"/>
</LinearLayout>

View File

@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.cardview.widget.CardView
android:id="@+id/userCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
app:cardBackgroundColor="@color/primary_light"
app:cardCornerRadius="25dp"
app:cardElevation="0dp"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="12dp">
<TextView
android:id="@+id/userID"
style="@style/title1_1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:gravity="start"
android:textColor="@color/black"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Name: MohamedKaif" />
<TextView
android:id="@+id/bloodGroup"
style="@style/title1_1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="4dp"
android:gravity="start"
android:textColor="@color/black"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/userID"
tools:text="UserID: MohamedKaif" />
<TextView
android:id="@+id/time"
style="@style/title1_1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="4dp"
android:gravity="start"
android:textColor="@color/black"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/bloodGroup"
tools:text="Test Status: Completed" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -72,6 +72,25 @@
app:layout_constraintTop_toBottomOf="@id/userId"
tools:text="Test Status: Completed"/>
<Button
android:id="@+id/btn_startIncubation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:text="@string/start_incubation"
android:visibility="gone"
android:textColor="@color/white"
app:layout_constraintStart_toEndOf="@+id/btn_blood"
app:layout_constraintBottom_toBottomOf="@+id/btn_blood" />
<Button
android:id="@+id/btn_blood"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:text="@string/blood_group"
android:textColor="@color/white"
app:layout_constraintEnd_toStartOf="@+id/btn_startIncubation"
app:layout_constraintTop_toBottomOf="@id/teststatus" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/navigation_graph"
app:startDestination="@id/hemoCubeFragment">
<fragment
android:id="@+id/hemoCubeFragment"
android:name="com.example.hpostesting.presentation.hemocube.HemoCubeFragment"
android:label="fragment_hemo_cube_reference"
tools:layout="@layout/fragment_hemo_cube_reference" >
<action
android:id="@+id/action_hemoCubeFragment_to_digitalCardFragment"
app:destination="@id/digitalCardFragment" />
</fragment>
<fragment
android:id="@+id/digitalCardFragment"
android:name="com.example.hpostesting.presentation.hemocube.DigitalCardFragment"
android:label="fragment_digital_card"
tools:layout="@layout/fragment_digital_card" />
</navigation>

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