Compare commits

...

42 Commits

Author SHA1 Message Date
Mariya
fbce8cad63 Changes on labels added for Refresh Buffer and Cuvette Absent 2024-05-08 15:14:19 +05:30
Mariya
ef620371f3 toast messages added for
If the entered kit number is valid, the application shall proceed with the intended operation.
provide a clear indication that the application is in offline mode.
2024-05-08 14:51:34 +05:30
Mariya
3fd36080ec Merge remote-tracking branch 'origin/dev-without-firebase-integration' into dev-without-firebase-integration 2024-05-08 12:11:13 +05:30
Mariya
1f8f2010ca The application shall provide a confirmation message or indication upon successful data saving. - Added ID in toast 2024-05-08 12:10:50 +05:30
chandrashekhar reddy
c4ca1b7169 device Diagnostics updated the screen with progress bar 2024-04-30 18:05:42 +05:30
Mariya
904c0fd2ad Added condition check for firebase integration enable, for trueheme device, if it enables only the data will upload to firebase, otherwise it will go to molbio server only, 2024-04-29 13:41:04 +05:30
Mariya
d7ef2b7ef9 removed birthyear,bloodgroup, gender, abhaid, UserImage field for molbio data, and device percentage is also changed and dao changed for pending userdata molbio flag 2024-04-25 17:02:15 +05:30
Mariya
efe9d83e2b removed birthyear,bloodgroup, gender, abhaid, UserImage field for molbio data 2024-04-25 16:29:40 +05:30
Mariya
74d8479aab integration for apk file with checksum added 2024-04-18 17:23:27 +05:30
Mariya
b9a5b1c763 location changes is done in home fragment,for to pass the ip address in login screen, and device id fetching from local file also added 2024-04-05 16:15:57 +05:30
Mariya
748af4155f changed the time zone for result upload for molbio 2024-04-05 14:29:26 +05:30
chandrashekhar reddy
0445e28fc1 DiagnosticsFragment uncommented the api parameters and we can test 2024-04-05 14:25:43 +05:30
chandrashekhar reddy
aa4cf1b7c3 Added details in AboutFragment about SMI 2024-04-03 16:58:35 +05:30
chandrashekhar reddy
0c155ae131 Removed the finish activity in HomeFragment while calling kit activity so onback pressed app will not exit instead come back to home 2024-04-03 16:29:27 +05:30
chandrashekhar reddy
4b60188582 For security added sql cipher to room and removed bug in ActivitiesFragment 2024-04-03 13:38:50 +05:30
chandrashekhar reddy
f258cc3440 Device provision show toast is device already registered 2024-04-02 16:10:17 +05:30
chandrashekhar reddy
c91082ee6d Location fetched as Ip address and send to server 2024-04-01 17:47:01 +05:30
chandrashekhar reddy
e78ae3a29e Merge remote-tracking branch 'origin/dev-without-firebase-integration' into dev-without-firebase-integration 2024-04-01 14:49:23 +05:30
chandrashekhar reddy
e112035756 Result screen stuck, issue is solves 2024-04-01 14:49:09 +05:30
Mariya
1031551bca Merge remote-tracking branch 'origin/dev-without-firebase-integration' into dev-without-firebase-integration 2024-04-01 13:08:41 +05:30
Mariya
9c4a4290bb nats certificate downloading only calling once code added 2024-04-01 13:07:46 +05:30
chandrashekhar reddy
f578c17b5f Duplicate test data in local database removed by adding update query in HemoCubeDao 2024-04-01 11:36:00 +05:30
Mariya
fdb63d808d Merge remote-tracking branch 'origin/dev-without-firebase-integration' into dev-without-firebase-integration 2024-03-30 16:11:31 +05:30
Mariya
dd2e115995 changes added for without firebase result submit 2024-03-30 16:11:10 +05:30
chandrashekhar reddy
70f703199a HemoCubeFragment test cases updated 2024-03-30 15:41:31 +05:30
chandrashekhar reddy
d5955507b8 HemoCubeFragment firebase upload committed 2024-03-30 14:06:57 +05:30
chandrashekhar reddy
31e92a0cbb HemoCubeFragment changes in device ratio and borderline metric 2024-03-30 13:45:47 +05:30
chandrashekhar reddy
96ba5ce92f HomeFragment network change edited 2024-03-28 16:32:21 +05:30
chandrashekhar reddy
0635cb6813 Location fetch code added in login fragment without gps 2024-03-27 15:13:37 +05:30
chandrashekhar reddy
326936fc26 Merge remote-tracking branch 'origin/dev' into dev
# Conflicts:
#	app/src/main/java/com/example/hpostesting/data/constant/Constants.kt
#	app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt
2024-03-27 15:12:57 +05:30
chandrashekhar reddy
da195ab573 Location fetch code added in login fragment without gps 2024-03-27 15:10:06 +05:30
Mariya
47f586ff63 Merge remote-tracking branch 'origin/dev' into dev
# Conflicts:
#	app/src/main/res/values-hi/strings.xml
#	app/src/main/res/values-kn/strings.xml
#	app/src/main/res/values/strings.xml
2024-03-26 12:32:30 +05:30
Mariya
9c22bdabf9 Lab Name is Added inside the settings screen, and added for molbio login request 2024-03-26 12:30:51 +05:30
chandrashekhar reddy
0a103795cd About screen added in drawer 2024-03-25 17:12:24 +05:30
Mariya
541b555c05 Panel screen specific options will only visible to ADMIN only 2024-03-23 17:22:32 +05:30
Mariya
d14afa0942 Merge remote-tracking branch 'origin/dev-usb-terminal-inapp' into dev 2024-03-23 17:02:12 +05:30
Mariya
71a364a9a2 csv file downloading changes added 2024-03-23 15:29:40 +05:30
Mariya
9aa89f810e error fixing 2024-03-23 12:21:49 +05:30
chandrashekhar reddy
262c3c19d2 new changes in UsbTerminalActivity 2024-03-22 15:47:47 +05:30
Mariya
12af81d142 error fixing 2024-03-22 15:16:09 +05:30
Mariya
29115786fa changed reverted back for csv option for ADMIN 2024-03-21 20:53:48 +05:30
Mariya
614192c04c Revert "changes made for dropdownlist for pq , for iocl 122 version added, for E command , RS AND RC changed to ES and EC"
This reverts commit 4fe1a0e187.
2024-03-20 18:04:22 +05:30
53 changed files with 2518 additions and 695 deletions

View File

@@ -16,7 +16,7 @@ android {
// dev -> development, quality -> qc, uat -> User Acceptance Testing, preprod -> preproduction, prod -> production, iocl -> iocl-iisc production // dev -> development, quality -> qc, uat -> User Acceptance Testing, preprod -> preproduction, prod -> production, iocl -> iocl-iisc production
defaultConfig { defaultConfig {
applicationId "in.sminnovations.hpostesting.iocl" applicationId "in.sminnovations.hpostesting.dev"
minSdk 21 minSdk 21
targetSdk 34 targetSdk 34
versionCode 122 versionCode 122
@@ -62,6 +62,7 @@ android {
dependencies { dependencies {
implementation "com.google.dagger:hilt-android:2.46" implementation "com.google.dagger:hilt-android:2.46"
implementation 'androidx.activity:activity:1.8.0'
kapt "com.google.dagger:hilt-android-compiler:2.46" kapt "com.google.dagger:hilt-android-compiler:2.46"
implementation 'androidx.core:core-ktx:1.12.0' implementation 'androidx.core:core-ktx:1.12.0'
@@ -137,6 +138,7 @@ dependencies {
implementation "androidx.room:room-ktx:2.6.1" implementation "androidx.room:room-ktx:2.6.1"
implementation "androidx.room:room-runtime:2.6.1" implementation "androidx.room:room-runtime:2.6.1"
kapt ("androidx.room:room-compiler:2.6.1") kapt ("androidx.room:room-compiler:2.6.1")
implementation "net.zetetic:android-database-sqlcipher:4.4.0"
//image //image
implementation 'com.github.bumptech.glide:glide:4.13.2' implementation 'com.github.bumptech.glide:glide:4.13.2'
@@ -166,5 +168,6 @@ dependencies {
implementation fileTree(dir: 'libs', include: ['*.aar']) implementation fileTree(dir: 'libs', include: ['*.aar'])
implementation 'io.nats:jnats:2.11.4' implementation 'io.nats:jnats:2.11.4'
implementation 'org.apache.commons:commons-math3:3.6.1'
} }

View File

@@ -1,26 +1,205 @@
{ {
"project_info": { "project_info": {
"project_number": "630821402019", "project_number": "650071678820",
"project_id": "iocl-iisc", "project_id": "hpos-af3cc",
"storage_bucket": "iocl-iisc.appspot.com" "storage_bucket": "hpos-af3cc.appspot.com"
}, },
"client": [ "client": [
{ {
"client_info": { "client_info": {
"mobilesdk_app_id": "1:630821402019:android:ed56bae066ac32b51dd616", "mobilesdk_app_id": "1:650071678820:android:f1435a1c07f710036c6471",
"android_client_info": { "android_client_info": {
"package_name": "in.sminnovations.hpostesting.iocl" "package_name": "com.example.hposconsentform"
} }
}, },
"oauth_client": [], "oauth_client": [
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [ "api_key": [
{ {
"current_key": "AIzaSyABIdxI89eTZ8BqU2cIoJOgJ1lS1cFLCtQ" "current_key": "AIzaSyAVdNGCev_AFX0qmuZJF6kxzRzXUTeAW5I"
} }
], ],
"services": { "services": {
"appinvite_service": { "appinvite_service": {
"other_platform_oauth_client": [] "other_platform_oauth_client": [
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:650071678820:android:7865bef608cdee6f6c6471",
"android_client_info": {
"package_name": "com.smi.counselling"
}
},
"oauth_client": [
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyAVdNGCev_AFX0qmuZJF6kxzRzXUTeAW5I"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:650071678820:android:2925e9ce3417d2386c6471",
"android_client_info": {
"package_name": "in.sminnovations.hemocube"
}
},
"oauth_client": [
{
"client_id": "650071678820-srhm9spm9hjn4frcd3r6o02gdhdbtd15.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "in.sminnovations.hemocube",
"certificate_hash": "7714b9268a81d0cf0fb178b0af8dbb630f8fc70a"
}
},
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyAVdNGCev_AFX0qmuZJF6kxzRzXUTeAW5I"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:650071678820:android:7569c1cad4fc99916c6471",
"android_client_info": {
"package_name": "in.sminnovations.hposregistration"
}
},
"oauth_client": [
{
"client_id": "650071678820-70kp5jvjda4r5diqch2kn4lc40p4f42g.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "in.sminnovations.hposregistration",
"certificate_hash": "7714b9268a81d0cf0fb178b0af8dbb630f8fc70a"
}
},
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyAVdNGCev_AFX0qmuZJF6kxzRzXUTeAW5I"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:650071678820:android:f96be19e5d43102b6c6471",
"android_client_info": {
"package_name": "in.sminnovations.hpostesting"
}
},
"oauth_client": [
{
"client_id": "650071678820-l87dnr0bdj95get0khgnvfv2an1k6ogq.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "in.sminnovations.hpostesting",
"certificate_hash": "7714b9268a81d0cf0fb178b0af8dbb630f8fc70a"
}
},
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyAVdNGCev_AFX0qmuZJF6kxzRzXUTeAW5I"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:650071678820:android:a53292637abb7c0d6c6471",
"android_client_info": {
"package_name": "in.sminnovations.hpostesting.dev"
}
},
"oauth_client": [
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyAVdNGCev_AFX0qmuZJF6kxzRzXUTeAW5I"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
]
} }
} }
} }

View File

@@ -1,17 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!--
~ // Copyright (c) 2024 ShanMukha Innovations Pvt. Ltd. All rights reserved.
~ // Notice: All information contained herein is, and remains
~ // the property of ShanMukha Innovations Pvt. Ltd. and its suppliers,
~ // if any. The intellectual and technical concepts contained
~ // herein are proprietary to ShanMukha Innovations Pvt. Ltd.
~ // and its suppliers and may be covered by Indian and Foreign Patents,
~ // patents in process, and are protected by trade secret or copyright law.
~ // Dissemination of this information or reproduction of this material
~ // is strictly forbidden unless prior written permission is obtained
~ // from ShanMukha Innovations Pvt. Ltd.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
@@ -19,7 +6,6 @@
<uses-permission android:name="android.permission.WRITE_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.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" /> <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission <uses-permission
android:name="android.permission.BATTERY_STATS" android:name="android.permission.BATTERY_STATS"
tools:ignore="ProtectedPermissions" /> tools:ignore="ProtectedPermissions" />
@@ -38,16 +24,20 @@
<application <application
android:name="com.example.hpostesting.HPOSTestingApplication" android:name="com.example.hpostesting.HPOSTestingApplication"
android:largeHeap="true"
android:allowBackup="true" android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules" android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules" android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/hpos_icon" android:icon="@mipmap/hpos_icon"
android:label="@string/app_name" android:label="@string/app_name"
android:largeHeap="true"
android:roundIcon="@mipmap/hpos_icon_round" android:roundIcon="@mipmap/hpos_icon_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.HPOSTesting" android:theme="@style/Theme.HPOSTesting"
tools:targetApi="31"> tools:targetApi="31">
<activity
android:name="com.example.hpostesting.presentation.usb_teminal.UsbTerminalActivity"
android:screenOrientation="portrait"
android:exported="false" />
<activity <activity
android:name="com.example.hpostesting.presentation.deviceinfo.DeviceActivity" android:name="com.example.hpostesting.presentation.deviceinfo.DeviceActivity"
android:exported="false" /> android:exported="false" />
@@ -73,23 +63,20 @@
<activity <activity
android:name="com.example.hpostesting.presentation.calibration.CalibrationActivity" android:name="com.example.hpostesting.presentation.calibration.CalibrationActivity"
android:exported="false" android:exported="false"
android:theme="@style/Theme.HPOS.NoActionBar"/> android:theme="@style/Theme.HPOS.NoActionBar" />
<activity <activity
android:name="com.example.hpostesting.presentation.assurance.AssuranceControlsActivity" android:name="com.example.hpostesting.presentation.assurance.AssuranceControlsActivity"
android:exported="false" android:exported="false"
android:screenOrientation="portrait" android:screenOrientation="portrait"
android:theme="@style/Theme.HPOS.NoActionBar"/> android:theme="@style/Theme.HPOS.NoActionBar" />
<activity <activity
android:name="com.example.hpostesting.presentation.hemocube.HemocubeActivity" android:name="com.example.hpostesting.presentation.hemocube.HemocubeActivity"
android:exported="false" android:exported="false"
android:noHistory="true" android:noHistory="true"
android:screenOrientation="portrait"
android:parentActivityName="com.example.hpostesting.presentation.MainActivity" android:parentActivityName="com.example.hpostesting.presentation.MainActivity"
android:screenOrientation="portrait"
android:theme="@style/Theme.HPOS.NoActionBar" android:theme="@style/Theme.HPOS.NoActionBar"
android:windowSoftInputMode="adjustPan" /> android:windowSoftInputMode="adjustPan" />
<activity <activity
android:name="com.example.hpostesting.presentation.trueheme.TrueHemeActivity" android:name="com.example.hpostesting.presentation.trueheme.TrueHemeActivity"
android:exported="false" android:exported="false"
@@ -97,7 +84,6 @@
android:parentActivityName="com.example.hpostesting.presentation.MainActivity" android:parentActivityName="com.example.hpostesting.presentation.MainActivity"
android:theme="@style/Theme.HPOS.NoActionBar" android:theme="@style/Theme.HPOS.NoActionBar"
android:windowSoftInputMode="adjustPan" /> android:windowSoftInputMode="adjustPan" />
<activity <activity
android:name="com.example.hpostesting.presentation.buffercheck.HemocubeBufferCheckActivity" android:name="com.example.hpostesting.presentation.buffercheck.HemocubeBufferCheckActivity"
android:exported="false" android:exported="false"
@@ -114,20 +100,21 @@
android:name="com.example.hpostesting.presentation.dashboard.DashboardActivity" android:name="com.example.hpostesting.presentation.dashboard.DashboardActivity"
android:exported="false" android:exported="false"
android:label="@string/title_activity_dashboard" android:label="@string/title_activity_dashboard"
android:theme="@style/Theme.HPOS.NoActionBar"
android:screenOrientation="portrait" android:screenOrientation="portrait"
android:theme="@style/Theme.HPOS.NoActionBar"
tools:ignore="AppLinkUrlError,MissingClass"> tools:ignore="AppLinkUrlError,MissingClass">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<data android:scheme="content" /> <data android:scheme="content" />
<data android:scheme="file" /> <data android:scheme="file" />
<data android:mimeType="application/vnd.android.package-archive" /> <data android:mimeType="application/vnd.android.package-archive" />
</intent-filter> </intent-filter>
</activity> </activity>
<service <service
android:name="com.example.hpostesting.util.UsbService" android:name="com.example.hpostesting.util.UsbService"
android:enabled="true" android:enabled="true"
@@ -139,16 +126,16 @@
android:noHistory="true" android:noHistory="true"
android:theme="@style/AppTheme.NoActionBar"> android:theme="@style/AppTheme.NoActionBar">
<!-- <intent-filter>--> <!-- <intent-filter>-->
<!-- <action android:name="android.intent.action.MAIN"/>--> <!-- <action android:name="android.intent.action.MAIN" />-->
<!-- <category android:name="android.intent.category.LAUNCHER"/>--> <!-- <category android:name="android.intent.category.HOME" />-->
<!-- <category android:name="android.intent.category.DEFAULT" />-->
<!-- <category android:name="android.intent.category.MONKEY"/>-->
<!-- <category android:name="android.intent.category.LAUNCHER_APP" />-->
<!-- </intent-filter>--> <!-- </intent-filter>-->
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.MONKEY"/>
<category android:name="android.intent.category.LAUNCHER_APP" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
@@ -185,8 +172,7 @@
android:name="com.journeyapps.barcodescanner.CaptureActivity" android:name="com.journeyapps.barcodescanner.CaptureActivity"
android:screenOrientation="portrait" android:screenOrientation="portrait"
android:stateNotNeeded="true" android:stateNotNeeded="true"
tools:replace="android:screenOrientation" /> tools:replace="android:screenOrientation" /> <!-- ${applicationId} -->
<!-- ${applicationId}-->
<provider <provider
android:name="androidx.core.content.FileProvider" android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider" android:authorities="${applicationId}.fileprovider"
@@ -196,7 +182,6 @@
android:name="android.support.FILE_PROVIDER_PATHS" android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" /> android:resource="@xml/file_paths" />
</provider> </provider>
</application> </application>
</manifest> </manifest>

View File

@@ -23,6 +23,7 @@ import com.example.hpostesting.data.model.updates.CheckUpdateResponse
import com.example.hpostesting.data.model.updates.DeviceUpdateRequest import com.example.hpostesting.data.model.updates.DeviceUpdateRequest
import okhttp3.MultipartBody import okhttp3.MultipartBody
import okhttp3.ResponseBody import okhttp3.ResponseBody
import retrofit2.Response
import retrofit2.http.Body import retrofit2.http.Body
import retrofit2.http.GET import retrofit2.http.GET
import retrofit2.http.Multipart import retrofit2.http.Multipart
@@ -45,7 +46,7 @@ interface MolbioResultApi {
@POST("deviceService/device/getUpdate") @POST("deviceService/device/getUpdate")
suspend fun deviceUpdate( suspend fun deviceUpdate(
@Body deviceUpdateRequest: DeviceUpdateRequest, @Body deviceUpdateRequest: DeviceUpdateRequest,
): ResponseBody ): Response<ResponseBody>
@GET("deviceService/device/getClientCertificate") @GET("deviceService/device/getClientCertificate")
suspend fun downloadClientCertificate( suspend fun downloadClientCertificate(

View File

@@ -16,12 +16,13 @@ package com.example.hpostesting.data.constant
object Constants { object Constants {
const val ACTION_USB_PERMISSION = "shanmukha.in.sickle_cell.USB_PERMISSION" const val ACTION_USB_PERMISSION = "shanmukha.in.sickle_cell.USB_PERMISSION"
const val HEMOCUBE_USB_PERMISSION = "shanmukha.in.sickle_cell_homocube.USB_PERMISSION" const val HEMOCUBE_USB_PERMISSION = "shanmukha.in.sickle_cell_homocube.USB_PERMISSION"
const val passphrase = "smi_#@sql"
const val BASE_URL = "www.google.com" const val BASE_URL = "www.google.com"
const val DOCUMENT_ID_FOR_UPDATE ="2o71vBKLqdgEKYtFG8Lb" const val DOCUMENT_ID_FOR_UPDATE ="2o71vBKLqdgEKYtFG8Lb"
const val ABHA_APP_PACKAGE = "in.ndhm.phr" const val ABHA_APP_PACKAGE = "in.ndhm.phr"
const val MOLBIO_INTEGRATION = true const val MOLBIO_INTEGRATION = true
const val FIREBASE_INTEGRATION = false
const val deviceProvisionEmail = "HPOS_provisioner@bigtec.co.in" const val deviceProvisionEmail = "HPOS_provisioner@bigtec.co.in"
const val deviceProvisionPassword = "f2ab0e7f9d69" const val deviceProvisionPassword = "f2ab0e7f9d69"
const val DEVICE_ID_API = "deviceIDAPI" const val DEVICE_ID_API = "deviceIDAPI"
@@ -259,7 +260,9 @@ object Constants {
const val BUFFER_VALUE_3 = "BufferValue3" const val BUFFER_VALUE_3 = "BufferValue3"
const val BUFFER_VALUE_4 = "BufferValue4" const val BUFFER_VALUE_4 = "BufferValue4"
const val DEVICE_ID = "DEVICE_ID" const val DEVICE_ID = "DEVICE_ID"
const val LABNAME = "LAB_NAME"
const val IS_TOKEN_AVAILABLE = "IS_TOKEN_AVAILABLE"
const val BUFFER_LED_LOWER_BOUND = 21000 const val BUFFER_LED_LOWER_BOUND = 21000
const val BUFFER_LED_UPPER_BOUND = 23500 const val BUFFER_LED_UPPER_BOUND = 23500
@@ -1242,7 +1245,7 @@ object Constants {
const val PQ_MODE = true const val PQ_MODE = true
const val READINGS_PER_SAMPLE = 1 const val READINGS_PER_SAMPLE = 1
const val MINIMUM_BATTERY_LEVEL = 0 const val MINIMUM_BATTERY_LEVEL = 40F
val BUFFER_INTENSITY_THRESHOLDS: Map<String, List<List<Int>>> = mapOf<String, List<List<Int>>>( val BUFFER_INTENSITY_THRESHOLDS: Map<String, List<List<Int>>> = mapOf<String, List<List<Int>>>(
"HCV-000-3001" to listOf( "HCV-000-3001" to listOf(

View File

@@ -38,6 +38,7 @@ object DataHolder {
var hemoCubeTestData: HemoCubeTestData? = null var hemoCubeTestData: HemoCubeTestData? = null
var kitSerial: String = "" var kitSerial: String = ""
var location: UserData.Location? = null var location: UserData.Location? = null
var ipAddress: String = "0.0"
var testExp: Boolean = true var testExp: Boolean = true
var hemocubeResult: Double? = null var hemocubeResult: Double? = null
} }

View File

@@ -26,10 +26,10 @@ interface HemoCubeDao {
@Query("SELECT * from hemo_cube_test_table") @Query("SELECT * from hemo_cube_test_table")
fun getAll(): LiveData<List<HemoCubeTestData>> fun getAll(): LiveData<List<HemoCubeTestData>>
@Query("SELECT * from hemo_cube_test_table WHERE molbioFlag=false") @Query("SELECT * from hemo_cube_test_table WHERE molbioFlag=0")
fun getMolbioPending(): List<HemoCubeTestData> fun getMolbioPending(): List<HemoCubeTestData>
@Query("SELECT * from hemo_cube_test_table WHERE localFlag=false") @Query("SELECT * from hemo_cube_test_table WHERE localFlag=0")
fun getFirebasePending():List<HemoCubeTestData> fun getFirebasePending():List<HemoCubeTestData>
@Insert(onConflict = OnConflictStrategy.REPLACE) @Insert(onConflict = OnConflictStrategy.REPLACE)
@@ -50,7 +50,8 @@ interface HemoCubeDao {
@Query("UPDATE hemo_cube_test_table SET isCSVCreated = :newValue WHERE _id = :id") @Query("UPDATE hemo_cube_test_table SET isCSVCreated = :newValue WHERE _id = :id")
suspend fun updateCSVFieldById(id: String, newValue: Boolean) suspend fun updateCSVFieldById(id: String, newValue: Boolean)
@Query("SELECT * from hemo_cube_test_table WHERE localFlag = 0") @Query("SELECT * from hemo_cube_test_table WHERE molbioFlag = 0")
fun getPendingUser(): LiveData<List<HemoCubeTestData>> fun getPendingUser(): LiveData<List<HemoCubeTestData>>
@Update
suspend fun updateTest(hemoCubeTestData: HemoCubeTestData)
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -43,6 +43,7 @@ data class UserData(
var result: TestRightResultType? = null, var result: TestRightResultType? = null,
var resultRatio: Double? = null, var resultRatio: Double? = null,
var prdClassification: String = "", var prdClassification: String = "",
var sampleid: Int = 0
) { ) {
enum class Gender { enum class Gender {
MALE, MALE,
@@ -60,6 +61,8 @@ fun UserData.toHemoCubeTestData() = HemoCubeTestData(
_id = _id, _id = _id,
name = name, name = name,
bloodGroup = bloodGroup, bloodGroup = bloodGroup,
sampleid = sampleid,
incubationTime = incubationTime,
birthYear = birthYear, birthYear = birthYear,
gender = gender, gender = gender,
state = state, state = state,

View File

@@ -45,6 +45,7 @@ import com.google.firebase.storage.ktx.storage
import kotlinx.coroutines.tasks.await import kotlinx.coroutines.tasks.await
import okhttp3.MultipartBody import okhttp3.MultipartBody
import okhttp3.ResponseBody import okhttp3.ResponseBody
import retrofit2.HttpException
import java.io.File import java.io.File
import java.net.ConnectException import java.net.ConnectException
import java.net.SocketTimeoutException import java.net.SocketTimeoutException
@@ -52,6 +53,7 @@ import javax.inject.Inject
import javax.inject.Named import javax.inject.Named
class NetworkException(message: String, cause: Throwable) : Exception(message, cause) class NetworkException(message: String, cause: Throwable) : Exception(message, cause)
class ValidationException(message: String) : Exception(message)
class DatabaseRepository @Inject constructor( class DatabaseRepository @Inject constructor(
@Named("Auth") private val molbioAuthApi: MolbioAuthApi, @Named("Auth") private val molbioAuthApi: MolbioAuthApi,
private val molbioResultApi: MolbioResultApi, private val molbioResultApi: MolbioResultApi,
@@ -64,6 +66,8 @@ class DatabaseRepository @Inject constructor(
return try { return try {
val response = apiCall.invoke() val response = apiCall.invoke()
Result.Success(response) Result.Success(response)
}catch (e: HttpException) {
Result.Error(ValidationException("Device Already Registered /"+e.message))
} catch (e: SocketTimeoutException) { } catch (e: SocketTimeoutException) {
Result.Error(NetworkException("Network timeout", e)) Result.Error(NetworkException("Network timeout", e))
} catch (e: ConnectException) { } catch (e: ConnectException) {
@@ -89,8 +93,8 @@ class DatabaseRepository @Inject constructor(
return safeApiCall { molbioResultApi.checkUpdate(checkUpdateRequest) } return safeApiCall { molbioResultApi.checkUpdate(checkUpdateRequest) }
} }
override suspend fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest): Result<ResponseBody> { override suspend fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest): retrofit2.Response<ResponseBody> {
return safeApiCall { molbioResultApi.deviceUpdate(deviceUpdateRequest) } return molbioResultApi.deviceUpdate(deviceUpdateRequest)
} }
override suspend fun deviceDiagnostics(deviceDiagnosticsRequest: DeviceDiagnosticsRequest): Result<DeviceDiagnosticsResponse> { override suspend fun deviceDiagnostics(deviceDiagnosticsRequest: DeviceDiagnosticsRequest): Result<DeviceDiagnosticsResponse> {

View File

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

View File

@@ -20,7 +20,7 @@ import android.content.res.AssetManager
import androidx.room.Room import androidx.room.Room
import com.example.hpostesting.data.api.MolbioAuthApi import com.example.hpostesting.data.api.MolbioAuthApi
import com.example.hpostesting.data.api.MolbioResultApi import com.example.hpostesting.data.api.MolbioResultApi
import com.example.hpostesting.util.PropertyProvider import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.dao.HemoCubeBufferDao import com.example.hpostesting.data.dao.HemoCubeBufferDao
import com.example.hpostesting.data.dao.HemoCubeDao import com.example.hpostesting.data.dao.HemoCubeDao
import com.example.hpostesting.data.dao.MyDatabase import com.example.hpostesting.data.dao.MyDatabase
@@ -37,12 +37,15 @@ import com.example.hpostesting.domain.SaveRawData
import com.example.hpostesting.domain.SaveRawDataTest import com.example.hpostesting.domain.SaveRawDataTest
import com.example.hpostesting.presentation.utils.UsbServiceListener import com.example.hpostesting.presentation.utils.UsbServiceListener
import com.example.hpostesting.presentation.utils.UsbServiceListenerImpl import com.example.hpostesting.presentation.utils.UsbServiceListenerImpl
import com.example.hpostesting.util.PropertyProvider
import com.example.hpostesting.util.PropertyProviderImpl import com.example.hpostesting.util.PropertyProviderImpl
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent import dagger.hilt.components.SingletonComponent
import net.sqlcipher.database.SQLiteDatabase
import net.sqlcipher.database.SupportFactory
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import retrofit2.Retrofit import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory import retrofit2.converter.gson.GsonConverterFactory
@@ -50,6 +53,7 @@ import java.util.concurrent.TimeUnit
import javax.inject.Named import javax.inject.Named
import javax.inject.Singleton import javax.inject.Singleton
@Module @Module
@InstallIn(SingletonComponent::class) @InstallIn(SingletonComponent::class)
object AppModule { object AppModule {
@@ -57,9 +61,12 @@ object AppModule {
@Provides @Provides
@Singleton @Singleton
fun provideMyDatabase(@ApplicationContext context: Context): MyDatabase { fun provideMyDatabase(@ApplicationContext context: Context): MyDatabase {
val passphraseBytes: ByteArray = SQLiteDatabase.getBytes(Constants.passphrase.toCharArray())
val factory = SupportFactory(passphraseBytes)
return Room.databaseBuilder( return Room.databaseBuilder(
context, MyDatabase::class.java, "my_database" context, MyDatabase::class.java, "my_database"
).fallbackToDestructiveMigration().build() ).openHelperFactory(factory).fallbackToDestructiveMigration().build()
} }
@Provides @Provides

View File

@@ -171,6 +171,12 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
binding.btnGo.setOnClickListener { binding.btnGo.setOnClickListener {
val serialNumber = binding.nameEditText.text.toString().trim() val serialNumber = binding.nameEditText.text.toString().trim()
if (serialNumber.isNotEmpty() && isSerialValid(serialNumber)) { if (serialNumber.isNotEmpty() && isSerialValid(serialNumber)) {
Toast.makeText(
applicationContext,
R.string.kit_update,
Toast.LENGTH_LONG
).show()
if (DataHolder.selectedTest == null) { if (DataHolder.selectedTest == null) {
with(sharedPreference.edit()) { with(sharedPreference.edit()) {
putString( putString(

View File

@@ -84,10 +84,10 @@ class MainActivity : AppCompatActivity() {
locationCallback = object : LocationCallback() { locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) { override fun onLocationResult(locationResult: LocationResult) {
locationResult.lastLocation?.let { location -> locationResult.lastLocation?.let { location ->
DataHolder.location = // DataHolder.location =
UserData.Location(location.latitude, location.longitude) // UserData.Location(location.latitude, location.longitude)
DataHolder.selectedTest?.location = // DataHolder.selectedTest?.location =
UserData.Location(location.latitude, location.longitude) // UserData.Location(location.latitude, location.longitude)
Log.i("Location", DataHolder.location.toString()) Log.i("Location", DataHolder.location.toString())
} }
} }
@@ -314,14 +314,14 @@ class MainActivity : AppCompatActivity() {
fusedLocationClient.lastLocation.addOnSuccessListener { location: Location? -> fusedLocationClient.lastLocation.addOnSuccessListener { location: Location? ->
location?.let { location?.let {
if (DataHolder.selectedTest != null) { if (DataHolder.selectedTest != null) {
DataHolder.selectedTest!!.location = // DataHolder.selectedTest!!.location =
UserData.Location(location.latitude, location.longitude) // UserData.Location(location.latitude, location.longitude)
} else { } else {
startActivity(Intent(this, DashboardActivity::class.java)) startActivity(Intent(this, DashboardActivity::class.java))
finish() finish()
} }
DataHolder.location = // DataHolder.location =
UserData.Location(location.latitude, location.longitude) // UserData.Location(location.latitude, location.longitude)
} ?: run { } ?: run {
requestLocationUpdates() requestLocationUpdates()
} }

View File

@@ -14,6 +14,7 @@
package com.example.hpostesting.presentation package com.example.hpostesting.presentation
import android.Manifest import android.Manifest
import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
@@ -33,6 +34,7 @@ import com.example.hpostesting.util.MyUtils
import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivitySplashBinding import `in`.sminnovations.hpostesting.databinding.ActivitySplashBinding
@SuppressLint("CustomSplashScreen")
class SplashActivity : AppCompatActivity() { class SplashActivity : AppCompatActivity() {
private lateinit var binding: ActivitySplashBinding private lateinit var binding: ActivitySplashBinding
@@ -64,6 +66,7 @@ class SplashActivity : AppCompatActivity() {
requestPermissions() requestPermissions()
} }
@SuppressLint("HardwareIds")
private fun setupStaticConstants() { private fun setupStaticConstants() {
DataHolder.mobileUniqueId = DataHolder.mobileUniqueId =
Settings.Secure.getString( Settings.Secure.getString(

View File

@@ -15,7 +15,10 @@ package com.example.hpostesting.presentation.adapter
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.res.Resources import android.content.res.Resources
import android.os.BatteryManager
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@@ -35,7 +38,7 @@ import java.util.Calendar
import java.util.Date import java.util.Date
import java.util.Locale import java.util.Locale
class OfflineUserListAdapter(private val view: View, private val batLevel: Int) : class OfflineUserListAdapter(private val view: View, private val batLevel: Int, private val fromWhere:String) :
RecyclerView.Adapter<OfflineUserListAdapter.OfflineUserListViewHolder>() { RecyclerView.Adapter<OfflineUserListAdapter.OfflineUserListViewHolder>() {
inner class OfflineUserListViewHolder(val binding: OfflineUserListViewBinding) : inner class OfflineUserListViewHolder(val binding: OfflineUserListViewBinding) :
@@ -88,58 +91,63 @@ class OfflineUserListAdapter(private val view: View, private val batLevel: Int)
} else { } else {
teststatus.text = view.context.getString(R.string.test_pending) teststatus.text = view.context.getString(R.string.test_pending)
} }
if(fromWhere == "Home"){
userCard.setOnClickListener { userCard.setOnClickListener {
if (false) { var batLevel = 50F
Toast.makeText( batLevel = getBatteryLevel()!!.toFloat()
view.context, if (batLevel < Constants.MINIMUM_BATTERY_LEVEL) {
view.context.getString(R.string.low_battery_warning),
Toast.LENGTH_SHORT
).show()
return@setOnClickListener
}
if (userList.testStatus != null) {
if (userList.testStatus!!) {
Toast.makeText( Toast.makeText(
view.context, view.context,
view.context.getString(R.string.test_already_conducted), view.context.getString(R.string.low_battery_warning),
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
} else { return@setOnClickListener
if (userList.incubationTime != "") { }
if (isBetween15And30Minutes(userList.incubationTime) < Constants.INCUBATION_TIME_MIN) { if (userList.testStatus != null) {
Toast.makeText( if (userList.testStatus!!) {
view.context,
view.context.getString(R.string.incubation_not_completed),
Toast.LENGTH_SHORT
).show()
} else
if (isBetween15And30Minutes(userList.incubationTime) > Constants.INCUBATION_TIME_MAX) {
Toast.makeText(
view.context,
view.context.getString(R.string.incubation_crossed_30_minutes),
Toast.LENGTH_SHORT
).show()
} else {
DataHolder.selectedTest = UserData(
_id = userList._id,
bloodGroup = userList.bloodGroup,
incubationTime = userList.incubationTime
)
view.findNavController()
.navigate(R.id.action_nav_home_to_mainActivity)
}
} else {
Toast.makeText( Toast.makeText(
view.context, view.context,
view.context.getString(R.string.incubation_not_started), view.context.getString(R.string.test_already_conducted),
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
} else {
if (userList.incubationTime != "") {
if (isBetween15And30Minutes(userList.incubationTime) < Constants.INCUBATION_TIME_MIN) {
Toast.makeText(
view.context,
view.context.getString(R.string.incubation_not_completed),
Toast.LENGTH_SHORT
).show()
} else
if (isBetween15And30Minutes(userList.incubationTime) > Constants.INCUBATION_TIME_MAX) {
Toast.makeText(
view.context,
view.context.getString(R.string.incubation_crossed_30_minutes),
Toast.LENGTH_SHORT
).show()
} else {
DataHolder.selectedTest = UserData(
sampleid = userList.sampleid,
_id = userList._id,
bloodGroup = userList.bloodGroup,
incubationTime = userList.incubationTime
)
view.findNavController()
.navigate(R.id.action_nav_home_to_mainActivity)
}
} else {
Toast.makeText(
view.context,
view.context.getString(R.string.incubation_not_started),
Toast.LENGTH_SHORT
).show()
}
} }
} }
} }
} }
} }
} }
@@ -169,4 +177,25 @@ class OfflineUserListAdapter(private val view: View, private val batLevel: Int)
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
} }
fun getBatteryLevel(): Float? {
val batteryPct: Float? = batteryStatus?.let { intent ->
val level: Int =
intent.getIntExtra(
BatteryManager.EXTRA_LEVEL,
-1
)
val scale: Int =
intent.getIntExtra(
BatteryManager.EXTRA_SCALE,
-1
)
level * 100 / scale.toFloat()
}
return batteryPct
}
private val batteryStatus: Intent? =
IntentFilter(Intent.ACTION_BATTERY_CHANGED).let { ifilter ->
view.context.registerReceiver(null, ifilter)
}
} }

View File

@@ -0,0 +1,46 @@
/*
* // Copyright (c) 2024 ShanMukha Innovations Pvt. Ltd. All rights reserved.
* // Notice: All information contained herein is, and remains
* // the property of ShanMukha Innovations Pvt. Ltd. and its suppliers,
* // if any. The intellectual and technical concepts contained
* // herein are proprietary to ShanMukha Innovations Pvt. Ltd.
* // and its suppliers and may be covered by Indian and Foreign Patents,
* // patents in process, and are protected by trade secret or copyright law.
* // Dissemination of this information or reproduction of this material
* // is strictly forbidden unless prior written permission is obtained
* // from ShanMukha Innovations Pvt. Ltd.
*/
package com.example.hpostesting.presentation.dashboard
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import `in`.sminnovations.hpostesting.databinding.FragmentAboutBinding
class AboutFragment : Fragment() {
private lateinit var binding: FragmentAboutBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
): View {
binding = FragmentAboutBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// binding.linkClick.setOnClickListener {
// val url = "https://sminnovations.in/"
// val intent = Intent(Intent.ACTION_VIEW)
// intent.data = Uri.parse(url)
// startActivity(intent)
// }
}
}

View File

@@ -14,25 +14,17 @@
package com.example.hpostesting.presentation.dashboard package com.example.hpostesting.presentation.dashboard
import android.content.Context import android.content.Context
import android.content.SharedPreferences
import android.os.BatteryManager import android.os.BatteryManager
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.presentation.adapter.OfflineUserListAdapter import com.example.hpostesting.presentation.adapter.OfflineUserListAdapter
import com.example.hpostesting.presentation.adapter.UserListAdapter
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.example.hpostesting.presentation.testRight.TestRightViewModel
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentActivitiesBinding import `in`.sminnovations.hpostesting.databinding.FragmentActivitiesBinding
import `in`.sminnovations.hpostesting.databinding.FragmentHomeBinding
class ActivitiesFragment : Fragment() { class ActivitiesFragment : Fragment() {
private lateinit var binding: FragmentActivitiesBinding private lateinit var binding: FragmentActivitiesBinding
@@ -58,7 +50,7 @@ class ActivitiesFragment : Fragment() {
val bm = val bm =
requireContext().getSystemService(Context.BATTERY_SERVICE) as BatteryManager requireContext().getSystemService(Context.BATTERY_SERVICE) as BatteryManager
val batLevel: Int = bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY) val batLevel: Int = bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
adapter = OfflineUserListAdapter(binding.root, batLevel) adapter = OfflineUserListAdapter(binding.root, batLevel,"Activities")
adapter.differ.submitList(userData) adapter.differ.submitList(userData)
binding.rvOrderOffline.adapter = adapter binding.rvOrderOffline.adapter = adapter
}else{ }else{

View File

@@ -35,7 +35,9 @@ import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController import androidx.navigation.ui.setupWithNavController
import com.example.hpostesting.util.Result import com.example.hpostesting.util.Result
import com.example.hpostesting.data.constant.Constants import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.constant.LanguageManager import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.data.model.login.LoginRequest
import com.example.hpostesting.data.model.updates.DeviceUpdateRequest import com.example.hpostesting.data.model.updates.DeviceUpdateRequest
import com.example.hpostesting.presentation.utils.NatsManager import com.example.hpostesting.presentation.utils.NatsManager
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
@@ -49,6 +51,7 @@ import `in`.sminnovations.hpostesting.BuildConfig
import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityDashboardBinding import `in`.sminnovations.hpostesting.databinding.ActivityDashboardBinding
import java.io.File import java.io.File
import java.security.MessageDigest
interface NatsMessageCallback { interface NatsMessageCallback {
fun onMessageReceived(topic: String, message: String) fun onMessageReceived(topic: String, message: String)
@@ -106,43 +109,34 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
nats.sub("server.hpos.${deviceId}.ping") nats.sub("server.hpos.${deviceId}.ping")
nats.pub("server.hpos.${deviceId}.ping", "THIS IS A TEST MSG") nats.pub("server.hpos.${deviceId}.ping", "THIS IS A TEST MSG")
hemocubeViewModel.deviceUpdate.observe(this) { result -> hemocubeViewModel.deviceUpdate.observe(this) {
when (result) { Log.d("DashboardLogs",it.toString())
is Result.Success -> {
// Handle success
val apk = result.data
val file = File(getExternalFilesDir("Updates"), "update.apk")
file.setReadable(true, false) // Ensure the file is readable
apk.byteStream().use { input ->
file.outputStream().use { output ->
input.copyTo(output)
}
}
Log.d("Responsebodyformat", "Responsebodyformat: ")
installApk(file)
Log.e("ApI", "APK URL: $apk")
Toast.makeText(
this,
"${result.data}",
Toast.LENGTH_SHORT
).show()
}
is Result.Error -> { var apk = it
result.exception.let { message -> val file = File(getExternalFilesDir("Downloads"), "update.apk")
Toast.makeText(this, "An error occurred On Updating App: $message", Toast.LENGTH_LONG) file.setReadable(true, false)
.show()
}
}
is Result.Loading -> { // Write APK to file
} apk.byteStream().use { input ->
file.outputStream().use { output ->
else -> { input.copyTo(output)
} }
} }
}
}
hemocubeViewModel.deviceUpdateheader.observe(this){
val apkFile = File(getExternalFilesDir("Downloads"), "update.apk")
val expectedChecksum = it.get("Checksum") // Provide your expected checksum here
val algorithm = "SHA-256" // Choose the algorithm you want to use (e.g., MD5, SHA-1, SHA-256)
val isIntegrityVerified = verifyChecksum(apkFile, expectedChecksum!!, algorithm)
if (isIntegrityVerified) {
println("APK integrity verified: The file has not been tampered with.")
installApk(apkFile)
} else {
println("APK integrity check failed: The file may have been tampered with.")
}
}
val drawerLayout: DrawerLayout = binding.drawerLayout val drawerLayout: DrawerLayout = binding.drawerLayout
val navView: NavigationView = binding.navView val navView: NavigationView = binding.navView
@@ -150,7 +144,7 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
appBarConfiguration = AppBarConfiguration( appBarConfiguration = AppBarConfiguration(
setOf( setOf(
R.id.nav_home, R.id.nav_profile, R.id.nav_activity,R.id.nav_settings R.id.nav_home, R.id.nav_profile, R.id.nav_activity,R.id.nav_settings,R.id.nav_about
), drawerLayout ), drawerLayout
) )
setupActionBarWithNavController(navController, appBarConfiguration) setupActionBarWithNavController(navController, appBarConfiguration)
@@ -175,7 +169,24 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp() return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
} }
fun calculateChecksum(file: File, algorithm: String): String {
val digest = MessageDigest.getInstance(algorithm)
val inputStream = file.inputStream()
val buffer = ByteArray(8192)
var bytesRead = inputStream.read(buffer)
while (bytesRead != -1) {
digest.update(buffer, 0, bytesRead)
bytesRead = inputStream.read(buffer)
}
val checksumBytes = digest.digest()
return checksumBytes.joinToString("") { "%02x".format(it) }
}
// Function to verify checksum
fun verifyChecksum(file: File, expectedChecksum: String, algorithm: String): Boolean {
val actualChecksum = calculateChecksum(file, algorithm)
return actualChecksum.equals(expectedChecksum, ignoreCase = true)
}
private fun installApk(file: File) { private fun installApk(file: File) {
val pInfo = baseContext.packageManager.getPackageInfo(baseContext.packageName, 0) val pInfo = baseContext.packageManager.getPackageInfo(baseContext.packageName, 0)
val uri: Uri = FileProvider.getUriForFile( val uri: Uri = FileProvider.getUriForFile(
@@ -284,4 +295,6 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
"N/A" "N/A"
} }
} }
} }

View File

@@ -32,6 +32,7 @@ import com.example.hpostesting.presentation.deviceinfo.DeviceActivity
import com.example.hpostesting.presentation.deviceprovision.DeviceProvisionActivity import com.example.hpostesting.presentation.deviceprovision.DeviceProvisionActivity
import com.example.hpostesting.presentation.diagnostics.DiagnosticsActivity import com.example.hpostesting.presentation.diagnostics.DiagnosticsActivity
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.example.hpostesting.presentation.usb_teminal.UsbTerminalActivity
import `in`.sminnovations.hpostesting.databinding.FragmentGalleryBinding import `in`.sminnovations.hpostesting.databinding.FragmentGalleryBinding
@@ -71,13 +72,39 @@ class GalleryFragment : Fragment() {
) { ) {
binding.btnDeviceProvision.visibility = View.VISIBLE binding.btnDeviceProvision.visibility = View.VISIBLE
} else { } else {
binding.btnDeviceProvision.visibility = View.GONE
}
if (sharedPreference.getString(Constants.USER_ID, "").toString() == "ADMIN") {
binding.btnDeviceProvision.visibility = View.VISIBLE binding.btnDeviceProvision.visibility = View.VISIBLE
binding.btnAutoDac.visibility = View.VISIBLE
binding.btnDeviceProvision.visibility = View.VISIBLE
binding.btnDiagnostics.visibility = View.VISIBLE
binding.btnFiles.visibility = View.VISIBLE
binding.btnFirefox.visibility = View.VISIBLE
binding.btnCalibration.visibility = View.VISIBLE
binding.btnUsbTerminal.visibility = View.VISIBLE
binding.btnSubmit.visibility = View.VISIBLE
binding.btnDeviceInfo.visibility = View.VISIBLE
}else{
binding.btnDeviceProvision.visibility = View.GONE
binding.btnAutoDac.visibility = View.GONE
binding.btnDeviceProvision.visibility = View.GONE
binding.btnDiagnostics.visibility = View.VISIBLE
binding.btnFiles.visibility = View.GONE
binding.btnFirefox.visibility = View.GONE
binding.btnCalibration.visibility = View.GONE
binding.btnUsbTerminal.visibility = View.GONE
binding.btnSubmit.visibility = View.GONE
binding.btnDeviceInfo.visibility = View.VISIBLE
} }
binding.btnDeviceProvision.setOnClickListener { binding.btnDeviceProvision.setOnClickListener {
startActivity(Intent(requireContext(), DeviceProvisionActivity::class.java)) startActivity(Intent(requireContext(), DeviceProvisionActivity::class.java))
} }
binding.btnUsbTerminal.setOnClickListener {
startActivity(Intent(requireContext(), UsbTerminalActivity::class.java))
}
binding.btnSubmit.setOnClickListener { binding.btnSubmit.setOnClickListener {
startActivity(Intent(requireContext(), HemocubeBufferCheckActivity::class.java)) startActivity(Intent(requireContext(), HemocubeBufferCheckActivity::class.java))
} }

View File

@@ -14,18 +14,68 @@
package com.example.hpostesting.presentation.dashboard package com.example.hpostesting.presentation.dashboard
import android.content.Context import android.content.Context
import android.content.SharedPreferences
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.preference.ListPreference import androidx.preference.ListPreference
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.constant.LanguageManager import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.data.model.TestState
import com.example.hpostesting.data.model.patient.toHemoCubeTestData
import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentHemoCubeReferenceBinding
import `in`.sminnovations.hpostesting.databinding.FragmentSlideshowBinding
private var isLanguageChanged = false private var isLanguageChanged = false
class SlideshowFragment : PreferenceFragmentCompat() { class SlideshowFragment : Fragment(){
private lateinit var binding: FragmentSlideshowBinding
private lateinit var sharedPreferences: SharedPreferences
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
): View {
binding = FragmentSlideshowBinding.inflate(inflater, container, false)
sharedPreferences =
requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.nameEditText.setText(sharedPreferences.getString(Constants.LABNAME,""))
binding.btnGo.setOnClickListener {
var labname = binding.nameEditText.text.toString()
DataHolder.hemoCubeTestData?.apply {
this.labName = labname
}
with(sharedPreferences.edit()) {
putString(Constants.LABNAME, labname)
apply()
}
Toast.makeText(
requireContext(),
"Lab Name is Added successfully.",
Toast.LENGTH_SHORT
).show()
}
childFragmentManager.beginTransaction().replace(binding.container.id,PrefsFragment()).commit()
}
}
class PrefsFragment: PreferenceFragmentCompat(){
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
val preferenceScreen = preferenceManager.createPreferenceScreen(requireContext()) val preferenceScreen = preferenceManager.createPreferenceScreen(requireContext())
@@ -56,19 +106,17 @@ class SlideshowFragment : PreferenceFragmentCompat() {
preferenceScreen.addPreference(languagePreference) preferenceScreen.addPreference(languagePreference)
preferenceScreen.addPreference(appVersionPreference) preferenceScreen.addPreference(appVersionPreference)
setPreferenceScreen(preferenceScreen) setPreferenceScreen(preferenceScreen)
if (isLanguageChanged) { if (isLanguageChanged) {
Toast.makeText(requireContext(), R.string.language_update, Toast.LENGTH_SHORT).show() Toast.makeText(requireContext(), R.string.language_update, Toast.LENGTH_SHORT).show()
} }
}
}
private fun updateLanguage(context: Context, languageCode: String) { private fun updateLanguage(context: Context, languageCode: String) {
LanguageManager.persistLanguagePreference(context, languageCode) LanguageManager.persistLanguagePreference(context, languageCode)
LanguageManager.setLocale(context, languageCode) LanguageManager.setLocale(context, languageCode)
requireActivity().recreate() // Recreate activity to apply language changes requireActivity().recreate() // Recreate activity to apply language changes
isLanguageChanged = true isLanguageChanged = true
} }
private fun getAppVersion(context: Context): String { private fun getAppVersion(context: Context): String {
return try { return try {
val pInfo = context.packageManager.getPackageInfo(context.packageName, 0) val pInfo = context.packageManager.getPackageInfo(context.packageName, 0)

View File

@@ -13,24 +13,46 @@
package com.example.hpostesting.presentation.dashboard.ui package com.example.hpostesting.presentation.dashboard.ui
import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Toast import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import com.example.hpostesting.data.constant.Constants import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.model.login.LoginRequest
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentLoginBinding import `in`.sminnovations.hpostesting.databinding.FragmentLoginBinding
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.net.HttpURLConnection
import java.net.URL
import java.util.Scanner
class LoginFragment : Fragment() { class LoginFragment : Fragment() {
private val LOCATION_PERMISSION_REQUEST_CODE = 1001
// private lateinit var locationManager: LocationManager
// var latitude = 0.0
// var longitude = 0.0
var TAG = "LoginFragmentCheck"
private var _binding: FragmentLoginBinding? = null private var _binding: FragmentLoginBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
private lateinit var sharedPreference: SharedPreferences private lateinit var sharedPreference: SharedPreferences
private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels()
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?, savedInstanceState: Bundle?,
@@ -41,11 +63,46 @@ class LoginFragment : Fragment() {
return binding.root return binding.root
} }
@RequiresApi(Build.VERSION_CODES.M)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
init() init()
if(isInternetAvailable()){
getPublicIpAddr { ipAddress ->
DataHolder.ipAddress = ipAddress
}
Log.d("ipaddress",DataHolder.ipAddress)
}
// getPublicIpAddr { ipAddress ->
// DataHolder.ipAddress = ipAddress
// }
// locationManager = requireActivity().getSystemService(Context.LOCATION_SERVICE) as LocationManager
// // Check for location permission
// if (ContextCompat.checkSelfPermission(requireContext(),
// Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(requireContext(),
// Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// // Permission is not granted, request it
// ActivityCompat.requestPermissions(requireActivity(),
// arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION,Manifest.permission.ACCESS_FINE_LOCATION),
// LOCATION_PERMISSION_REQUEST_CODE)
// } else {
// // Permission is granted, fetch location
// checkLocation()
// }
//
// if (isNetworkProviderAvailable()) {
// Toast.makeText(requireContext(), "Network provider is available", Toast.LENGTH_SHORT).show()
// } else {
// Toast.makeText(requireContext(), "Network provider is not available", Toast.LENGTH_SHORT).show()
// }
} }
// private fun isNetworkProviderAvailable(): Boolean {
//
// return locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
// }
private fun init() { private fun init() {
if (isUserLoggedIn()) { if (isUserLoggedIn()) {
navigateToHomeFragment() navigateToHomeFragment()
@@ -53,11 +110,16 @@ class LoginFragment : Fragment() {
} }
binding.btnLogin.setOnClickListener { binding.btnLogin.setOnClickListener {
// Toast.makeText(requireContext(), "$latitude/$longitude",Toast.LENGTH_SHORT).show()
val loginId = binding.loginId.text.toString() val loginId = binding.loginId.text.toString()
val password = binding.password.text.toString() val password = binding.password.text.toString()
if (loginId.isNotBlank() && password.isNotBlank()) { if (loginId.isNotBlank() && password.isNotBlank()) {
performLogin(loginId, password) performLogin(loginId, password)
var Password = sharedPreference.getString(Constants.DEVICE_PASSWORD_API, "").toString()
var UserID = sharedPreference.getString(Constants.DEVICE_ID_API, "").toString()
hemoCubeViewModel.login(createLoginRequestData(UserID, Password))
} else { } else {
if (loginId.isBlank()) { if (loginId.isBlank()) {
binding.loginId.error = R.string.enter_proper_login_id.toString() binding.loginId.error = R.string.enter_proper_login_id.toString()
@@ -68,7 +130,17 @@ class LoginFragment : Fragment() {
} }
} }
} }
private fun createLoginRequestData(userID: String, password: String): LoginRequest {
val pInfo = requireActivity().packageManager.getPackageInfo(
requireActivity().packageName, 0
)
val version = pInfo.versionName
var labname = sharedPreference.getString(Constants.LABNAME,"")
return LoginRequest(
password = password, serialNumber = userID, username = userID, version = version, lab = labname,location = DataHolder.ipAddress.toString()
)
}
private fun isUserLoggedIn(): Boolean { private fun isUserLoggedIn(): Boolean {
return sharedPreference.getString(Constants.USER_ID, "")?.isNotBlank() == true return sharedPreference.getString(Constants.USER_ID, "")?.isNotBlank() == true
} }
@@ -102,4 +174,158 @@ class LoginFragment : Fragment() {
super.onDestroyView() super.onDestroyView()
_binding = null _binding = null
} }
/** Check if we can get our location */
// @SuppressLint("MissingPermission")
// fun checkLocation() {
//
// val locationManager = requireActivity().getSystemService(Context.LOCATION_SERVICE) as LocationManager
// val locationProviderWifi = LocationManager.NETWORK_PROVIDER
// val locationProviderGPS = LocationManager.FUSED_PROVIDER
// val locationListenerNetwork: LocationListener
// val locationListenerGPS: LocationListener
// var gps_enabled = false
// var network_enabled = false
// Log.d(TAG,"PRoveider"+locationManager.allProviders.toString())
// //check wifi
//
// //check wifi
// val connectivityManager = requireActivity().getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
// val mWifi = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI)
//
// if (mWifi!!.isConnected) {
// Log.d(TAG, "Wifi connected")
// }
//
// //check gps and wifi availability
//
// //check gps and wifi availability
// try {
// gps_enabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
// } catch (ex: java.lang.Exception) {
// }
//
// try {
// network_enabled =
// locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
// } catch (ex: java.lang.Exception) {
// }
//
// if (!gps_enabled) {
// Log.d(TAG, "GPS: Missing")
// }
// if (!network_enabled) {
// Log.d(TAG, "Network: Missing")
// }
//
// /* Location change listeners */
//
// /* Location change listeners */try {
// // Define a listener that responds to gps location updates
// locationListenerGPS = object : LocationListener {
// override fun onLocationChanged(location: Location) {
// Log.d(
// TAG,
// "GPS: Latitude: " + location.latitude + ", Longitude = " + location.longitude
// )
// }
//
// override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {
// Log.d(TAG, "GPS location found 1")
// }
//
// override fun onProviderEnabled(provider: String) {
// Log.d(TAG, "GPS location found 2")
// }
//
// override fun onProviderDisabled(provider: String) {
// Log.d(TAG, "GPS location found 3")
// }
// }
// locationManager.requestLocationUpdates(
// locationProviderGPS,
// 0,
// 0f,
// locationListenerGPS
// )
// } catch (e: java.lang.Exception) {
// Log.e(TAG, "Location Exception GPS: " + e.message)
// }
//
// try {
// // Define a listener that responds to wifi location updates
// locationListenerNetwork = object : LocationListener {
// override fun onLocationChanged(location: Location) {
// Log.d(
// TAG,
// "NW: Latitude: " + location.latitude + ", Longitude = " + location.longitude
// )
// }
//
// override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {
// Log.d(TAG, "location found 1")
// }
//
// override fun onProviderEnabled(provider: String) {
// Log.d(TAG, "location found 2")
// }
//
// override fun onProviderDisabled(provider: String) {
// Log.d(TAG, "location found 3")
// }
// }
// locationManager.requestLocationUpdates(
// locationProviderWifi,
// 0,
// 0f,
// locationListenerNetwork
// )
// } catch (e: java.lang.Exception) {
// Log.e(TAG, "Location Exception: " + e.message)
// }
//
// }
// override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
// super.onRequestPermissionsResult(requestCode, permissions, grantResults)
// if (requestCode == LOCATION_PERMISSION_REQUEST_CODE) {
// if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// // Permission granted, fetch location
// checkLocation()
// } else {
// // Permission denied
// Toast.makeText(requireContext(), "Location permission denied", Toast.LENGTH_SHORT).show()
// }
// }
// }
private fun getPublicIpAddr(callback: (String) -> Unit) {
try {
GlobalScope.launch(Dispatchers.IO) {
val url = URL("https://api.ipify.org")
val conn = url.openConnection() as HttpURLConnection
try {
conn.connect()
if (conn.responseCode == HttpURLConnection.HTTP_OK) {
val scanner = Scanner(conn.inputStream)
scanner.useDelimiter("\\A")
if (scanner.hasNext()) {
val ipAddress = scanner.next()
callback(ipAddress)
}
}
} finally {
conn.disconnect()
}
}
}catch (e: Exception){
Log.e(TAG,e.toString())
}
}
@SuppressLint("NewApi")
private fun isInternetAvailable(): Boolean {
val connectivityManager = requireActivity().getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val network = connectivityManager.activeNetwork ?: return false
val networkCapabilities = connectivityManager.getNetworkCapabilities(network) ?: return false
return networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
}
} }

View File

@@ -161,10 +161,11 @@ class DeviceProvisionFragment : Fragment() {
} }
is Result.Error -> { is Result.Error -> {
Log.d("deviceProvisionResponse", response.exception.toString())
response.exception.let { message -> response.exception.let { message ->
Toast.makeText( Toast.makeText(
activity, activity,
"An error occurred in device provision: $message", "An error occurred in device provision: ${message.message}",
Toast.LENGTH_LONG Toast.LENGTH_LONG
).show() ).show()
} }

View File

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

View File

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

View File

@@ -138,7 +138,7 @@ class HemoCubeFragment : Fragment() {
if (isBufferValueAvailable()){ if (isBufferValueAvailable()){
binding.btnPlacebuffer.apply { binding.btnPlacebuffer.apply {
setBackgroundColor(Color.GREEN) // Set button background color to green setBackgroundColor(Color.GREEN) // Set button background color to green
text = "Fresh Buffer" // Change button text to "Buffer Exists" text = "Refresh Buffer" // Change button text to "Buffer Exists"
} }
}else{ }else{
binding.btnPlacebuffer.apply { binding.btnPlacebuffer.apply {
@@ -189,56 +189,89 @@ class HemoCubeFragment : Fragment() {
if (sharedPreferences.getString(Constants.USER_ID, "").toString() == "ADMIN") { if (sharedPreferences.getString(Constants.USER_ID, "").toString() == "ADMIN") {
activity?.runOnUiThread { activity?.runOnUiThread {
binding.tvDeviceMessages.visibility = View.GONE binding.tvDeviceMessages.visibility = View.VISIBLE
} }
} }
} }
private fun observeViewModel() { private fun observeViewModel() {
if (Constants.MOLBIO_INTEGRATION) {
hemoCubeViewModel.resultUpload.observe(viewLifecycleOwner) {
when (it) {
is Result.Success -> {
uploadedToMolbio = true
it.data.data?.get(0)?.rawData?.let { it1 ->
hemoCubeViewModel.updateMolbioFlag(
it1._id
)
}
if(!Constants.FIREBASE_INTEGRATION) {
Toast.makeText(
requireContext(),
testDetails?._id + ": id details stored successfully",
Toast.LENGTH_LONG
).show()
}
handleReadingFinish()
hemoCubeViewModel.uploadLogs()
val sharedPreferences = requireContext().getSharedPreferences("NATSCertificatePrefs", Context.MODE_PRIVATE)
val lastDownloadTime = sharedPreferences.getLong("lastDownloadTime", 0)
val currentTime = System.currentTimeMillis()
if (currentTime - lastDownloadTime < 365L * 24 * 60 * 60 * 1000) {
Toast.makeText(requireContext(), "NATS certificate download is not required yet.", Toast.LENGTH_SHORT).show()
return@observe
}else{
hemoCubeViewModel.downloadClientCertificate()
}
activity?.runOnUiThread {
binding.btnSubmit.visibility = View.GONE
val i = Intent(
requireContext().applicationContext, DashboardActivity::class.java
)
startActivity(i)
}
}
is Result.Error -> {
binding.btnSubmit.visibility = View.VISIBLE
//Remove this line of code while deploying to IOCL
it.exception.let { message ->
Toast.makeText(
activity,
"$message",
Toast.LENGTH_LONG
)
.show()
Log.d("resultuploadfail1", message.toString())
}
handleReadingFinish()
activity?.runOnUiThread {
binding.btnSubmit.visibility = View.GONE
val i = Intent(
requireContext().applicationContext, DashboardActivity::class.java
)
startActivity(i)
}
}
else -> {}
}
}
} else {
handleReadingFinish()
}
hemoCubeViewModel.fireBaseUpload.observe(viewLifecycleOwner) { result -> hemoCubeViewModel.fireBaseUpload.observe(viewLifecycleOwner) { result ->
if (result == "Success") { if (result == "Success") {
uploadedToCloud = true uploadedToCloud = true
var accessToken = sharedPreferences.getString(Constants.ACCESS_TOKEN, "").toString() var accessToken = sharedPreferences.getString(Constants.ACCESS_TOKEN, "").toString()
showToast(R.string.test_upload) // showToast( R.string.test_upload)
if (Constants.MOLBIO_INTEGRATION) { Toast.makeText(requireContext(), testDetails?._id +": id details stored successfully",Toast.LENGTH_LONG).show()
hemoCubeViewModel.resultUpload.observe(viewLifecycleOwner) {
when (it) {
is Result.Success -> {
uploadedToMolbio = true
it.data.data?.get(0)?.rawData?.let { it1 ->
hemoCubeViewModel.updateMolbioFlag(
it1._id
)
}
handleReadingFinish()
hemoCubeViewModel.uploadLogs()
hemoCubeViewModel.downloadClientCertificate()
}
is Result.Error -> {
binding.btnSubmit.visibility = View.VISIBLE
//Remove this line of code while deploying to IOCL
it.exception.let { message ->
Toast.makeText(
activity,
"$message",
Toast.LENGTH_LONG
)
.show()
Log.d("resultuploadfail1", message.toString())
}
handleReadingFinish()
}
else -> {}
}
}
} else {
handleReadingFinish()
}
} }
if (result == "Local") { if (result == "Local") {
showToast(R.string.internt_not_local) // showToast(R.string.internt_not_local)
Toast.makeText(requireContext(), testDetails?._id +": id details stored locally, Internet is not Available",Toast.LENGTH_LONG).show()
startActivity(Intent(requireActivity(), DashboardActivity::class.java)) startActivity(Intent(requireActivity(), DashboardActivity::class.java))
} }
if (result == "Error") { if (result == "Error") {
@@ -463,9 +496,9 @@ class HemoCubeFragment : Fragment() {
fetchResult() fetchResult()
} }
//#EC for v0 and v1 and #RC for v2 //#EC for v0 and v1 and #RC for v2
(resultData.contains("#EC") && this.testStatusCode < TestStatus.EPROM_ADC_RETRIEVAL_COMPLETED.code) -> { (resultData.contains("#RC") && this.testStatusCode < TestStatus.EPROM_ADC_RETRIEVAL_COMPLETED.code) -> {
this.testStatusCode = TestStatus.EPROM_ADC_RETRIEVAL_COMPLETED.code this.testStatusCode = TestStatus.EPROM_ADC_RETRIEVAL_COMPLETED.code
hemoCubeViewModel.messages.postValue("EPROM ADC Loaded") hemoCubeViewModel.messages.postValue("Ready to test")//EPROM ADC Loaded
//checkCuvettePresence() //checkCuvettePresence()
activity?.runOnUiThread { activity?.runOnUiThread {
binding.btnPlacebuffer.visibility = View.VISIBLE binding.btnPlacebuffer.visibility = View.VISIBLE
@@ -476,7 +509,7 @@ class HemoCubeFragment : Fragment() {
(resultData.contains("#AC") && this.testStatusCode < TestStatus.TEMPERATURE_CHECK.code) -> { (resultData.contains("#AC") && this.testStatusCode < TestStatus.TEMPERATURE_CHECK.code) -> {
this.testStatusCode = TestStatus.TEMPERATURE_CHECK.code this.testStatusCode = TestStatus.TEMPERATURE_CHECK.code
temperature = resultData.substringAfter("#AS").substringBefore("#AC") temperature = resultData.substringAfter("#AS").substringBefore("#AC")
hemoCubeViewModel.messages.postValue("EPROM ADC Loaded and Temperature fetched \n Temp : $temperature") hemoCubeViewModel.messages.postValue("Ready to test \n Temperature : $temperature")
} }
resultData.contains("#CIN") && sampleClick && this.testStatusCode < TestStatus.CUVETTE_PRESENTS.code -> { resultData.contains("#CIN") && sampleClick && this.testStatusCode < TestStatus.CUVETTE_PRESENTS.code -> {
hemoCubeViewModel.messages.postValue(getString(R.string.cuvette_present)) hemoCubeViewModel.messages.postValue(getString(R.string.cuvette_present))
@@ -1019,6 +1052,7 @@ class HemoCubeFragment : Fragment() {
led3Buffer = led3BufferForDevice led3Buffer = led3BufferForDevice
led4Buffer = led4BufferForDevice led4Buffer = led4BufferForDevice
appVersion = version appVersion = version
labName = sharedPreferences.getString(Constants.LABNAME,"")
this.led1Sample = led1SampleForDevice this.led1Sample = led1SampleForDevice
this.led2Sample = led2SampleForDevice this.led2Sample = led2SampleForDevice
this.led3Sample = led3SampleForDevice this.led3Sample = led3SampleForDevice
@@ -1126,7 +1160,7 @@ class HemoCubeFragment : Fragment() {
"Borderline. Sickle Cell Trait" "Borderline. Sickle Cell Trait"
} }
if (deviceRatioClass == "Positive for Sickle Cell. HPLC for Confirmation") { if (deviceRatioClass == "Positive for Sickle Cell. HPLC for Confirmation") {
return if (borderlineMetric >= 1.34) return if (borderlineMetric >= 1.4)//1.34
"Borderline. Sickle Cell Trait" "Borderline. Sickle Cell Trait"
else else
"Borderline. Sickle Cell Disease" "Borderline. Sickle Cell Disease"
@@ -1168,7 +1202,7 @@ class HemoCubeFragment : Fragment() {
fun deviceRatioClassification(ratio: Double?): String { fun deviceRatioClassification(ratio: Double?): String {
try { try {
if (ratio != null) { if (ratio != null) {
if (ratio in 0.16..0.23) { if (ratio in 0.11..0.23) {
// setSubtitleTextColor(R.color.green_2) // setSubtitleTextColor(R.color.green_2)
return "Normal" return "Normal"
} }
@@ -1176,9 +1210,9 @@ class HemoCubeFragment : Fragment() {
return "Negative Borderline" return "Negative Borderline"
if (ratio in 0.25..0.31) if (ratio in 0.25..0.31)
return "Sickle Cell Trait" return "Sickle Cell Trait"
if (ratio in 0.31..0.36) if (ratio in 0.31..0.39)//0.36
return "Positive for Sickle Cell. HPLC for Confirmation" return "Positive for Sickle Cell. HPLC for Confirmation"
if (ratio in 0.36..0.7) if (ratio in 0.39..1.0)
return "Sickle Cell Disease" return "Sickle Cell Disease"
} else { } else {
return "Invalid" return "Invalid"

View File

@@ -43,6 +43,7 @@ import com.example.hpostesting.data.model.molbioresult.MolbioV2ResultResponse
import com.example.hpostesting.data.model.patient.BufferCheckData import com.example.hpostesting.data.model.patient.BufferCheckData
import com.example.hpostesting.data.model.patient.DeviceData import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.HemoCubeTestData import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.MolbioHemocubeData
import com.example.hpostesting.data.model.patient.toHemoCubeTestData import com.example.hpostesting.data.model.patient.toHemoCubeTestData
import com.example.hpostesting.data.model.updates.CheckUpdateRequest import com.example.hpostesting.data.model.updates.CheckUpdateRequest
import com.example.hpostesting.data.model.updates.CheckUpdateResponse import com.example.hpostesting.data.model.updates.CheckUpdateResponse
@@ -51,8 +52,10 @@ import com.example.hpostesting.data.repository.Repository
import com.example.hpostesting.domain.CheckUpdateWorker import com.example.hpostesting.domain.CheckUpdateWorker
import com.example.hpostesting.domain.LogFileManager import com.example.hpostesting.domain.LogFileManager
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import okhttp3.Headers
import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody import okhttp3.MultipartBody
import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.RequestBody.Companion.asRequestBody
@@ -76,6 +79,7 @@ class HemoCubeViewModel @Inject constructor(
var isServiceConnected = false var isServiceConnected = false
val progressBar = MutableLiveData(false) val progressBar = MutableLiveData(false)
private val testDetails = DataHolder.selectedTest?.toHemoCubeTestData() private val testDetails = DataHolder.selectedTest?.toHemoCubeTestData()
private val testDetailsmolbio = DataHolder.hemoCubeTestData?.MolbioHemocubeData()
val messages = MutableLiveData<String>() val messages = MutableLiveData<String>()
private val sharedPreference = private val sharedPreference =
context.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE) context.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
@@ -92,7 +96,8 @@ class HemoCubeViewModel @Inject constructor(
val checkUpdate = MutableLiveData<Result<CheckUpdateResponse>>() val checkUpdate = MutableLiveData<Result<CheckUpdateResponse>>()
val deviceUpdate = MutableLiveData<Result<ResponseBody>>() val deviceUpdate = MutableLiveData<ResponseBody>()
val deviceUpdateheader = MutableLiveData<Headers>()
val downloadcertificate = MutableLiveData<Result<ResponseBody>>() val downloadcertificate = MutableLiveData<Result<ResponseBody>>()
val uploadLogs = MutableLiveData<Result<UploadLogsResponse>?>() val uploadLogs = MutableLiveData<Result<UploadLogsResponse>?>()
@@ -136,7 +141,7 @@ class HemoCubeViewModel @Inject constructor(
testDetails?.testTime = SimpleDateFormat( testDetails?.testTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault() "yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time) ).format(Calendar.getInstance().time)
hemoCubeDao.insertAll(testDetails!!) hemoCubeDao.updateTest(testDetails!!)
fireBaseUpload.postValue("Local") fireBaseUpload.postValue("Local")
} }
} catch (e: Exception) { } catch (e: Exception) {
@@ -167,7 +172,7 @@ class HemoCubeViewModel @Inject constructor(
} }
fun sendDataToMolbio() = viewModelScope.launch(Dispatchers.IO) { fun sendDataToMolbio() = viewModelScope.launch(Dispatchers.IO + coroutineExceptionHandler) {
Log.d("molbio","getting in sendMolbio") Log.d("molbio","getting in sendMolbio")
val resultList = MolbioV2ResultRequest(mutableListOf()) val resultList = MolbioV2ResultRequest(mutableListOf())
@@ -184,7 +189,7 @@ class HemoCubeViewModel @Inject constructor(
?: "defaultThreshold" // Handle possible nulls safely ?: "defaultThreshold" // Handle possible nulls safely
resultList.results?.add( resultList.results?.add(
MolbioV2Result( MolbioV2Result(
rawData = userData, rawData = userData.MolbioHemocubeData(),
analysisId = userData._id, analysisId = userData._id,
analysisDate = currentTimeFormatted, analysisDate = currentTimeFormatted,
analysisStatus = userData.classificationResult analysisStatus = userData.classificationResult
@@ -235,7 +240,7 @@ class HemoCubeViewModel @Inject constructor(
} }
fun sendDataToFirebase() = viewModelScope.launch ( Dispatchers.IO ) { fun sendDataToFirebase() = viewModelScope.launch ( Dispatchers.IO + coroutineExceptionHandler ) {
val pendingData = hemoCubeDao.getFirebasePending() val pendingData = hemoCubeDao.getFirebasePending()
pendingData.forEach{ pendingData.forEach{
userData -> userData ->
@@ -258,9 +263,11 @@ class HemoCubeViewModel @Inject constructor(
} }
fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest) = viewModelScope.launch { fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest) = viewModelScope.launch {
deviceUpdate.postValue(Result.Loading()) //deviceUpdate.postValue(Result.Loading())
repository.deviceUpdate(deviceUpdateRequest).let { repository.deviceUpdate(deviceUpdateRequest).let {
deviceUpdate.postValue(it) deviceUpdate.postValue(it.body())
deviceUpdateheader.postValue(it.headers())
} }
} }
@@ -413,6 +420,7 @@ class HemoCubeViewModel @Inject constructor(
testDetails?.concentration = DataHolder.hemoCubeTestData?.concentration testDetails?.concentration = DataHolder.hemoCubeTestData?.concentration
testDetails?.volume = DataHolder.hemoCubeTestData?.volume testDetails?.volume = DataHolder.hemoCubeTestData?.volume
testDetails?.filter = DataHolder.hemoCubeTestData?.filter testDetails?.filter = DataHolder.hemoCubeTestData?.filter
testDetails?.labName = DataHolder.hemoCubeTestData?.labName
} }
@@ -422,7 +430,11 @@ class HemoCubeViewModel @Inject constructor(
testDetails!!.reportUploadTime = SimpleDateFormat( testDetails!!.reportUploadTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault() "yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time) ).format(Calendar.getInstance().time)
val currentTimeFormatted = SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ssZZZZZ",
Locale.getDefault()
).format(Calendar.getInstance().time)
if(Constants.FIREBASE_INTEGRATION) {
when (val response = repository.addTestToDatabase(testDetails)) { when (val response = repository.addTestToDatabase(testDetails)) {
is Response.Success -> { is Response.Success -> {
val kitCount = sharedPreference.getInt(Constants.KIT_COUNT, 0) val kitCount = sharedPreference.getInt(Constants.KIT_COUNT, 0)
@@ -433,41 +445,49 @@ class HemoCubeViewModel @Inject constructor(
Log.i("Testdb", "Data uploaded to Firestore successfully") Log.i("Testdb", "Data uploaded to Firestore successfully")
fireBaseUpload.postValue("Success") fireBaseUpload.postValue("Success")
testDetails.localFlag = true testDetails.localFlag = true
if (Constants.MOLBIO_INTEGRATION) {
// Sanitize testDetails before using it in the API call
val sanitizedTestDetails = sanitizeDoubleValues(testDetails)
// Now, use sanitizedTestDetails for the API call hemoCubeDao.updateTest(testDetails)
uploadResult(
MolbioV2ResultRequest(
mutableListOf(
MolbioV2Result(
rawData = sanitizedTestDetails,
analysisId = sanitizedTestDetails._id,
analysisDate = sanitizedTestDetails.testTime,
analysisStatus = sanitizedTestDetails.classificationResult,
thresholds = Constants.BUFFER_INTENSITY_THRESHOLDS[sanitizedTestDetails.deviceId]?.toString(),
interpretation = sanitizedTestDetails.classificationResult,
testId = sanitizedTestDetails._id,
testTime = sanitizedTestDetails.testTime,
collectionTime = sanitizedTestDetails.testTime,
expiryTime = sanitizedTestDetails.testTime,
)
)
)
)
}
hemoCubeDao.insertAll(testDetails)
} }
is Response.Error -> { is Response.Error -> {
Log.e("Testdb", "Error uploading data to Firestore: $response") Log.e("Testdb", "Error uploading data to Firestore: $response")
fireBaseUpload.postValue("Error") fireBaseUpload.postValue("Error")
hemoCubeDao.insertAll(testDetails) hemoCubeDao.updateTest(testDetails)
} }
else -> {} else -> {}
} }
}
if (Constants.MOLBIO_INTEGRATION) {
val kitCount = sharedPreference.getInt(Constants.KIT_COUNT, 0)
with(sharedPreference.edit()) {
putInt(Constants.KIT_COUNT, kitCount.plus(1))
apply()
}
// Sanitize testDetails before using it in the API call
val sanitizedTestDetails = testDetailsmolbio?.let { sanitizeDoubleValues(it) }
// Now, use sanitizedTestDetails for the API call
uploadResult(
MolbioV2ResultRequest(
mutableListOf(
MolbioV2Result(
rawData = sanitizedTestDetails,
analysisId = sanitizedTestDetails!!._id,
analysisDate = currentTimeFormatted,
analysisStatus = sanitizedTestDetails.classificationResult,
thresholds = Constants.BUFFER_INTENSITY_THRESHOLDS[sanitizedTestDetails.deviceId]?.toString(),
interpretation = sanitizedTestDetails.classificationResult,
testId = sanitizedTestDetails._id,
testTime = currentTimeFormatted,
collectionTime = currentTimeFormatted,
expiryTime = currentTimeFormatted,
)
)
)
)
hemoCubeDao.updateTest(testDetails)
}
} catch (e: Exception) { } catch (e: Exception) {
Log.e("Testdb", "Exception during data upload: ${e.message}") Log.e("Testdb", "Exception during data upload: ${e.message}")
fireBaseUpload.postValue("Error") fireBaseUpload.postValue("Error")
@@ -493,17 +513,17 @@ class HemoCubeViewModel @Inject constructor(
} }
} }
fun sanitizeDoubleValues(hemoCubeTestData: HemoCubeTestData): HemoCubeTestData { fun sanitizeDoubleValues(molbiohemocubeData: MolbioHemocubeData): MolbioHemocubeData {
hemoCubeTestData::class.java.declaredFields.forEach { field -> molbiohemocubeData::class.java.declaredFields.forEach { field ->
if (field.type == Double::class.javaObjectType || field.type == Double::class.javaPrimitiveType) { if (field.type == Double::class.javaObjectType || field.type == Double::class.javaPrimitiveType) {
field.isAccessible = true field.isAccessible = true
val value = field.get(hemoCubeTestData) as Double? val value = field.get(molbiohemocubeData) as Double?
if (value != null && (value.isInfinite() || value.isNaN())) { if (value != null && (value.isInfinite() || value.isNaN())) {
field.set(hemoCubeTestData, 0.0) // Replace with a suitable default value field.set(molbiohemocubeData, 0.0) // Replace with a suitable default value
} }
} }
} }
return hemoCubeTestData return molbiohemocubeData
} }
private fun updateLocalFlag(userId: String) = viewModelScope.launch { private fun updateLocalFlag(userId: String) = viewModelScope.launch {
@@ -518,6 +538,7 @@ class HemoCubeViewModel @Inject constructor(
hemoCubeDao.insertAll(userData) hemoCubeDao.insertAll(userData)
} }
fun deleteById(userId: String) = viewModelScope.launch { fun deleteById(userId: String) = viewModelScope.launch {
hemoCubeDao.deleteById(id = userId) hemoCubeDao.deleteById(id = userId)
} }
@@ -673,4 +694,7 @@ class HemoCubeViewModel @Inject constructor(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault() "yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time) ).format(Calendar.getInstance().time)
} }
val coroutineExceptionHandler = CoroutineExceptionHandler{_, throwable ->
throwable.printStackTrace()
}
} }

View File

@@ -43,6 +43,7 @@ import com.example.hpostesting.data.model.molbioresult.MolbioV2ResultResponse
import com.example.hpostesting.data.model.patient.BufferCheckData import com.example.hpostesting.data.model.patient.BufferCheckData
import com.example.hpostesting.data.model.patient.DeviceData import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.HemoCubeTestData import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.MolbioHemocubeData
import com.example.hpostesting.data.model.patient.toHemoCubeTestData import com.example.hpostesting.data.model.patient.toHemoCubeTestData
import com.example.hpostesting.data.model.updates.CheckUpdateRequest import com.example.hpostesting.data.model.updates.CheckUpdateRequest
import com.example.hpostesting.data.model.updates.CheckUpdateResponse import com.example.hpostesting.data.model.updates.CheckUpdateResponse
@@ -75,6 +76,7 @@ class TrueHemeViewModel @Inject constructor(
var isServiceConnected = false var isServiceConnected = false
val progressBar = MutableLiveData(false) val progressBar = MutableLiveData(false)
private val testDetails = DataHolder.selectedTest?.toHemoCubeTestData() private val testDetails = DataHolder.selectedTest?.toHemoCubeTestData()
private val testDetailsmolbio = DataHolder.hemoCubeTestData?.MolbioHemocubeData()
val messages = MutableLiveData<String>() val messages = MutableLiveData<String>()
private val sharedPreference = private val sharedPreference =
context.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE) context.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
@@ -162,7 +164,7 @@ class TrueHemeViewModel @Inject constructor(
fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest) = viewModelScope.launch { fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest) = viewModelScope.launch {
deviceUpdate.postValue(Result.Loading()) deviceUpdate.postValue(Result.Loading())
repository.deviceUpdate(deviceUpdateRequest).let { repository.deviceUpdate(deviceUpdateRequest).let {
deviceUpdate.postValue(it) // deviceUpdate.postValue(it)
} }
} }
@@ -321,12 +323,12 @@ class TrueHemeViewModel @Inject constructor(
} }
Log.i("Testdb", "Data uploaded to Firestore successfully") Log.i("Testdb", "Data uploaded to Firestore successfully")
fireBaseUpload.postValue("Success") fireBaseUpload.postValue("Success")
testDetails.localFlag = true testDetailsmolbio!!.localFlag = true
uploadResult( uploadResult(
MolbioV2ResultRequest( MolbioV2ResultRequest(
mutableListOf( mutableListOf(
MolbioV2Result( MolbioV2Result(
rawData = testDetails, rawData = testDetailsmolbio,
analysisId = testDetails._id, analysisId = testDetails._id,
analysisDate = testDetails.testTime, analysisDate = testDetails.testTime,
analysisStatus = testDetails.classificationResult, analysisStatus = testDetails.classificationResult,

View File

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

View File

@@ -0,0 +1,105 @@
/*
* // Copyright (c) 2024 ShanMukha Innovations Pvt. Ltd. All rights reserved.
* // Notice: All information contained herein is, and remains
* // the property of ShanMukha Innovations Pvt. Ltd. and its suppliers,
* // if any. The intellectual and technical concepts contained
* // herein are proprietary to ShanMukha Innovations Pvt. Ltd.
* // and its suppliers and may be covered by Indian and Foreign Patents,
* // patents in process, and are protected by trade secret or copyright law.
* // Dissemination of this information or reproduction of this material
* // is strictly forbidden unless prior written permission is obtained
* // from ShanMukha Innovations Pvt. Ltd.
*/
package com.example.hpostesting.presentation.usb_teminal
import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
import android.text.method.ScrollingMovementMethod
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.MutableLiveData
import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.presentation.utils.UsbServiceListener
import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.ktx.Firebase
import `in`.sminnovations.hpostesting.databinding.FragmentUsbTerminalBinding
class UsbTerminalFragment : Fragment() {
private lateinit var binding: FragmentUsbTerminalBinding
private val usbTerminalViewModel: UsbTerminalViewModel by activityViewModels()
private lateinit var sharedPreferences: SharedPreferences
private var startListening = MutableLiveData(false)
private var resultData: String = ""
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
): View {
binding = FragmentUsbTerminalBinding.inflate(inflater, container, false)
sharedPreferences =
requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initViews()
}
private fun initViews() {
binding.messageCommand.movementMethod = ScrollingMovementMethod()
usbTerminalViewModel.messages.observe(viewLifecycleOwner) {
binding.messageCommand.text = it
}
binding.sendCommand.setOnClickListener {
callCommand(binding.etCommands.text.trim().toString())
}
listenToHemoCube()
callCommand("I")
}
private fun callCommand(command: String) {
usbTerminalViewModel.progressBar.postValue(true)
(activity as UsbTerminalActivity).mService.sendAndListenToHemoCubeTxt(
command,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
}
override fun onUsbError(e: Exception?) {
usbTerminalViewModel.progressBar.postValue(false)
}
})
}
private fun listenToHemoCube() {
val fullReadOutput = StringBuilder()
startListening.postValue(true)
try {
(activity as UsbTerminalActivity).mService.listenToHemoCube(object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
data?.let {
val stringData = String(it)
fullReadOutput.append(stringData)
resultData += stringData
usbTerminalViewModel.messages.postValue(resultData)
}
}
override fun onUsbError(e: Exception?) {
usbTerminalViewModel.messages.postValue(e!!.localizedMessage)
usbTerminalViewModel.progressBar.postValue(false)
}
})
} catch (e: Exception) {
usbTerminalViewModel.messages.postValue(e.localizedMessage)
Firebase.crashlytics.recordException(e)
}
}
}

View File

@@ -0,0 +1,34 @@
/*
* // Copyright (c) 2024 ShanMukha Innovations Pvt. Ltd. All rights reserved.
* // Notice: All information contained herein is, and remains
* // the property of ShanMukha Innovations Pvt. Ltd. and its suppliers,
* // if any. The intellectual and technical concepts contained
* // herein are proprietary to ShanMukha Innovations Pvt. Ltd.
* // and its suppliers and may be covered by Indian and Foreign Patents,
* // patents in process, and are protected by trade secret or copyright law.
* // Dissemination of this information or reproduction of this material
* // is strictly forbidden unless prior written permission is obtained
* // from ShanMukha Innovations Pvt. Ltd.
*/
package com.example.hpostesting.presentation.usb_teminal
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.example.hpostesting.data.dao.HemoCubeDao
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.repository.Repository
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
@HiltViewModel
class UsbTerminalViewModel @Inject constructor(
private val hemoCubeDao: HemoCubeDao,
private val repository: Repository,
) : ViewModel() {
var isServiceConnected = false
val progressBar = MutableLiveData(false)
val messages = MutableLiveData<String>()
val deviceData = MutableLiveData<DeviceData?>()
val fireBaseUpload = MutableLiveData<String>()
}

View File

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

View File

@@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M11.5,2C6.81,2 3,5.81 3,10.5S6.81,19 11.5,19h0.5v3c4.86,-2.34 8,-7 8,-11.5C20,5.81 16.19,2 11.5,2zM12.5,16.5h-2v-2h2v2zM12.5,13h-2c0,-3.25 3,-3 3,-5 0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2h-2c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,2.5 -3,2.75 -3,5z"/>
</vector>

View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ // Copyright (c) 2024 ShanMukha Innovations Pvt. Ltd. All rights reserved.
~ // Notice: All information contained herein is, and remains
~ // the property of ShanMukha Innovations Pvt. Ltd. and its suppliers,
~ // if any. The intellectual and technical concepts contained
~ // herein are proprietary to ShanMukha Innovations Pvt. Ltd.
~ // and its suppliers and may be covered by Indian and Foreign Patents,
~ // patents in process, and are protected by trade secret or copyright law.
~ // Dissemination of this information or reproduction of this material
~ // is strictly forbidden unless prior written permission is obtained
~ // from ShanMukha Innovations Pvt. Ltd.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_parent"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- <androidx.appcompat.widget.Toolbar-->
<!-- android:id="@+id/my_toolbar"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="?attr/actionBarSize"-->
<!-- android:background="?attr/colorPrimary"-->
<!-- app:titleTextColor="#FFFFFF"-->
<!-- android:elevation="4dp"-->
<!-- app:menu="@menu/my_menu"-->
<!-- android:theme="@style/ToolbarTheme"-->
<!-- app:popupTheme="@style/ThemeOverlay.AppCompat.Light"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toTopOf="parent"/>-->
<FrameLayout
android:id="@+id/fg_device"
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.deviceinfo.DeviceActivity">
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ // Copyright (c) 2024 ShanMukha Innovations Pvt. Ltd. All rights reserved.
~ // Notice: All information contained herein is, and remains
~ // the property of ShanMukha Innovations Pvt. Ltd. and its suppliers,
~ // if any. The intellectual and technical concepts contained
~ // herein are proprietary to ShanMukha Innovations Pvt. Ltd.
~ // and its suppliers and may be covered by Indian and Foreign Patents,
~ // patents in process, and are protected by trade secret or copyright law.
~ // Dissemination of this information or reproduction of this material
~ // is strictly forbidden unless prior written permission is obtained
~ // from ShanMukha Innovations Pvt. Ltd.
-->
<ScrollView
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">
<LinearLayout
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="wrap_content">
<ImageView
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_gravity="center"
android:layout_marginTop="20dp"
android:src="@drawable/smi_logo"
android:contentDescription="@string/smi" />
<TextView
android:id="@+id/titleText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/smi_desp"
android:layout_marginTop="12dp"
android:layout_marginEnd="12dp"
android:layout_marginStart="12dp"
android:textSize="18sp"
android:textColor="@color/black"
/>
<TextView
android:id="@+id/link_click"
android:clickable="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/learn_more"
android:layout_marginTop="5dp"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:textSize="18sp"
android:textColor="@color/red"
android:focusable="true" />
</LinearLayout>
</ScrollView>

View File

@@ -27,7 +27,7 @@
android:layout_marginTop="10dp" android:layout_marginTop="10dp"
android:gravity="center" android:gravity="center"
android:text="Start" android:text="Start"
android:visibility="invisible" android:visibility="visible"
android:textColor="@color/black" android:textColor="@color/black"
android:textSize="16sp" android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"

View File

@@ -59,17 +59,28 @@
android:id="@+id/tv_subtitle4" android:id="@+id/tv_subtitle4"
style="@style/title1_1" style="@style/title1_1"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="380dp" android:layout_height="450dp"
android:layout_marginHorizontal="24dp" android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
android:gravity="center" android:gravity="center"
android:text="Start" android:text="Start"
android:scrollbars="vertical"
android:textColor="@color/red" android:textColor="@color/red"
android:textSize="22sp" android:textSize="22sp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle3" /> app:layout_constraintTop_toBottomOf="@id/tv_subtitle3" />
<ProgressBar
android:id="@+id/progressBarHor"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:visibility="gone"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle4"/>
<Button <Button
android:id="@+id/btn_submit" android:id="@+id/btn_submit"

View File

@@ -97,8 +97,21 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_auto_dac" /> app:layout_constraintTop_toBottomOf="@id/btn_auto_dac" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_usb_terminal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:text="@string/usb_terminal"
android:textColor="@color/white"
app:cornerRadius="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_calibration" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/btn_deviceInfo" android:id="@+id/btn_deviceInfo"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -110,7 +123,7 @@
app:cornerRadius="16dp" app:cornerRadius="16dp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_calibration" /> app:layout_constraintTop_toBottomOf="@id/btn_usb_terminal" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/btn_deviceProvision" android:id="@+id/btn_deviceProvision"

View File

@@ -193,7 +193,7 @@
android:layout_width="50dp" android:layout_width="50dp"
android:layout_height="50dp" android:layout_height="50dp"
android:src="@drawable/upload_data" android:src="@drawable/upload_data"
android:visibility="visible" android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@+id/tv_title" app:layout_constraintBottom_toBottomOf="@+id/tv_title"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/tv_title" /> app:layout_constraintTop_toTopOf="@+id/tv_title" />

View File

@@ -12,11 +12,60 @@
~ // from ShanMukha Innovations Pvt. Ltd. ~ // from ShanMukha Innovations Pvt. Ltd.
--> -->
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.hpostesting.presentation.dashboard.SlideshowFragment"> tools:context="com.example.hpostesting.presentation.dashboard.SlideshowFragment">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_parent"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/lab_name"
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_toTopOf="parent">
<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/lab_name" />
</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/add"
app:cornerRadius="16dp"
app:layout_constraintBottom_toBottomOf="@id/lab_name"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toEndOf="@id/lab_name"
app:layout_constraintTop_toTopOf="@id/lab_name" />
<FrameLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/lab_name"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="10dp"/>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@@ -0,0 +1,69 @@
<!--
~ // Copyright (c) 2024 ShanMukha Innovations Pvt. Ltd. All rights reserved.
~ // Notice: All information contained herein is, and remains
~ // the property of ShanMukha Innovations Pvt. Ltd. and its suppliers,
~ // if any. The intellectual and technical concepts contained
~ // herein are proprietary to ShanMukha Innovations Pvt. Ltd.
~ // and its suppliers and may be covered by Indian and Foreign Patents,
~ // patents in process, and are protected by trade secret or copyright law.
~ // Dissemination of this information or reproduction of this material
~ // is strictly forbidden unless prior written permission is obtained
~ // from ShanMukha Innovations Pvt. Ltd.
-->
<RelativeLayout
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"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
>
<TextView
android:id="@+id/message_command"
style="@style/title1_1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:gravity="start|bottom"
android:text="Start"
android:scrollbars = "vertical"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:layout_above="@+id/ll_commands"
android:visibility="visible"
android:textColor="@color/black"
android:textSize="18sp"
/>
<RelativeLayout
android:id="@+id/ll_commands"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentStart="true"
android:layout_alignParentBottom="true"
android:orientation="horizontal">
<EditText
android:id="@+id/et_commands"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:hint="commands"
android:layout_alignParentStart="true"
android:imeOptions="actionDone"
android:textSize="18sp"
android:layout_marginBottom="10dp"
/>
<ImageView
android:id="@+id/send_command"
android:layout_width="32dp"
android:layout_height="26dp"
android:layout_alignParentEnd="true"
android:layout_centerInParent="true"
android:src="@drawable/ic_baseline_send_24"/>
</RelativeLayout>
</RelativeLayout>

View File

@@ -33,5 +33,9 @@
android:id="@+id/nav_settings" android:id="@+id/nav_settings"
android:icon="@drawable/baseline_settings_24" android:icon="@drawable/baseline_settings_24"
android:title="@string/menu_settings" /> android:title="@string/menu_settings" />
<item
android:id="@+id/nav_about"
android:icon="@drawable/baseline_contact_support_24"
android:title="@string/menu_about" />
</group> </group>
</menu> </menu>

View File

@@ -45,6 +45,11 @@
android:name="com.example.hpostesting.presentation.dashboard.SlideshowFragment" android:name="com.example.hpostesting.presentation.dashboard.SlideshowFragment"
android:label="@string/action_settings" android:label="@string/action_settings"
tools:layout="@layout/fragment_slideshow" /> tools:layout="@layout/fragment_slideshow" />
<fragment
android:id="@+id/nav_about"
android:name="com.example.hpostesting.presentation.dashboard.AboutFragment"
android:label="@string/action_about"
tools:layout="@layout/fragment_about" />
<fragment <fragment
android:id="@+id/nav_activity" android:id="@+id/nav_activity"
android:name="com.example.hpostesting.presentation.dashboard.ActivitiesFragment" android:name="com.example.hpostesting.presentation.dashboard.ActivitiesFragment"
@@ -57,7 +62,7 @@
<fragment <fragment
android:id="@+id/loginFragment" android:id="@+id/loginFragment"
android:name="com.example.hpostesting.presentation.dashboard.ui.LoginFragment" android:name="com.example.hpostesting.presentation.dashboard.ui.LoginFragment"
android:label="fragment_login" android:label="@string/login"
tools:layout="@layout/fragment_login" > tools:layout="@layout/fragment_login" >
<action <action
android:id="@+id/action_loginFragment_to_homeFragment" android:id="@+id/action_loginFragment_to_homeFragment"

View File

@@ -289,4 +289,13 @@
<string name="cuvette_present">Cuvette present</string> <string name="cuvette_present">Cuvette present</string>
<string name="cuvette_absent">Cuvette absent</string> <string name="cuvette_absent">Cuvette absent</string>
<string name="retry">Retry</string> <string name="retry">Retry</string>
<string name="Firefox">Firefox</string>
<string name="Files">Files</string>
<string name="usb_terminal">Usb Terminal</string>
<string name="lab_name">Lab Name</string>
<string name="menu_about">About</string>
<string name="action_about">About</string>
<string name="smi_desp">ShanMukha Innovations is a spin-off from Indian Institute of Science, Bangalore. Incorporated in 2016, the company has been delivering innovative Made in India first of its kind deep technology-based products in healthcare.\n\nNotable solutions include Mobile Infection Testing and Reporting Labs (MITR Labs), portable thermal cycler (PolyCube).\n\nThe company launched Sicklecert ®, Indias first CDSCO approved indigenous diagnostic test for sickle-cell anemia.\n\nOur customers include government, non-profit and private sector companies. Leading research institutes such as IISc, IIT Tirupati have engaged us for unique projects. We take pride in supporting Indian and global customers with world-class products.</string>
<string name="smi">SMI</string>
<string name="learn_more">Visit to learn more: <u>sminnovations.in</u></string>
</resources> </resources>

View File

@@ -288,6 +288,15 @@
<string name="cuvette_present">Cuvette present</string> <string name="cuvette_present">Cuvette present</string>
<string name="cuvette_absent">Cuvette absent</string> <string name="cuvette_absent">Cuvette absent</string>
<string name="retry">Retry</string> <string name="retry">Retry</string>
<string name="Firefox">Firefox</string>
<string name="Files">Files</string>
<string name="usb_terminal">Usb Terminal</string>
<string name="menu_about">About</string>
<string name="action_about">About</string>
<string name="lab_name">Lab Name</string>
<string name="smi_desp">ShanMukha Innovations is a spin-off from Indian Institute of Science, Bangalore. Incorporated in 2016, the company has been delivering innovative Made in India first of its kind deep technology-based products in healthcare.\n\nNotable solutions include Mobile Infection Testing and Reporting Labs (MITR Labs), portable thermal cycler (PolyCube).\n\nThe company launched Sicklecert ®, Indias first CDSCO approved indigenous diagnostic test for sickle-cell anemia.\n\nOur customers include government, non-profit and private sector companies. Leading research institutes such as IISc, IIT Tirupati have engaged us for unique projects. We take pride in supporting Indian and global customers with world-class products.</string>
<string name="smi">SMI</string>
<string name="learn_more">Visit to learn more: <u>sminnovations.in</u></string>
<!-- Add translations for other strings --> <!-- Add translations for other strings -->
</resources> </resources>

View File

@@ -218,7 +218,7 @@
<string name="all_registered_user_are_tested_successfully">All registered user are tested successfully</string> <string name="all_registered_user_are_tested_successfully">All registered user are tested successfully</string>
<string name="start_incubation">Incubate</string> <string name="start_incubation">Incubate</string>
<string name="check_buffer">Check Buffer</string> <string name="check_buffer">Check Buffer</string>
<string name="low_battery_warning">Battery level is low than 40%, please charge the device to continue testing</string> <string name="low_battery_warning">Battery level is lower than 40%, please charge the device to continue testing</string>
<string name="test_already_conducted">Test has been already conducted for this user</string> <string name="test_already_conducted">Test has been already conducted for this user</string>
<string name="incubation_not_completed">Incubation has not completed 15 minutes</string> <string name="incubation_not_completed">Incubation has not completed 15 minutes</string>
<string name="incubation_crossed_30_minutes">Incubation crossed 30 minutes, need to repeat the incubation</string> <string name="incubation_crossed_30_minutes">Incubation crossed 30 minutes, need to repeat the incubation</string>
@@ -249,6 +249,7 @@
<string name="do_log_out">Do you want to LogOut the Application?</string> <string name="do_log_out">Do you want to LogOut the Application?</string>
<string name="cancelled_unable_scan">Cancelled: Unable to scan, Try Again!!</string> <string name="cancelled_unable_scan">Cancelled: Unable to scan, Try Again!!</string>
<string name="kit_updated">Kit number is updated, Please Select user before starting test</string> <string name="kit_updated">Kit number is updated, Please Select user before starting test</string>
<string name="kit_update">Kit number is updated.</string>
<string name="select_patient">Please Select patient before starting test</string> <string name="select_patient">Please Select patient before starting test</string>
<string name="enable_location">Please enable location services</string> <string name="enable_location">Please enable location services</string>
<string name="location_denied">Fine location permission denied</string> <string name="location_denied">Fine location permission denied</string>
@@ -289,6 +290,13 @@
<string name="action_activity">Activities</string> <string name="action_activity">Activities</string>
<string name="check_cuvette">Checking cuvette presence</string> <string name="check_cuvette">Checking cuvette presence</string>
<string name="cuvette_present">Cuvette present , you can start the test</string> <string name="cuvette_present">Cuvette present , you can start the test</string>
<string name="cuvette_absent">Cuvette is absent , please place the cuvette and retry again</string> <string name="cuvette_absent">cuvette is not present, please put the cuvette and retry again</string>
<string name="retry">Retry again</string> <string name="retry">Retry again</string>
<string name="usb_terminal">Usb Terminal</string>
<string name="menu_about">About</string>
<string name="action_about">About</string>
<string name="lab_name">Lab Name</string>
<string name="smi_desp"><b>ShanMukha Innovations</b> is a spin-off from Indian Institute of Science, Bangalore. Incorporated in 2016, the company has been delivering innovative Made in India first of its kind deep technology-based products in healthcare.\n\nNotable solutions include Mobile Infection Testing and Reporting Labs (MITR Labs), portable thermal cycler (PolyCube).\n\nThe company launched Sicklecert ®, Indias first CDSCO approved indigenous diagnostic test for sickle-cell anemia.\n\nOur customers include government, non-profit and private sector companies. Leading research institutes such as IISc, IIT Tirupati have engaged us for unique projects. We take pride in supporting Indian and global customers with world-class products.</string>
<string name="smi">SMI</string>
<string name="learn_more">Visit to learn more: <u>sminnovations.in</u></string>
</resources> </resources>

View File

@@ -13,11 +13,13 @@
package com.example.hpostesting package com.example.hpostesting
import android.content.Context
import androidx.arch.core.executor.testing.InstantTaskExecutorRule import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import com.example.hpostesting.data.model.Response import com.example.hpostesting.data.model.Response
import com.example.hpostesting.data.model.diagnostics.DiagnosticsData import com.example.hpostesting.data.model.diagnostics.DiagnosticsData
import com.example.hpostesting.data.repository.Repository import com.example.hpostesting.data.repository.Repository
import com.example.hpostesting.presentation.diagnostics.DiagnosticsActivity
import com.example.hpostesting.presentation.diagnostics.DiagnosticsViewModel import com.example.hpostesting.presentation.diagnostics.DiagnosticsViewModel
import io.mockk.coEvery import io.mockk.coEvery
import io.mockk.mockk import io.mockk.mockk
@@ -49,7 +51,8 @@ class DiagnosticsViewModelTest {
// Mock Repository // Mock Repository
private val mockRepository = mockk<Repository>() private val mockRepository = mockk<Repository>()
@Mock
private lateinit var context: Context
// Mock Observer for LiveData // Mock Observer for LiveData
@Mock @Mock
private lateinit var mockObserver: Observer<String> private lateinit var mockObserver: Observer<String>
@@ -63,7 +66,7 @@ class DiagnosticsViewModelTest {
MockitoAnnotations.openMocks(this) MockitoAnnotations.openMocks(this)
// Create the ViewModel with the mock repository and set the coroutine dispatcher // Create the ViewModel with the mock repository and set the coroutine dispatcher
diagnosticsViewModel = DiagnosticsViewModel(repository = mockRepository) diagnosticsViewModel = DiagnosticsViewModel(repository = mockRepository, context = context)
// diagnosticsViewModel.viewModelScope = testCoroutineScope // diagnosticsViewModel.viewModelScope = testCoroutineScope
// Observe the LiveData // Observe the LiveData

View File

@@ -360,7 +360,7 @@ class HemoCubeFragmentTest {
@Test @Test
fun testDeviceRatioClassificationSickleCellDiseaseLowerBound() { fun testDeviceRatioClassificationSickleCellDiseaseLowerBound() {
val ratio = 0.361 val ratio = 0.391
val result = hemoCubeFragment.deviceRatioClassification(ratio) val result = hemoCubeFragment.deviceRatioClassification(ratio)
assertEquals("Sickle Cell Disease", result) assertEquals("Sickle Cell Disease", result)
} }
@@ -398,7 +398,7 @@ class HemoCubeFragmentTest {
val result = hemoCubeFragment.findResultWithAdditionalMethods( val result = hemoCubeFragment.findResultWithAdditionalMethods(
0.5, 0.5,
"Positive for Sickle Cell. HPLC for Confirmation", "Positive for Sickle Cell. HPLC for Confirmation",
1.35 1.4
) )
assertEquals("Borderline. Sickle Cell Trait", result) assertEquals("Borderline. Sickle Cell Trait", result)
} }
@@ -441,7 +441,7 @@ class HemoCubeFragmentTest {
val result = hemoCubeFragment.findResultWithAdditionalMethods( val result = hemoCubeFragment.findResultWithAdditionalMethods(
0.5, 0.5,
"Positive for Sickle Cell. HPLC for Confirmation", "Positive for Sickle Cell. HPLC for Confirmation",
1.35 1.4
) )
assertEquals("Borderline. Sickle Cell Trait", result) assertEquals("Borderline. Sickle Cell Trait", result)
} }