Compare commits

...

88 Commits

Author SHA1 Message Date
smileomi18@gmail.com
057abbd87c Calculated ratio error code added 2023-09-07 13:51:07 +05:30
mohamedkaif356
c3775eeea1 Error code added 2023-09-07 13:31:02 +05:30
smileomi18@gmail.com
882fdb7374 APP VERSION added 2023-09-05 17:20:21 +05:30
smileomi18@gmail.com
b6e086c407 APP VERSION added 2023-09-05 15:37:53 +05:30
mohamedkaif356
53c2fd5ad4 Blood group 2023-09-05 13:44:18 +05:30
smileomi18@gmail.com
4b733b3a96 FirebaseCrashAnalytics added 2023-08-23 12:07:25 +05:30
mohamedkaif356
dc4291eaa8 Offline storage 2023-08-18 12:21:21 +05:30
Mariya Varghese
5d2830d515 Merge branch 'blood-group' into 'Homocube'
Blood group

See merge request sminnovations/hpos!1
2023-08-16 10:22:40 +00:00
smileomi18@gmail.com
dfa9fe7672 deviceData function called 2023-08-14 21:12:14 +05:30
smileomi18@gmail.com
d51d46a9a1 Blood-Group is added 2023-08-09 14:54:59 +05:30
smileomi18@gmail.com
64209fd2f2 Blood-Group is added 2023-08-09 14:51:44 +05:30
Pritimay Sarkar
d4752a9491 Merge branch 'qc-testing' into Homocube 2023-08-09 11:46:38 +05:30
Pritimay Sarkar
484790e721 Added device login 2023-08-09 11:43:29 +05:30
Pritimay Sarkar
954795030c Added device login 2023-08-09 11:40:31 +05:30
mohamedkaif356
53695d9240 Made some corrections 2023-08-09 11:13:48 +05:30
mohamedkaif356
bac0baf53c Made some corrections 2023-08-09 11:07:58 +05:30
mohamedkaif356
f3c292b268 Done with error handling 2023-08-08 15:30:46 +05:30
mohamedkaif356
2bb87c7780 Optimized HemoCube data parsing and changed user card 2023-08-07 17:43:24 +05:30
mohamedkaif356
85d9c6306d Fixed Navigation, Location, and updated user card and gitignore file 2023-08-07 15:02:16 +05:30
Pritimay Sarkar
e5390df0f4 add resultData 2023-08-07 12:43:39 +05:30
Pritimay Sarkar
afdaac7f1d Merge branch 'Homocube' of https://gitlab.com/sminnovations/hpos into Homocube 2023-08-05 15:28:35 +05:30
Pritimay Sarkar
60cd1aef1a add popup for sample reading 2023-08-05 15:28:11 +05:30
smileomi18@gmail.com
22f080ff9f dialogue box is done 2023-08-05 14:07:22 +05:30
Pritimay Sarkar
013dc569a1 take message as frames 2023-08-05 12:50:50 +05:30
Pritimay Sarkar
7ca2d78325 Merge branch 'Homocube' of https://gitlab.com/sminnovations/hpos into Homocube 2023-08-04 22:41:49 +05:30
Pritimay Sarkar
a43e29a03e disable button 2023-08-04 22:41:34 +05:30
mohamedkaif356
c1c6c7cce4 Buffer error resolved 2023-08-04 19:54:10 +05:30
Pritimay Sarkar
e049e6ede3 Merge 2023-08-04 15:51:04 +05:30
Pritimay Sarkar
4d366cbf02 set buffer and new kit logic 2023-08-04 15:49:26 +05:30
smileomi18@gmail.com
a491343a43 navigation is done 2023-08-04 13:41:51 +05:30
Pritimay Sarkar
1b893c5730 Merge 2023-08-03 23:04:59 +05:30
Pritimay Sarkar
547b5d8663 add device data parsing and saving calcualtion data 2023-08-03 23:01:49 +05:30
Pritimay Sarkar
4c7c24449b show text and disable button 2023-08-03 17:42:06 +05:30
smileomi18@gmail.com
3daba2fbb1 Added Kit and Buffer Button 2023-08-03 17:39:29 +05:30
Pritimay Sarkar
23ef8bc74f save calculateRatio 2023-08-03 17:33:53 +05:30
mohamedkaif356
9f79d32cbf Flushed Kit number, Kit count and Buffer value for new kit 2023-08-03 17:06:36 +05:30
mohamedkaif356
1a87344f44 Flushed Kit number, Kit count and Buffer value for new kit 2023-08-03 17:03:04 +05:30
Pritimay Sarkar
7c1100fc39 Merge branch 'Homocube' of https://gitlab.com/sminnovations/hpos into Homocube 2023-08-03 16:46:01 +05:30
Pritimay Sarkar
82b3944d94 add alert on check buffer 2023-08-03 16:45:27 +05:30
smileomi18@gmail.com
340b656990 Added 2 Buffer values 2023-08-03 16:44:04 +05:30
smileomi18@gmail.com
567fe237da calibration calculation done 2023-08-03 16:15:57 +05:30
Pritimay Sarkar
281d206492 Merge branch 'tmp' into Homocube 2023-08-03 15:45:39 +05:30
smileomi18@gmail.com
750fb67ff9 calibration calculation done 2023-08-03 15:41:57 +05:30
Pritimay Sarkar
d0c309801d add commands to set and read buffer sample
- add commands
2023-08-03 15:34:49 +05:30
smileomi18@gmail.com
36799ea81e Merge remote-tracking branch 'origin/Homocube' into Homocube 2023-08-03 13:43:31 +05:30
smileomi18@gmail.com
e0937d9f03 Fetching caliberation value done 2023-08-03 13:41:51 +05:30
smileomi18@gmail.com
47633267f7 Fetching caliberation value done 2023-08-03 13:40:35 +05:30
mohamedkaif356
0dd77027e9 Flushed Kit number, Kit count and Buffer value for new kit 2023-08-03 13:12:28 +05:30
mohamedkaif356
8237e753c0 Added Buffer Value Logic 2023-08-03 13:01:03 +05:30
mohamedkaif356
4c847fb132 Added KitNumber and KitCount 2023-08-03 12:46:45 +05:30
Pritimay Sarkar
4488e5e16e merge 2023-08-02 23:28:35 +05:30
Pritimay Sarkar
c8199b9044 merge 2023-08-02 23:23:47 +05:30
Pritimay Sarkar
3292a0e382 merge 2023-08-02 23:14:57 +05:30
smileomi18@gmail.com
1ba919c956 Fetching caliberation value done 2023-08-02 20:03:26 +05:30
smileomi18@gmail.com
6e2729a075 Fetching caliberation value done 2023-08-02 20:02:45 +05:30
smileomi18@gmail.com
0b44ce47b9 Added Device Data and HemoCube Schema 2023-08-02 19:32:58 +05:30
smileomi18@gmail.com
8506d3da6d Added Device Data and HemoCube Schema 2023-08-02 19:07:08 +05:30
smileomi18@gmail.com
ece2cec4c0 hemocube alert Dialogue 2023-08-02 16:33:46 +05:30
Pritimay Sarkar
f6613b3b69 fix hemocube db save error
- add mapper to hemocube data
	- save test details correctly on dataholder
	- add result data from device on test details
2023-08-02 11:32:23 +05:30
smileomi18@gmail.com
9382708140 hemocube test uploading data 2023-08-01 18:45:49 +05:30
smileomi18@gmail.com
f8f8f140a9 Removed 2023-07-31 17:05:36 +05:30
smileomi18@gmail.com
e0a4008966 HemoCube new Changes 2023-07-27 17:26:44 +05:30
smileomi18@gmail.com
90b92897bd HemoCube new Changes 2023-07-27 17:16:28 +05:30
smileomi18@gmail.com
106aa496fc HemoCube new Changes 2023-07-27 17:12:14 +05:30
smileomi18@gmail.com
97b66acda3 HemoCube new Changes 2023-07-27 16:44:12 +05:30
smileomi18@gmail.com
a5db2e759c HemoCube new Changes 2023-07-26 18:11:46 +05:30
mohamedkaif356
ebf212d33a Improved logic 2023-07-25 13:42:29 +05:30
mohamedkaif356
e2e9c28efb Improved Code 2023-07-25 12:22:57 +05:30
smileomi18@gmail.com
46ee7b55be HemoCube new Changes 2023-07-25 12:12:34 +05:30
smileomi18@gmail.com
c0d706f2a3 Merge remote-tracking branch 'origin/Homocube' into Homocube 2023-07-25 12:03:06 +05:30
prisar
4b8a380541 read data from dev 2023-07-25 11:47:29 +05:30
prisar
3cd6bd1bc8 read data from device homocube 2023-07-25 11:47:27 +05:30
prisar
dbdcd647af usb permission 2023-07-25 11:47:15 +05:30
smileomi18@gmail.com
a28e4634e0 usb 2023-07-25 11:47:14 +05:30
mohamedkaif356
ed567f6545 Displaying message when user list is empty and update blood group 2023-07-25 11:46:24 +05:30
smileomi18@gmail.com
af5c3c3bde Test pending list filter 2023-07-25 11:46:24 +05:30
mohamedkaif356
21e9b9b7b2 Blood group selection 2023-07-25 11:46:23 +05:30
smileomi18@gmail.com
9067240c4f HemoCube new Changes 2023-07-25 11:40:10 +05:30
smileomi18@gmail.com
0d2027381c HemoCube new Changes 2023-07-24 15:45:33 +05:30
smileomi18@gmail.com
ca403ab862 HemoCube new Changes 2023-07-24 14:49:51 +05:30
smileomi18@gmail.com
3b042c6587 HemoCube new Changes 2023-07-24 14:33:06 +05:30
prisar
ff5cc154e6 refactor code 2023-07-21 11:12:50 +05:30
smileomi18@gmail.com
51b49a010c read data from device homocube 2023-07-20 16:08:59 +05:30
smileomi18@gmail.com
a8e7d7d60b Merge remote-tracking branch 'origin/Homocube' into Homocube
# Conflicts:
#	app/src/main/java/com/example/hpostesting/presentation/testRight/UsbService.kt
2023-07-20 15:44:43 +05:30
prisar
a34d101fbf read data from device homocube 2023-07-20 15:44:01 +05:30
prisar
fd8fbb863f read data from dev 2023-07-19 18:18:39 +05:30
prisar
b64c3fb471 usb permission 2023-07-19 17:27:57 +05:30
smileomi18@gmail.com
8151d6da61 usb 2023-07-19 16:28:31 +05:30
45 changed files with 1920 additions and 513 deletions

8
.gitignore vendored
View File

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

2
.idea/gradle.xml generated
View File

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

1
.idea/misc.xml generated
View File

@@ -1,3 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DesignSurface">
<option name="filePathToZoomLevelMap">

View File

@@ -6,17 +6,18 @@ plugins {
id 'com.google.gms.google-services'
id 'androidx.navigation.safeargs.kotlin'
id 'kotlin-kapt'
id 'com.google.firebase.crashlytics'
}
//apply plugin: 'kotlin-android'
android {
compileSdk 33
compileSdk 34
namespace 'in.sminnovations.hpostesting'
defaultConfig {
applicationId "in.sminnovations.hpostesting"
minSdk 21
targetSdk 33
targetSdk 34
versionCode 2
versionName "2.0.1"
@@ -39,14 +40,13 @@ android {
dataBinding {
enabled = true
}
lintOptions {
checkReleaseBuilds false
// Or, if you prefer, you can continue to check for errors in release builds,
// but continue the build even when errors are found:
abortOnError false
}
buildFeatures {
viewBinding true
buildConfig = true
}
lint {
abortOnError false
checkReleaseBuilds false
}
}
@@ -60,13 +60,16 @@ dependencies {
//firebase
implementation platform('com.google.firebase:firebase-bom:32.1.0')
implementation("com.google.firebase:firebase-crashlytics-ktx")
implementation("com.google.firebase:firebase-analytics-ktx")
implementation 'com.google.firebase:firebase-firestore-ktx'
implementation 'com.google.firebase:firebase-auth-ktx'
implementation 'com.google.firebase:firebase-storage-ktx'
implementation 'com.firebaseui:firebase-ui-firestore:8.0.2'
implementation 'com.google.android.gms:play-services-auth:20.5.0'
implementation 'com.google.android.gms:play-services-auth:20.6.0'
implementation 'com.google.android.gms:play-services-location:21.0.1'
implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1'
implementation 'com.google.android.things:androidthings:1.0'
// Testing
testImplementation 'junit:junit:4.13.2'
@@ -76,9 +79,9 @@ dependencies {
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1"
implementation 'com.opencsv:opencsv:4.6'
implementation 'com.github.mik3y:usb-serial-for-android:3.4.6'
implementation 'com.github.mik3y:usb-serial-for-android:3.5.1'
implementation "androidx.fragment:fragment-ktx:1.6.0"
implementation "androidx.fragment:fragment-ktx:1.6.1"
// CSV read, write
implementation 'com.opencsv:opencsv:4.6'
@@ -87,20 +90,20 @@ dependencies {
implementation 'com.journeyapps:zxing-android-embedded:4.3.0'
// Google ML Kit usign play services
implementation 'com.google.android.gms:play-services-code-scanner:16.0.0'
implementation 'com.google.android.gms:play-services-code-scanner:16.1.0'
//Room
implementation "androidx.room:room-ktx:2.6.0-alpha01"
implementation "androidx.room:room-runtime:2.6.0-alpha01"
kapt ("androidx.room:room-compiler:2.6.0-alpha01")
implementation "androidx.room:room-ktx:2.6.0-beta01"
implementation "androidx.room:room-runtime:2.6.0-beta01"
kapt ("androidx.room:room-compiler:2.6.0-beta01")
//image
implementation 'com.github.bumptech.glide:glide:4.13.2'
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.13.2'
// Navigation Component
implementation "androidx.navigation:navigation-fragment-ktx:2.7.0-beta01"
implementation "androidx.navigation:navigation-ui-ktx:2.7.0-beta01"
implementation "androidx.navigation:navigation-fragment-ktx:2.7.1"
implementation "androidx.navigation:navigation-ui-ktx:2.7.1"
//Dagger - Hilt
implementation "com.google.dagger:hilt-android:2.46"

View File

@@ -14,6 +14,10 @@
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-feature android:name="android.hardware.usb.host" />
<uses-permission android:name="android.permission.USB_PERMISSION" />
<application
android:name="com.example.hpostesting.HPOSTestingApplication"
android:allowBackup="true"
@@ -26,15 +30,26 @@
android:theme="@style/Theme.HPOSTesting"
tools:targetApi="31">
<activity
android:name="com.example.hpostesting.presentation.KitScanActivity"
android:name="com.example.hpostesting.presentation.BloodCollectingMethodActivity"
android:exported="true"
android:noHistory="true"
android:theme="@style/Theme.HPOS.NoActionBar" />
<activity
android:name="com.example.hpostesting.presentation.hemocube.HemocubeActivity"
android:exported="false"
android:noHistory="true"
android:parentActivityName="com.example.hpostesting.presentation.MainActivity"
android:theme="@style/Theme.HPOS.NoActionBar"
android:windowSoftInputMode="adjustPan" />
<activity
android:name="com.example.hpostesting.presentation.KitScanActivity"
android:exported="false"
android:noHistory="true"
android:theme="@style/Theme.HPOS.NoActionBar" />
<activity
android:name="com.example.hpostesting.presentation.dashboard.DashboardActivity"
android:exported="false"
android:label="@string/title_activity_dashboard"
android:screenOrientation="portrait"
android:theme="@style/Theme.HPOS.NoActionBar" />
<service
@@ -56,11 +71,10 @@
<activity
android:name="com.example.hpostesting.presentation.testRight.TestRightActivity"
android:exported="false"
android:parentActivityName="com.example.hpostesting.presentation.MainActivity"
android:screenOrientation="portrait"
android:noHistory="true"
android:windowSoftInputMode="adjustPan"
android:theme="@style/Theme.HPOS.NoActionBar">
android:parentActivityName="com.example.hpostesting.presentation.MainActivity"
android:theme="@style/Theme.HPOS.NoActionBar"
android:windowSoftInputMode="adjustPan">
<!-- <intent-filter> -->
<!-- <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /> -->
@@ -74,7 +88,6 @@
<activity
android:name="com.example.hpostesting.presentation.MainActivity"
android:exported="true"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
@@ -89,7 +102,6 @@
android:screenOrientation="portrait"
android:stateNotNeeded="true"
tools:replace="android:screenOrientation" />
</application>
</manifest>

View File

@@ -1,12 +1,19 @@
package com.example.hpostesting
import android.app.Application
import android.content.Context
import androidx.room.Room
import com.example.hpostesting.data.dao.MyDatabase
import com.google.android.datatransport.runtime.dagger.Provides
import dagger.hilt.android.HiltAndroidApp
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import javax.inject.Singleton
@HiltAndroidApp
class HPOSTestingApplication: Application() {
val applicationScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
}

View File

@@ -1,6 +1,7 @@
package com.example.hpostesting.data
import androidx.lifecycle.MutableLiveData
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.data.model.test.TestRightDeviceConstants
import com.example.hpostesting.data.model.test.TestType
@@ -8,12 +9,8 @@ import com.example.hpostesting.data.model.test.TestType
object DataHolder {
var selectedTestType: TestType = TestType.SICKLECERT
val usbConnected = MutableLiveData(true)
var mobileUniqueId: String? = null
var isStoragePermissionGranted = false
var isAppFolderCreated = false
var appFolderPath = ""
var isReferenceTaken = false
@@ -21,16 +18,13 @@ object DataHolder {
var deviceConstant: TestRightDeviceConstants? = null
var deviceSerialNumber: String = "ABCD"
/* Contains wavelength -> pixel no.*/
val deviceType = MutableLiveData<String>()
val wavelengthToPixelArray = ArrayList<Double>()
/* (For reference/baseline) Contains pixel no. -> Intensity of light falling on that pixel */
val intensityReferenceArray = ArrayList<Double>()
var selectedTest: UserData? = null
var hemoCubeTestData: HemoCubeTestData? = null
var kitSerial: String = ""
var location: UserData.Location? = null
var testExp: Boolean = true
var hemocubeResult: Double? = null
}

View File

@@ -2,6 +2,7 @@ package com.example.hpostesting.data.constant
object Constants {
const val ACTION_USB_PERMISSION = "shanmukha.in.sickle_cell.USB_PERMISSION"
const val HOMOCUBE_USB_PERMISSION = "shanmukha.in.sickle_cell_homocube.USB_PERMISSION"
const val ABHA_APP_PACKAGE = "in.ndhm.phr"
@@ -22,7 +23,12 @@ object Constants {
const val MAX_WAVELENGTH_RANGE_TO_RECORD = 750
const val DEVICE_PRODUCT_ID = 24597
const val DEVICE_TYPE_HOMOCUBE = "HOMOCUBE"
const val DEVICE_TYPE_TEST_RIGHT = "TEST_RIGHT"
const val DEVICE_VENDOR_ID = 1027
const val HOMO_CUBE_ID = 29987
const val VENDOR_ID = 6790
const val ERROR_NORMAL = 400
const val ERROR_CRITICAL = 401
@@ -32,27 +38,25 @@ object Constants {
const val USER_ID = "usernameId"
val STATICID = listOf(
"VIZ-1000-0001",
"VIZ-1000-0002",
"VIZ-1000-0003",
"VIZ-1000-0004",
"VIZ-1000-0005",
"VIZ-1000-0006",
"VIZ-1000-0007",
"VIZ-1000-0008",
"VIZ-1000-0009",
"VIZ-1000-0010",
"VIZ-1000-0011",
"VIZ-1000-0012",
"VIZ-1000-0013",
"VIZ-1000-0014",
"VIZ-1000-0015",
"VIZ-1000-0016",
"VIZ-1000-0017",
"VIZ-1000-0018",
"VIZ-1000-0019"
"HC-V1-001",
"HC-V1-002",
"HC-V1-003",
"HC-V1-004",
"HC-V1-005",
"HC-V1-006",
)
const val password = "SMI@12345"
const val KIT_NUMBER = "KitNumber"
const val KIT_COUNT = "KitCount"
const val BUFFER_VALUE_1 = "BufferValue1"
const val BUFFER_VALUE_2 = "BufferValue2"
const val BLOOD_COLLECTING_METHOD = "bloodCollectingMethod"
const val VENOUS_BLOOD = "venousBlood"
const val FINGER_PRICK_BLOOD = "fingerPrickBlood"
}

View File

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

View File

@@ -2,6 +2,7 @@ package com.example.hpostesting.data.dao
import androidx.room.TypeConverter
import com.example.hpostesting.data.model.patient.UserData
import com.google.common.reflect.TypeToken
import com.google.gson.Gson
class Converters {
@@ -15,7 +16,6 @@ class Converters {
null
}
}
@TypeConverter
fun toString(location: UserData.Location?): String? {
return if (location != null) {
@@ -24,4 +24,15 @@ class Converters {
null
}
}
@TypeConverter
fun fromList(list: List<Double>): String {
return Gson().toJson(list)
}
@TypeConverter
fun toList(json: String): List<Double> {
val type = object : TypeToken<List<Double>>() {}.type
return Gson().fromJson(json, type)
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -45,12 +45,6 @@ data class PatientDetails(
OTHER
}
// enum class BloodGroup {
// O_POSITIVE, O_NEGATIVE,
// A_POSITIVE, A_NEGATIVE,
// B_POSITIVE, B_NEGATIVE,
// AB_POSITIVE, AB_NEGATIVE,
// }
data class Address(
var house: String?,

View File

@@ -36,3 +36,12 @@ data class UserData(
var longitude: Double? = null
)
}
fun UserData.toHemoCubeTestData() = HemoCubeTestData(
_id = _id,
name = name,
birthYear = birthYear,
userImageURL = userImageURL,
testStatus = testStatus,
location = location
)

View File

@@ -1,36 +1,65 @@
package com.example.hpostesting.data.repository
import android.content.Context
import android.net.Uri
import androidx.room.Room
import com.example.hpostesting.data.dao.MyDatabase
import com.example.hpostesting.data.model.PendingUploads
import com.example.hpostesting.data.model.Response
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.UserData
import com.google.android.datatransport.runtime.dagger.Provides
import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.firestore.ktx.firestore
import com.google.firebase.ktx.Firebase
import com.google.firebase.storage.ktx.storage
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.tasks.await
import kotlinx.coroutines.withContext
import java.io.File
import javax.inject.Singleton
class DatabaseRepository : Repository {
private val db: FirebaseFirestore = Firebase.firestore
private val storage = Firebase.storage
suspend fun addTestToDatabase(data: UserData): Response<String> {
suspend fun addTestToDatabase(data: HemoCubeTestData?): Response<String> {
return try {
val userdata = db.collection("patientData").whereEqualTo("_id", data._id).get().await()
val userdata = db.collection("patientData").whereEqualTo("_id", data!!._id).get().await()
if (userdata.documents.isNotEmpty()) {
userdata.documents.forEach {
db.collection("patientData").document(it.id).update("testStatus", true)
}
}
db.collection("testData").add(data).await()
Response.Success(data._id)
db.collection("testData").add(data!!).await()
Response.Success(data!!._id)
} catch (e: Exception) {
Response.Error(e)
}
}
suspend fun addTestToDatabase(data: UserData?): Response<String> {
return try {
val userdata = db.collection("patientData").whereEqualTo("_id", data!!._id).get().await()
if (userdata.documents.isNotEmpty()) {
userdata.documents.forEach {
db.collection("patientData").document(it.id).update("testStatus", true)
}
}
db.collection("testData").add(data!!).await()
Response.Success(data!!._id)
} catch (e: Exception) {
Response.Error(e)
}
}
suspend fun uploadFileToStorage(patientID: String, filePath: String): Response<Boolean> {
try {
@@ -87,4 +116,19 @@ class DatabaseRepository : Repository {
}
}
suspend fun getDeviceData(): List<DeviceData> {
return db.collection("devices").get().await().toObjects(DeviceData::class.java)
}
suspend fun getDeviceDataById(deviceId: String): DeviceData? {
val querySnapshot = db.collection("devices").get().await()
val allDeviceDataList = querySnapshot.toObjects(DeviceData::class.java)
// Find the DeviceData object with the specified deviceId
return allDeviceDataList.find { it.deviceId == deviceId }
}
}

View File

@@ -3,6 +3,7 @@ package com.example.hpostesting.domain.di
import android.app.Application
import android.content.Context
import androidx.room.Room
import com.example.hpostesting.data.dao.HemoCubeDao
import com.example.hpostesting.data.dao.MyDatabase
import com.example.hpostesting.data.dao.UserDao
import com.example.hpostesting.data.datasource.LocalFileDataSource
@@ -26,7 +27,9 @@ object AppModule {
fun provideMyDatabase(@ApplicationContext context: Context): MyDatabase {
return Room.databaseBuilder(
context, MyDatabase::class.java, "my_database"
).build()
)
.fallbackToDestructiveMigration()
.build()
}
@Provides
@@ -35,6 +38,12 @@ object AppModule {
return myDatabase.userDao()
}
@Provides
@Singleton
fun provideMyHemo(myDatabase: MyDatabase): HemoCubeDao {
return myDatabase.hemoCubeDao()
}
@Provides
@Singleton
fun provideContext(application: Application): Context {

View File

@@ -0,0 +1,57 @@
package com.example.hpostesting.presentation
import android.content.Intent
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.presentation.hemocube.HemocubeActivity
import com.example.hpostesting.presentation.testRight.TestRightActivity
import `in`.sminnovations.hpostesting.databinding.ActivityBloodCollectingMethodBinding
class BloodCollectingMethodActivity : AppCompatActivity() {
private lateinit var binding: ActivityBloodCollectingMethodBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityBloodCollectingMethodBinding.inflate(layoutInflater)
setContentView(binding.root)
init()
}
private fun init() {
setSupportActionBar(binding.toolbar)
binding.btnGo.setOnClickListener {
DataHolder.usbConnected.observe(this) {
if (it) {
if (binding.venousBloodRadioButton.isChecked) {
moveToNext(Constants.VENOUS_BLOOD)
} else {
moveToNext(Constants.FINGER_PRICK_BLOOD)
}
} else {
Toast.makeText(this, "No Device Connected", Toast.LENGTH_SHORT).show()
}
}
}
}
private fun moveToNext(bloodCollectingMethod: String) {
DataHolder.deviceType.observe(this) { deviceType ->
when (deviceType) {
Constants.DEVICE_TYPE_HOMOCUBE -> {
val intent = Intent(applicationContext, HemocubeActivity::class.java)
intent.putExtra(Constants.BLOOD_COLLECTING_METHOD, bloodCollectingMethod)
startActivity(intent)
}
Constants.DEVICE_TYPE_TEST_RIGHT -> {
val intent = Intent(applicationContext, TestRightActivity::class.java)
intent.putExtra(Constants.BLOOD_COLLECTING_METHOD, bloodCollectingMethod)
startActivity(intent)
}
}
}
}
}

View File

@@ -1,6 +1,8 @@
package com.example.hpostesting.presentation
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.os.Bundle
import android.util.Log
import android.widget.Toast
@@ -8,7 +10,6 @@ import androidx.appcompat.app.AppCompatActivity
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.example.hpostesting.presentation.testRight.TestRightActivity
import com.journeyapps.barcodescanner.ScanContract
import com.journeyapps.barcodescanner.ScanIntentResult
import com.journeyapps.barcodescanner.ScanOptions
@@ -20,6 +21,8 @@ class KitScanActivity : AppCompatActivity() {
private val TAG = "KitScanActivity"
private lateinit var binding: ActivityKitScanBinding
private lateinit var sharedPreference: SharedPreferences
private val barcodeLauncher = registerForActivityResult(
ScanContract()
) { result: ScanIntentResult ->
@@ -39,12 +42,30 @@ class KitScanActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
binding = ActivityKitScanBinding.inflate(layoutInflater)
sharedPreference = this.getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE)
setContentView(binding.root)
if (DataHolder.sampleReadCounter <= Constants.MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE && DataHolder.isReferenceTaken) {
DataHolder.selectedTest!!.kitSerial = DataHolder.kitSerial
moveToNext()
}
if (checkHemoCubeKitData()) {
DataHolder.selectedTest!!.kitSerial =
sharedPreference.getString(Constants.KIT_NUMBER, "").toString()
moveToNext()
} else {
with(sharedPreference.edit()) {
putString(Constants.KIT_NUMBER, "")
putInt(Constants.KIT_COUNT, 0)
putString(Constants.BUFFER_VALUE_1, "")
putString(Constants.BUFFER_VALUE_2, "")
apply()
}
}
binding.nameEditText.setText("SMI/SC/")
setSupportActionBar(binding.toolbar)
binding.btnScanNow.setOnClickListener {
@@ -55,7 +76,13 @@ class KitScanActivity : AppCompatActivity() {
binding.btnGo.setOnClickListener {
val serialNumber = binding.nameEditText.text.toString().trim()
if (serialNumber.isNotEmpty() && checkDataNotNull() && isSerialValid(serialNumber)) {
DataHolder.selectedTest!!.kitSerial = binding.nameEditText.text.toString()
DataHolder.kitSerial = binding.nameEditText.text.toString()
DataHolder.selectedTest?.kitSerial = binding.nameEditText.text.toString()
with(sharedPreference.edit()) {
putString(Constants.KIT_NUMBER, binding.nameEditText.text.toString())
putInt(Constants.KIT_COUNT, 1)
apply()
}
moveToNext()
} else {
Toast.makeText(this, "Invalid KIT Number", Toast.LENGTH_LONG).show()
@@ -63,6 +90,12 @@ class KitScanActivity : AppCompatActivity() {
}
}
private fun checkHemoCubeKitData(): Boolean {
return sharedPreference.getString(Constants.KIT_NUMBER, "")
?.isNotBlank() == true && sharedPreference.getInt(Constants.KIT_COUNT, 0) > 0
&& sharedPreference.getInt(Constants.KIT_COUNT, 0) < 35
}
private fun isSerialValid(s: String): Boolean {
if (s.length != 17) {
binding.nameEditText.error = getString(R.string.invalid_kit)
@@ -72,7 +105,7 @@ class KitScanActivity : AppCompatActivity() {
}
private fun moveToNext() {
val i = Intent(applicationContext, TestRightActivity::class.java)
val i = Intent(applicationContext, BloodCollectingMethodActivity::class.java)
startActivity(i)
}
@@ -95,9 +128,7 @@ class KitScanActivity : AppCompatActivity() {
private fun checkDataNotNull(): Boolean {
return if (DataHolder.selectedTest?._id == null) {
Toast.makeText(
applicationContext,
"Please Select patient before starting test",
Toast.LENGTH_SHORT
applicationContext, "Please Select patient before starting test", Toast.LENGTH_SHORT
).show()
val i = Intent(applicationContext, DashboardActivity::class.java)

View File

@@ -1,16 +1,16 @@
package com.example.hpostesting.presentation
import android.Manifest
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.*
import android.content.pm.PackageManager
import android.hardware.usb.UsbManager
import android.location.Location
import android.os.Bundle
import android.util.Log
import android.view.Menu
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
@@ -20,11 +20,7 @@ import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.data.model.test.TestType
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationCallback
import com.google.android.gms.location.LocationRequest
import com.google.android.gms.location.LocationResult
import com.google.android.gms.location.LocationServices
import com.google.android.gms.location.*
import com.hoho.android.usbserial.driver.UsbSerialProber
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityMainBinding
@@ -32,22 +28,18 @@ import `in`.sminnovations.hpostesting.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private var myMenu: Menu? = null
private val TAG = "MainActivity"
private lateinit var fusedLocationClient: FusedLocationProviderClient
private lateinit var locationCallback: LocationCallback
private var mUsbReceiver: BroadcastReceiver = object : BroadcastReceiver() {
private val usbReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent) {
val action = intent.action
if (UsbManager.ACTION_USB_DEVICE_DETACHED == action) {
DataHolder.usbConnected.value = false
} else if (UsbManager.ACTION_USB_DEVICE_ATTACHED == action) {
DataHolder.usbConnected.value = true
when (intent.action) {
UsbManager.ACTION_USB_DEVICE_DETACHED -> DataHolder.usbConnected.value = false
UsbManager.ACTION_USB_DEVICE_ATTACHED -> DataHolder.usbConnected.value = true
}
checkAndUpdateUsbConnection()
}
}
@@ -64,32 +56,101 @@ class MainActivity : AppCompatActivity() {
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
locationResult.lastLocation?.let { location ->
DataHolder.location = UserData.Location(location.latitude, location.longitude)
DataHolder.location =
UserData.Location(location.latitude, location.longitude)
DataHolder.selectedTest?.location =
UserData.Location(location.latitude, location.longitude)
Log.i("Location", DataHolder.location.toString())
}
}
}
val filter = IntentFilter().apply {
val usbFilter = IntentFilter().apply {
addAction(UsbManager.ACTION_USB_DEVICE_DETACHED)
addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED)
}
registerReceiver(mUsbReceiver, filter)
registerReceiver(usbReceiver, usbFilter)
DataHolder.deviceType.observe(this) { deviceType ->
with(binding) {
if (deviceType == Constants.DEVICE_TYPE_HOMOCUBE) {
cvItem1.visibility = View.VISIBLE
cvItem3.visibility = View.VISIBLE
cvItem2.visibility = View.GONE
cvItem4.visibility = View.GONE
}
DataHolder.usbConnected.value = true
}
}
// val crashButton = Button(this)
// crashButton.text = "Test Crash"
// crashButton.setOnClickListener {
// throw RuntimeException("Test Crash") // Force a crash
// }
//
// addContentView(crashButton, ViewGroup.LayoutParams(
// ViewGroup.LayoutParams.MATCH_PARENT,
// ViewGroup.LayoutParams.WRAP_CONTENT))
}
private fun checkAndUpdateUsbConnection() {
val availableDrivers = UsbSerialProber.getDefaultProber()
.findAllDrivers(getSystemService(Context.USB_SERVICE) as UsbManager)
if (availableDrivers.isNotEmpty() && availableDrivers[0].device.productId == Constants.DEVICE_PRODUCT_ID && availableDrivers[0].device.vendorId == Constants.DEVICE_VENDOR_ID) {
Log.d(TAG, "Device matched -> product = ${availableDrivers[0].device.productId}, vendor = ${availableDrivers[0].device.vendorId}")
DataHolder.usbConnected.value = true
} else if (availableDrivers.isNotEmpty()) {
Log.d(TAG, "Device NOT matched -> product = ${availableDrivers[0].device.productId}, vendor = ${availableDrivers[0].device.vendorId}")
Toast.makeText(this, "Device Not Compatible", Toast.LENGTH_SHORT).show()
val deviceType = when {
availableDrivers.isNotEmpty() -> {
val device = availableDrivers[0].device
when {
device.productId == Constants.HOMO_CUBE_ID && device.vendorId == Constants.VENDOR_ID -> {
binding.cvItem1.visibility = View.VISIBLE
binding.cvItem3.visibility = View.VISIBLE
binding.cvItem2.visibility = View.GONE
binding.cvItem4.visibility = View.GONE
DataHolder.deviceType.postValue(Constants.DEVICE_TYPE_HOMOCUBE)
Constants.DEVICE_TYPE_HOMOCUBE
}
device.productId == Constants.DEVICE_PRODUCT_ID && device.vendorId == Constants.DEVICE_VENDOR_ID -> {
Log.d(
TAG,
"Device matched -> product = ${device.productId}, vendor = ${device.vendorId}"
)
binding.cvItem1.visibility = View.VISIBLE
binding.cvItem3.visibility = View.VISIBLE
binding.cvItem2.visibility = View.VISIBLE
binding.cvItem4.visibility = View.VISIBLE
DataHolder.deviceType.postValue(Constants.DEVICE_TYPE_TEST_RIGHT)
Constants.DEVICE_TYPE_TEST_RIGHT
}
else -> {
Log.d(
TAG,
"Device NOT matched -> product = ${device.productId}, vendor = ${device.vendorId}"
)
val message =
if (device.productId == Constants.DEVICE_PRODUCT_ID) "Device Not Compatible" else "Device Not Connected"
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
DataHolder.usbConnected.value = false
} else {
null
}
}
}
else -> {
Log.d(TAG, "Device NOT Connected")
Toast.makeText(this, "Device Not Connected", Toast.LENGTH_SHORT).show()
DataHolder.usbConnected.value = false
null
}
}
deviceType?.let {
DataHolder.usbConnected.value = true
DataHolder.deviceType.postValue(it)
}
}
@@ -108,9 +169,11 @@ class MainActivity : AppCompatActivity() {
DataHolder.usbConnected.observe(this) {
if (it) {
myMenu?.get(0)?.icon = ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_24)
myMenu?.get(0)?.icon =
ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_24)
} else {
myMenu?.get(0)?.icon = ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_off_24)
myMenu?.get(0)?.icon =
ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_off_24)
}
}
}
@@ -127,14 +190,11 @@ class MainActivity : AppCompatActivity() {
val coarseLocationPermissionRequestCode = 101
if (ContextCompat.checkSelfPermission(
this,
coarseLocationPermission
this, coarseLocationPermission
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this,
arrayOf(coarseLocationPermission),
coarseLocationPermissionRequestCode
this, arrayOf(coarseLocationPermission), coarseLocationPermissionRequestCode
)
} else {
getLocation()
@@ -146,14 +206,11 @@ class MainActivity : AppCompatActivity() {
val fineLocationPermissionRequestCode = 102
if (ContextCompat.checkSelfPermission(
this,
fineLocationPermission
this, fineLocationPermission
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this,
arrayOf(fineLocationPermission),
fineLocationPermissionRequestCode
this, arrayOf(fineLocationPermission), fineLocationPermissionRequestCode
)
} else {
getLocation()
@@ -165,12 +222,9 @@ class MainActivity : AppCompatActivity() {
val fineLocationPermission = Manifest.permission.ACCESS_FINE_LOCATION
if (ActivityCompat.checkSelfPermission(
this,
coarseLocationPermission
) != PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(
this,
fineLocationPermission
this, coarseLocationPermission
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
this, fineLocationPermission
) != PackageManager.PERMISSION_GRANTED
) {
// Handle location permission request if needed
@@ -180,16 +234,16 @@ class MainActivity : AppCompatActivity() {
return
}
fusedLocationClient.lastLocation
.addOnSuccessListener { location: Location? ->
fusedLocationClient.lastLocation.addOnSuccessListener { location: Location? ->
location?.let {
DataHolder.location = UserData.Location(location.latitude, location.longitude)
Log.i("Location", DataHolder.location.toString())
DataHolder.selectedTest!!.location =
UserData.Location(location.latitude, location.longitude)
DataHolder.location =
UserData.Location(location.latitude, location.longitude)
} ?: run {
requestLocationUpdates()
}
}
.addOnFailureListener { exception: Exception ->
}.addOnFailureListener { exception: Exception ->
exception.printStackTrace()
}
}
@@ -202,12 +256,9 @@ class MainActivity : AppCompatActivity() {
}
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
this, Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
this, Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
return
@@ -226,9 +277,7 @@ class MainActivity : AppCompatActivity() {
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
requestCode: Int, permissions: Array<String>, grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when (requestCode) {
@@ -238,16 +287,19 @@ class MainActivity : AppCompatActivity() {
requestFineLocationPermission()
} else {
// Coarse location permission denied
Toast.makeText(this, "Coarse location permission denied", Toast.LENGTH_SHORT).show()
Toast.makeText(this, "Coarse location permission denied", Toast.LENGTH_SHORT)
.show()
}
}
102 -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Fine location permission granted
getLocation()
} else {
// Fine location permission denied
Toast.makeText(this, "Fine location permission denied", Toast.LENGTH_SHORT).show()
Toast.makeText(this, "Fine location permission denied", Toast.LENGTH_SHORT)
.show()
}
}
}

View File

@@ -10,12 +10,16 @@ import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.presentation.testRight.TestRightViewModel
import com.firebase.ui.firestore.FirestoreRecyclerAdapter
import com.firebase.ui.firestore.FirestoreRecyclerOptions
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.UserItemViewBinding
class UserListAdapter(options: FirestoreRecyclerOptions<UserData>, private val view: View) :
class UserListAdapter(
options: FirestoreRecyclerOptions<UserData>,
private val view: View
) :
FirestoreRecyclerAdapter<UserData, UserListAdapter.OrderItemViewHolder>(options) {
class OrderItemViewHolder(val binding: UserItemViewBinding) :
@@ -30,8 +34,8 @@ class UserListAdapter(options: FirestoreRecyclerOptions<UserData>, private val v
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: OrderItemViewHolder, position: Int, model: UserData) {
holder.binding.apply {
userName.text = model.name
userId.text = model._id
userName.text = "Name: ${model.name}"
userId.text = "User ID:${model._id}"
Glide.with(view).load(model.userImageURL).into(userImage)
if (model.testStatus!!) {
teststatus.text = "Test concluded"

View File

@@ -6,7 +6,7 @@ import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import com.example.hpostesting.presentation.dashboard.ui.gallery.GalleryViewModel
//import com.example.hpostesting.presentation.dashboard.ui.gallery.GalleryViewModel
import `in`.sminnovations.hpostesting.databinding.FragmentGalleryBinding
class GalleryFragment : Fragment() {
@@ -22,10 +22,10 @@ class GalleryFragment : Fragment() {
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val galleryViewModel =
ViewModelProvider(this).get(GalleryViewModel::class.java)
// val galleryViewModel =
// ViewModelProvider(this).get(GalleryViewModel::class.java)
_binding = FragmentGalleryBinding.inflate(inflater, container, false)
// _binding = FragmentGalleryBinding.inflate(inflater, container, false)
val root: View = binding.root
// val textView: TextView = binding.textGallery

View File

@@ -5,7 +5,6 @@ import android.content.Context
import android.content.DialogInterface
import android.content.SharedPreferences
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -15,8 +14,10 @@ import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.presentation.adapter.UserListAdapter
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.example.hpostesting.presentation.testRight.TestRightViewModel
import com.firebase.ui.firestore.FirestoreRecyclerOptions
import com.google.firebase.firestore.ktx.firestore
@@ -28,10 +29,10 @@ import java.util.Locale
@AndroidEntryPoint
class HomeFragment : Fragment() {
private var _binding: FragmentHomeBinding? = null
private val binding get() = _binding!!
private val viewModel: TestRightViewModel by activityViewModels()
private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels()
private lateinit var rvAdapter: UserListAdapter
private lateinit var sharedPreference: SharedPreferences
override fun onCreateView(
@@ -43,12 +44,17 @@ class HomeFragment : Fragment() {
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.allUserData.observe(viewLifecycleOwner) { userData ->
if (userData.isNotEmpty()) {
}
deleteIncompleteRegistrations(userData)
}
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userData ->
deleteHemoCubeIncompleteRegistrations(userData)
}
viewModel.networkStatusLiveData.observe(viewLifecycleOwner) { isConnected ->
if (isConnected) {
binding.internetAvailableCL.visibility = View.VISIBLE
@@ -69,7 +75,6 @@ class HomeFragment : Fragment() {
showUploadDialog(requireContext())
}
}
private fun setUserId() {
binding.btnSubmit.setOnClickListener {
val userId = binding.userId.text.toString()
@@ -84,9 +89,15 @@ class HomeFragment : Fragment() {
}
}
}
private fun loadUserData() {
val query = Firebase.firestore.collection("patientData")
val query = Firebase.firestore.collection("patientData").whereEqualTo("testStatus", false)
query.get().addOnSuccessListener {
if (it.documents.isEmpty()) {
binding.pendingTest.visibility = View.VISIBLE
} else {
binding.pendingTest.visibility = View.GONE
}
}
val recyclerViewOptions =
FirestoreRecyclerOptions.Builder<UserData>().setQuery(query, UserData::class.java)
.build()
@@ -94,7 +105,6 @@ class HomeFragment : Fragment() {
binding.rvOrder.adapter = rvAdapter
rvAdapter.startListening()
}
private fun saveUserId(userId: String) {
with(sharedPreference.edit()) {
putString(Constants.USER_ID, userId)
@@ -105,15 +115,11 @@ class HomeFragment : Fragment() {
val builder = AlertDialog.Builder(context)
builder.setTitle("Log Out")
builder.setMessage("Do you want to LogOut the Application?")
// Positive button
builder.setPositiveButton("Yes") { dialog, _ ->
saveUserId("")
findNavController().navigate(R.id.action_nav_home_to_loginFragment)
dialog.dismiss()
}
// Negative button
builder.setNegativeButton("No") { dialog, _ ->
dialog.dismiss()
}
@@ -121,9 +127,6 @@ class HomeFragment : Fragment() {
val dialog = builder.create()
dialog.show()
}
private fun getData(search: String?, field: String) {
val capitalizedSearch = search?.replaceFirstChar {
if (search.lowercase()
@@ -131,19 +134,15 @@ class HomeFragment : Fragment() {
) it.titlecase(Locale.getDefault()) else it.toString()
}
val query = Firebase.firestore.collection("patientData").orderBy(field).startAt(search)
.endAt(search + "\uf8ff")
val recyclerViewOptions =
FirestoreRecyclerOptions.Builder<UserData>().setQuery(query, UserData::class.java)
.build()
rvAdapter = UserListAdapter(recyclerViewOptions, binding.root)
binding.rvOrder.adapter = rvAdapter
rvAdapter.startListening()
}
private fun setSearch() {
binding.searchProduct.setOnQueryTextListener(object :
androidx.appcompat.widget.SearchView.OnQueryTextListener {
@@ -162,7 +161,6 @@ class HomeFragment : Fragment() {
false
}
}
override fun onQueryTextChange(query: String?): Boolean {
return if (!query.isNullOrEmpty()) {
val field = when {
@@ -180,14 +178,17 @@ class HomeFragment : Fragment() {
}
})
}
private fun checkForLocalDBData() {
viewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
val uploadDataVisibility = if (userDataList.isEmpty()) View.GONE else View.VISIBLE
binding.uploadData.visibility = uploadDataVisibility
}
}
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
val uploadDataVisibility = if (userDataList.isEmpty()) View.GONE else View.VISIBLE
binding.uploadData.visibility = uploadDataVisibility
}
}
private fun showUploadDialog(context: Context) {
val builder = AlertDialog.Builder(context)
builder.setTitle(R.string.upload_db_registration_title)
@@ -222,16 +223,41 @@ class HomeFragment : Fragment() {
).show()
}
}
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
if (userDataList.isEmpty()) {
dialog.dismiss()
} else {
userDataList.forEach { userData ->
userData.localFlag = true
hemoCubeViewModel.bulkAddResultTestToDb(userData)
}
dialog.dismiss()
Toast.makeText(
requireContext(),
R.string.upload_success_message,
Toast.LENGTH_SHORT
).show()
}
}
}
private fun deleteIncompleteRegistrations(userDataList: List<UserData>) {
userDataList.forEach { userData ->
if (userData._id.isEmpty()) {
if (userData.csvPath.isEmpty()) {
viewModel.deleteById(userData._id)
}
}
}
private fun deleteHemoCubeIncompleteRegistrations(userDataList: List<HemoCubeTestData>) {
userDataList.forEach { userData ->
if (userData.testTime?.isEmpty() == false) {
hemoCubeViewModel.deleteById(userData._id)
}
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null

View File

@@ -0,0 +1,556 @@
package com.example.hpostesting.presentation.hemocube
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.toHemoCubeTestData
import com.example.hpostesting.presentation.KitScanActivity
import com.example.hpostesting.presentation.UsbServiceListener
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.example.hpostesting.presentation.utils.MyDialogListener
import com.example.hpostesting.presentation.utils.UIUtils
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.firestore.ktx.firestore
import com.google.firebase.ktx.Firebase
import `in`.sminnovations.hpostesting.BuildConfig
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentHemoCubeReferenceBinding
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.tasks.await
import kotlinx.coroutines.withContext
import kotlin.math.log10
class HemoCubeFragment : Fragment() {
private lateinit var binding: FragmentHemoCubeReferenceBinding
private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels()
private lateinit var sharedPreferences: SharedPreferences
private var isOnline = false
private var currentDeviceData: DeviceData? = null
private var resultData: String = ""
private var isUsingExistingBuffer = false
private var isTestOngoing = false
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
binding = FragmentHemoCubeReferenceBinding.inflate(inflater, container, false)
sharedPreferences =
requireContext().getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initViews()
observeViewModel()
checkAndStartProcess()
}
private fun initViews() {
binding.btnSubmit.setOnClickListener {
val bloodGroupText = binding.etBloodGroup.text.toString()
if (bloodGroupText.isEmpty()) {
binding.etBloodGroup.error = "Please enter your blood group"
} else {
fetchResult()
}
}
if (isTestOngoing) {
binding.btnKit.visibility = View.GONE
binding.btnKit.isEnabled = false
binding.btnKit.isClickable = false
}
binding.btnSubmit.isEnabled = false
binding.btnSubmit.isClickable = false
binding.btnKit.setOnClickListener {
if (isTestOngoing) {
val title = "WARNING"
val message = "There is a on going test, do you want to stop it"
val negativeText = getString(R.string.no)
val positiveText = "Yes"
UIUtils.createAlertDialog(requireContext(),
title,
message,
negativeText,
positiveText,
object : MyDialogListener {
override fun onClickNegativeButton() {
}
override fun onClickPositiveButton() {
resetKitCount()
val intent = Intent(context, KitScanActivity::class.java)
startActivity(intent)
(activity as HemocubeActivity).finish()
}
})
}
}
}
private suspend fun checkBloodGroup() {
binding.apply {
val bloodGroup = etBloodGroup.text.toString()
if (bloodGroup.isEmpty()) {
etBloodGroup.error = "Please enter your blood group"
} else {
val db: FirebaseFirestore = Firebase.firestore
val userdata = db.collection("patientData")
.whereEqualTo("_id", hemoCubeViewModel.testDetails?._id).get().await()
if (userdata.documents.isNotEmpty()) {
db.collection("patientData").document(userdata.documents[0].id)
.update("bloodGroup", bloodGroup)
withContext(Dispatchers.Main) {
val i = Intent(
requireContext().applicationContext, DashboardActivity::class.java
)
startActivity(i)
(activity as HemocubeActivity).finish()
}
}
}
}
}
private fun observeViewModel() {
hemoCubeViewModel.fireBaseUpload.observe(viewLifecycleOwner) { result ->
if (result == "Success") {
showToast("Test Results Uploaded Successfully")
lifecycleScope.launch {
checkBloodGroup()
}
}
if (result == "Local") {
showToast("Internet not available, test details stored locally")
startActivity(Intent(requireActivity(), DashboardActivity::class.java))
}
binding.progressBar.visibility = View.GONE
}
hemoCubeViewModel.getDeviceData(sharedPreferences.getString(Constants.USER_ID, ""))
hemoCubeViewModel.deviceData.observe(viewLifecycleOwner) {
currentDeviceData = it
showToast(calculateRatio(0.17).toString())
}
hemoCubeViewModel.networkStatusLiveData.observe(viewLifecycleOwner) { isNetworkAvailable ->
isOnline = isNetworkAvailable
}
hemoCubeViewModel.messages.observe(viewLifecycleOwner) {
binding.tvSubtitle4.text = it
}
}
private fun checkAndStartProcess() {
if (isBufferValueAvailable()) {
showBufferAlertDialog()
} else {
listenToHemoCube()
startBufferProcess()
}
}
private fun isBufferValueAvailable(): Boolean {
return if (sharedPreferences.getString(
Constants.BUFFER_VALUE_1, ""
) != "" && sharedPreferences.getString(Constants.BUFFER_VALUE_2, "") != ""
) {
sharedPreferences.getString(Constants.BUFFER_VALUE_1, "")
?.toDouble()!! > 0.0 && sharedPreferences.getString(Constants.BUFFER_VALUE_2, "")
?.toDouble()!! > 0.0
} else {
false
}
}
private fun showBufferAlertDialog() {
val title = "WARNING"
val message = "Do you want to continue with existing buffer?"
val negativeText = getString(R.string.no)
val positiveText = "Yes"
UIUtils.createAlertDialog(requireContext(),
title,
message,
negativeText,
positiveText,
object : MyDialogListener {
override fun onClickNegativeButton() {
listenToHemoCube()
startBufferProcess()
}
override fun onClickPositiveButton() {
listenToHemoCube()
startSampleProcess()
isUsingExistingBuffer = true
}
})
}
private fun listenToHemoCube() {
if (DataHolder.hemoCubeTestData == null) {
DataHolder.hemoCubeTestData = DataHolder.selectedTest?.toHemoCubeTestData()
}
hemoCubeViewModel.progressBar.postValue(true)
val fullReadOutput = StringBuilder()
(activity as HemocubeActivity).mService.listenToHemoCube(object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
data?.let {
val stringData = String(it)
fullReadOutput.append(stringData)
handleUsbData(stringData, fullReadOutput)
}
}
override fun onUsbError(e: Exception?) {
hemoCubeViewModel.progressBar.postValue(false)
}
})
}
private fun handleUsbData(stringData: String, fullReadOutput: StringBuilder) {
if (stringData.contains("#")) {
hemoCubeViewModel.messages.postValue(stringData)
isTestOngoing = true
}
resultData += fullReadOutput.toString()
when {
stringData.contains("#Buffer Completed") -> showStartSampleDialog()
stringData.contains("#Sample Completed") -> {
activity?.runOnUiThread {
binding.btnSubmit.isEnabled = true
binding.btnSubmit.isClickable = true
}
}
stringData.contains("RESULT") || resultData.contains("REND") -> {
var validString: String
val results: List<String>
if (stringData.contains("RESULT")) {
validString = isValidResult(stringData)
if (validString.isEmpty()) {
results = resultData.split("\n")
validString = parseResult(results)
}
} else {
results = resultData.split("\n")
validString = parseResult(results)
}
if (validString.isNotEmpty()) {
handleValidResult(validString, resultData)
}
}
}
}
private fun showStartSampleDialog() {
activity?.runOnUiThread {
UIUtils.createAlertDialog(requireContext(),
"Start Sample",
"Do you want to start sample reading?",
getString(R.string.no),
"Yes",
object : MyDialogListener {
override fun onClickNegativeButton() {}
override fun onClickPositiveButton() {
}
})
}
}
private fun handleValidResult(validString: String, fullReadOutput: String) {
try {
val result = validString.split(" ")
if (result.size != 8) return
val deviceSerialNo = result[2]
val led1BufferForDevice =
getLedBufferValue(isUsingExistingBuffer, Constants.BUFFER_VALUE_1, result[3])
val led2BufferForDevice =
getLedBufferValue(isUsingExistingBuffer, Constants.BUFFER_VALUE_2, result[4])
val version = BuildConfig.VERSION_NAME
val led1Sample = result[5].toDoubleOrNull()
val led2Sample = result[6].toDoubleOrNull()
val led1Average = calculateAverage(led1BufferForDevice, led1Sample)
val led2Average = calculateAverage(led2BufferForDevice, led2Sample)
val deviceRatio = led1Average / led2Average
val calculatedRatio = calculateRatio(deviceRatio)
val isBufferValid = validateBuffer(led1BufferForDevice, led2BufferForDevice)
val isSampleValid =
validateSample(led1Sample, led1BufferForDevice, led2Sample, led2BufferForDevice)
val isCalculatedRatioValid = validateCalculatedRatio(deviceRatio)
when {
!isBufferValid -> showError(
"Buffer error",
"Check for Empty curved, disconnected and reconnect the device, and please retest this sample again with a new blank"
)
!isSampleValid -> showError(
"Sample error",
"Check for Empty curved, disconnected and reconnect the device, and please retest this sample again with a new blank"
)
!validateBloodVolume(led1Average, led2Average) -> {
showError(
"Low Blood Volume",
"Please retest this sample with a higher volume of blood"
)
}
!validateHighBloodVolume(led1Average, led2Average) -> {
showError(
"High Blood Volume",
"Please retest this sample by diluting the sample in the buffer"
)
}
!isCalculatedRatioValid -> showError(
"calculated Ratio error",
"Check for Empty curved, disconnected and reconnect the device, and please retest this sample again with a new blank"
)
else -> processValidData(
deviceSerialNo,
led1BufferForDevice,
led2BufferForDevice,
version,
led1Sample,
led2Sample,
led1Average,
led2Average,
deviceRatio,
fullReadOutput,
calculatedRatio
)
}
} catch (_: Exception) {
// handle exception or log it if necessary
}
}
private fun getLedBufferValue(
usingExistingBuffer: Boolean, bufferConstant: String, resultValue: String
): Double? {
return if (usingExistingBuffer) {
sharedPreferences.getString(bufferConstant, "")?.toDoubleOrNull()
} else {
resultValue.toDoubleOrNull()
}
}
private fun calculateAverage(bufferForDevice: Double?, sample: Double?): Double {
return log10(bufferForDevice?.div(sample ?: 1.0) ?: 0.0)
}
private fun validateBuffer(led1Buffer: Double?, led2Buffer: Double?): Boolean {
return led1Buffer!! in 20001.0..23999.0 && led2Buffer!! in 20001.0..23999.0
}
private fun validateSample(
sample1: Double?, buffer1: Double?, sample2: Double?, buffer2: Double?
): Boolean {
return sample1 != null && sample1 < buffer1!! && sample1 < 24000 && sample2 != null && sample2 < buffer2!! && sample2 < 24000
}
private fun validateBloodVolume(average1: Double, average2: Double): Boolean {
return average1 > 0.08 && average2 > 0.08
}
private fun validateCalculatedRatio(deviceRatio: Double): Boolean {
return deviceRatio > 0.08 && deviceRatio < 0.3
}
private fun validateHighBloodVolume(average1: Double, average2: Double): Boolean {
return average1 < 1.07 && average2 < 1.07
}
private fun showError(title: String, message: String) {
customErrorDialogBox(title, message)
}
private fun processValidData(
deviceId: String,
led1Buffer: Double?,
led2Buffer: Double?,
appVersion: String,
led1Sample: Double?,
led2Sample: Double?,
led1Average: Double,
led2Average: Double,
deviceRatio: Double,
resultData: String,
calculatedRatio: Double
) {
val threshold =
if ((activity as HemocubeActivity).bloodCollectingMethod == Constants.FINGER_PRICK_BLOOD) 0.05 else 0.06
if (led1Average > threshold) {
DataHolder.hemoCubeTestData?.apply {
this.deviceId = deviceId
this.led1Buffer = led1Buffer
this.led2Buffer = led2Buffer
this.appVersion = appVersion
this.led1Sample = led1Sample
this.led2Sample = led2Sample
this.led1Average = led1Average
this.led2Average = led2Average
this.deviceRatio = deviceRatio
this.calculatedRatio = calculatedRatio
this.resultData = resultData
if (!isBufferValueAvailable()) {
with(sharedPreferences.edit()) {
putString(Constants.BUFFER_VALUE_1, led1Buffer.toString())
putString(Constants.BUFFER_VALUE_2, led2Buffer.toString())
apply()
}
}
hemoCubeViewModel.uploadHemoCubeResultToDatabase(
isOnline, true, sharedPreferences.getString(Constants.KIT_NUMBER, "")
)
}
} else {
showError(
"Low Blood Volume",
"Please repeat the test with 10 µl of blood added to 1 ml of buffer"
)
}
}
private fun customErrorDialogBox(title: String, message: String) {
activity?.runOnUiThread {
MaterialAlertDialogBuilder(requireContext()).setTitle(title).setMessage(message)
.setPositiveButton("OK") { dialog, _ ->
if (title == "Buffer error" || title == "Sample error") {
with(sharedPreferences.edit()) {
putString(Constants.BUFFER_VALUE_1, "")
putString(Constants.BUFFER_VALUE_2, "")
apply()
}
finishTestingActivity()
} else {
finishTestingActivity()
}
dialog.dismiss()
}.show()
}
}
private fun finishTestingActivity() {
val i = Intent(requireContext().applicationContext, DashboardActivity::class.java)
startActivity(i)
(activity as HemocubeActivity).finish()
}
private fun showToast(message: String) {
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
}
private fun startBufferProcess() {
hemoCubeViewModel.progressBar.postValue(true)
(activity as HemocubeActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.startBuffer,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {}
override fun onUsbError(e: Exception?) {
hemoCubeViewModel.progressBar.postValue(false)
}
})
}
private fun startSampleProcess() {
hemoCubeViewModel.progressBar.postValue(true)
(activity as HemocubeActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.startSample,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {}
override fun onUsbError(e: Exception?) {
hemoCubeViewModel.progressBar.postValue(false)
}
})
}
private fun fetchResult() {
hemoCubeViewModel.progressBar.postValue(true)
(activity as HemocubeActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.getSample,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {}
override fun onUsbError(e: Exception?) {
hemoCubeViewModel.progressBar.postValue(false)
}
})
}
private fun calculateRatio(ratio: Double): Double {
val coefficient1 = currentDeviceData?.coefficients?.get(0) ?: 0.0
val coefficient2 = currentDeviceData?.coefficients?.get(1) ?: 0.0
return coefficient1 * ratio + coefficient2
}
private fun parseResult(frames: List<String>): String {
val lines = mutableListOf<String>()
for (frame in frames.reversed()) {
if (frame.contains("REND") || frame.contains("RESULT")) lines += frame
if (frame.contains("RESULT")) {
break
}
}
val line = lines.reversed().joinToString("").trim()
if (line.contains("RESULT") && line.split(" ").size == 8) {
return line
}
return ""
}
private fun isValidResult(line: String): String {
return if (line.contains("RESULT") && line.split(" ").size == 8) {
line
} else {
""
}
}
private fun resetKitCount() {
with(sharedPreferences.edit()) {
putString(Constants.KIT_NUMBER, "")
putInt(Constants.KIT_COUNT, 0)
apply()
}
}
}

View File

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

View File

@@ -0,0 +1,178 @@
package com.example.hpostesting.presentation.hemocube
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.ServiceConnection
import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbDeviceConnection
import android.hardware.usb.UsbManager
import android.os.Bundle
import android.os.IBinder
import android.util.Log
import android.view.Menu
import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.get
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.presentation.testRight.UsbService
import com.hoho.android.usbserial.driver.UsbSerialDriver
import com.hoho.android.usbserial.driver.UsbSerialProber
import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityHemocubeBinding
@AndroidEntryPoint
class HemocubeActivity : AppCompatActivity() {
private lateinit var binding: ActivityHemocubeBinding
private val viewModel by viewModels<HemoCubeViewModel>()
private var myMenu: Menu? = null
private lateinit var mDriver: UsbSerialDriver
private var mConnection: UsbDeviceConnection? = null
lateinit var mService: UsbService
private val TAG = "HemoCube"
var bloodCollectingMethod = ""
private val broadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
synchronized(this) {
val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
device?.apply {
connectUsb(true)
DataHolder.usbConnected.postValue(true)
}
} else {
onErrorReported("permission denied for device")
DataHolder.usbConnected.postValue(true)
}
}
}
}
private val connection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) {
val binder = service as UsbService.UsbServiceBinder
mService = binder.getService()
viewModel.isServiceConnected = true
mConnection.let { mService.connect(mDriver, mConnection!!) }
moveToNext()
}
override fun onServiceDisconnected(arg0: ComponentName) {
viewModel.isServiceConnected = false
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityHemocubeBinding.inflate(layoutInflater)
setContentView(binding.root)
bloodCollectingMethod = intent.getStringExtra(Constants.BLOOD_COLLECTING_METHOD).toString()
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()
}
}
}
private fun connectUsb(permissionGranted: Boolean) {
Log.d(TAG, "connectUsb() called, permission variable = $permissionGranted")
val manager = getSystemService(Context.USB_SERVICE) as UsbManager
val availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager)
if (availableDrivers.isEmpty()) {
onErrorReported("No Device is Connected")
} else {
mDriver = availableDrivers[0]
mConnection = manager.openDevice(mDriver.device)
if (mConnection == null) {
requestUserPermission(manager, mDriver.device)
} else {
setupService()
}
}
}
private fun requestUserPermission(manager: UsbManager, device: UsbDevice) {
val mPendingIntent: PendingIntent = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
PendingIntent.getBroadcast(
this,
0,
Intent(Constants.HOMOCUBE_USB_PERMISSION),
PendingIntent.FLAG_MUTABLE
)
} else {
PendingIntent.getBroadcast(
this,
0,
Intent(Constants.HOMOCUBE_USB_PERMISSION),
PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
)
}
val filter = IntentFilter(Constants.HOMOCUBE_USB_PERMISSION)
registerReceiver(broadcastReceiver, filter)
manager.requestPermission(device, mPendingIntent)
}
private fun setupService() {
val intent = Intent(this, UsbService::class.java)
// startService(intent)
bindService(intent, connection, Context.BIND_AUTO_CREATE)
}
private fun moveToNext() {
if (supportFragmentManager.isDestroyed)
return
supportFragmentManager.beginTransaction()
.replace(binding.fghemocube.id, HemoCubeFragment()).commit()
}
fun onErrorReported(msg: String) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
if (!isFinishing)
onBackPressed()
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.my_menu, menu)
return true
}
override fun onDestroy() {
super.onDestroy()
if (viewModel.isServiceConnected) {
mService.disconnect()
unbindService(connection)
viewModel.isServiceConnected = false
}
}
}

View File

@@ -103,17 +103,6 @@ class TestRightActivity : AppCompatActivity() {
}
}
// private fun testing() {
// supportFragmentManager.beginTransaction()
// .replace(binding.flMain.id, TestRightExpSample()).commit()
// }
// Todo: Comment this
// private fun connectUsb(permissionGranted: Boolean) {
// setupService()
// }
// Todo: Uncomment this
private fun connectUsb(permissionGranted: Boolean) {
Log.d(TAG, "connectUsb() called, permission variable = $permissionGranted")
val manager = getSystemService(Context.USB_SERVICE) as UsbManager
@@ -124,12 +113,6 @@ class TestRightActivity : AppCompatActivity() {
} else {
mDriver = availableDrivers[0]
if (mDriver.device.productId != Constants.DEVICE_PRODUCT_ID || mDriver.device.vendorId != Constants.DEVICE_VENDOR_ID){
Toast.makeText(this, "Device Connected is not supported", Toast.LENGTH_SHORT).show()
onBackPressed()
return
}
viewModel.testDetails?.deviceId = mDriver.device.serialNumber.toString()
DataHolder.deviceSerialNumber = mDriver.device.serialNumber.toString()
mConnection = manager.openDevice(mDriver.device)
@@ -142,12 +125,7 @@ class TestRightActivity : AppCompatActivity() {
}
}
/*
* Request user permission. The response will be received in the BroadcastReceiver
*/
private fun requestUserPermission(manager: UsbManager, device: UsbDevice) {
// Log.d(TAG, "requestUserPermissions() called -> vendor id = ${device.vendorId} & product id = ${device.productId}")
val mPendingIntent: PendingIntent
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
mPendingIntent = PendingIntent.getBroadcast(
@@ -196,11 +174,6 @@ class TestRightActivity : AppCompatActivity() {
fun onErrorReported(msg: String) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
// Snackbar.make(binding.clParent, msg, Snackbar.LENGTH_LONG)
// .setAction("CLOSE") { Toast.makeText(this, "Will soon", Toast.LENGTH_SHORT).show() }
// .setActionTextColor(resources.getColor(R.color.white))
// .show()
if (!isFinishing)
onBackPressed()
}
@@ -210,16 +183,6 @@ class TestRightActivity : AppCompatActivity() {
myMenu = menu
return true
}
// override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
// R.id.action_usb -> {
//// Toast.makeText(this, "USB Connected", Toast.LENGTH_SHORT).show()
//// myMenu?.get(0)?.icon = ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_off_24)
// true
// }
// else -> {super.onOptionsItemSelected(item)}
// }
override fun onDestroy() {
super.onDestroy()
if (viewModel.isServiceConnected) {
@@ -228,10 +191,4 @@ class TestRightActivity : AppCompatActivity() {
viewModel.isServiceConnected = false
}
}
// fun View.setAllEnabled(enabled: Boolean) {
// isEnabled = enabled
// if (this is ViewGroup) children.forEach { child -> child.setAllEnabled(enabled) }
// }
}

View File

@@ -24,17 +24,12 @@ import `in`.sminnovations.hpostesting.databinding.FragmentTestRightExpReferenceB
@AndroidEntryPoint
class TestRightExpReference : Fragment() {
private lateinit var binding: FragmentTestRightExpReferenceBinding
private val viewModel: TestRightViewModel by activityViewModels()
private val TAG = "TestRightExpReference"
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
// Inflate the layout for this fragment
binding = FragmentTestRightExpReferenceBinding.inflate(inflater, container, false)
return binding.root
}
@@ -42,25 +37,17 @@ class TestRightExpReference : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupListeners()
// if (DataHolder.isReferenceTaken)
// moveToSamplePage()
//
// DataHolder.sampleReadCounter <= Constants.MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE
if (DataHolder.deviceConstant == null) {
viewModel.progressBar.postValue(true)
Handler(Looper.getMainLooper()).postDelayed(
{ sendCmdToFetchDeviceConstant() },
Constants.DELAY_BETWEEN_COMMANDS
{ sendCmdToFetchDeviceConstant() }, Constants.DELAY_BETWEEN_COMMANDS
)
}
}
private fun setupListeners() {
binding.btnSetReference.setOnClickListener {
UIUtils.createAlertDialog(
requireContext(),
UIUtils.createAlertDialog(requireContext(),
getString(R.string.have_you_placed),
getString(R.string.please_place),
getString(R.string.no),
@@ -69,6 +56,7 @@ class TestRightExpReference : Fragment() {
override fun onClickNegativeButton() {
}
override fun onClickPositiveButton() {
startTakingReference()
}
@@ -85,7 +73,6 @@ class TestRightExpReference : Fragment() {
}
viewModel.progressBar.observe(viewLifecycleOwner) {
// Log.d(TAG, "SURYA OBSERVER Activated outcome = $it")
if (it) {
binding.progressBar.visibility = View.VISIBLE
binding.clParent.alpha = 0.5f
@@ -96,7 +83,6 @@ class TestRightExpReference : Fragment() {
binding.btnSetReference.isEnabled = true
}
}
}
/**
@@ -107,19 +93,17 @@ class TestRightExpReference : Fragment() {
* 4. command print
*/
private fun startTakingReference() {
// requireActivity().runOnUiThread {
sendCmdToSetLed()
// }
}
// private fun sendCmdToFetchDeviceConstant(recursive: Boolean) {
private fun sendCmdToFetchDeviceConstant() {
Log.d(TAG, "sendCmdToFetchDeviceConstant() called")
viewModel.progressBar.postValue(true)
val fullReadOutput = StringBuilder()
(activity as TestRightActivity).mService.eventDrivenWrite(TestRightCommands.read,
(activity as TestRightActivity).mService.eventDrivenWrite(
TestRightCommands.read,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
data?.let {
@@ -129,8 +113,7 @@ class TestRightExpReference : Fragment() {
if (stringData.contains("OK", true)) {
Log.d(
TAG,
"onUsbRead() called in sendCmdToFetchDeviceConstant() found OK"
TAG, "onUsbRead() called in sendCmdToFetchDeviceConstant() found OK"
)
viewModel.mapDeviceConstants(fullReadOutput.toString())
viewModel.progressBar.postValue(false)
@@ -138,7 +121,11 @@ class TestRightExpReference : Fragment() {
Log.d(TAG, "results = FINE")
viewModel.progressBar.postValue(false)
viewModel.errorTriggered.postValue(ErrorMessage("Please Try Again!!", Constants.ERROR_CRITICAL))
viewModel.errorTriggered.postValue(
ErrorMessage(
"Please Try Again!!", Constants.ERROR_CRITICAL
)
)
}
}
@@ -146,7 +133,11 @@ class TestRightExpReference : Fragment() {
override fun onUsbError(e: Exception?) {
Log.e(TAG, "onUsbIoError() called in sendCmdToFetchDeviceConstant() -> $e")
viewModel.errorTriggered.postValue(ErrorMessage("Please Try Again this step", Constants.ERROR_NORMAL))
viewModel.errorTriggered.postValue(
ErrorMessage(
"Please Try Again this step", Constants.ERROR_NORMAL
)
)
viewModel.progressBar.postValue(false)
}
@@ -171,8 +162,7 @@ class TestRightExpReference : Fragment() {
Runnable {
viewModel.progressBar.postValue(false)
sendCmdToAutoset()
},
Constants.DELAY_BETWEEN_COMMANDS
}, Constants.DELAY_BETWEEN_COMMANDS
)
}
}
@@ -203,8 +193,7 @@ class TestRightExpReference : Fragment() {
Runnable {
viewModel.progressBar.postValue(false)
sendCmdToRun()
},
Constants.DELAY_BETWEEN_COMMANDS
}, Constants.DELAY_BETWEEN_COMMANDS
)
}
@@ -237,12 +226,10 @@ class TestRightExpReference : Fragment() {
Runnable {
viewModel.progressBar.postValue(false)
sendCmdToFetchLightIntensities()
},
Constants.DELAY_BETWEEN_COMMANDS
}, Constants.DELAY_BETWEEN_COMMANDS
)
}
}
// }
}
override fun onUsbError(e: Exception?) {
@@ -264,18 +251,15 @@ class TestRightExpReference : Fragment() {
data?.let {
val stringData = String(it)
fullReadOutput.append(stringData)
// Log.d(TAG, stringData)
// if (stringData.contains("OK", true)) {
// if (fullReadOutput.substring(Math.max(fullReadOutput.length - 15, 0)).contains("OK", true)) {
if (stringData.trim().isNotEmpty() && fullReadOutput.substring(Math.max(fullReadOutput.length - 15, 0)).contains("OK [0]", true)) {
if (stringData.trim().isNotEmpty() && fullReadOutput.substring(
Math.max(
fullReadOutput.length - 15, 0
)
).contains("OK [0]", true)
) {
Log.d(TAG, "onUsbRead() called in sendCmdToFetchLightIntensities()")
// Log.d(TAG, fullReadOutput.toString())
viewModel.mapIntensityValues(fullReadOutput.toString(), true)
// viewModel.saveLogTest(requireContext().applicationContext, true, fullReadOutput.toString())
DataHolder.isReferenceTaken = true
Handler(Looper.getMainLooper()).postDelayed(
@@ -290,7 +274,11 @@ class TestRightExpReference : Fragment() {
override fun onUsbError(e: Exception?) {
Log.e(TAG, "onUsbIoError() called in sendCmdToFetchLightIntensities() -> $e")
viewModel.errorTriggered.postValue(ErrorMessage("Please Try Again this step", Constants.ERROR_NORMAL))
viewModel.errorTriggered.postValue(
ErrorMessage(
"Please Try Again this step", Constants.ERROR_NORMAL
)
)
viewModel.progressBar.postValue(false)
}

View File

@@ -35,16 +35,7 @@ class TestRightExpSample : Fragment() {
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
// Inflate the layout for this fragment
binding = FragmentTestRightExpSampleBinding.inflate(inflater, container, false)
// if (DataHolder.sampleReadCounter > Constants.MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE) {
// binding.btnUpdateReference.enable()
// binding.clInstructions.setAllEnabled(false)
// } else {
// binding.btnUpdateReference.disable()
// binding.clInstructions.setAllEnabled(false)
// }
return binding.root
}
@@ -75,10 +66,15 @@ class TestRightExpSample : Fragment() {
}
binding.btnSubmit.setOnClickListener {
// val details = validateAndReturnTestData()
// if (details != null) {
// viewModel.patientDetails = details
UIUtils.createAlertDialog(
requireContext(),
"WARNING",
"Please check if you have placed the sample of this person ${viewModel.testDetails?._id}",
getString(R.string.no),
"Yes",
object : MyDialogListener {
override fun onClickNegativeButton() {}
override fun onClickPositiveButton() {
UIUtils.createAlertDialog(
requireContext(),
getString(R.string.have_you_placed_sample),
@@ -91,6 +87,8 @@ class TestRightExpSample : Fragment() {
startAcquiring()
}
})
}
})
// }
}
@@ -100,24 +98,13 @@ class TestRightExpSample : Fragment() {
val i = Intent(requireContext(), MainActivity::class.java)
startActivity(i)
}
// binding.etNameBlock.setOnClickListener { binding.etName.isErrorEnabled = false }
// binding.etAgeBlock.setOnClickListener { binding.etAge.isErrorEnabled = false }
// binding.etGenderBlock.setOnClickListener { binding.ddGender.isErrorEnabled = false }
}
// private fun validateAndReturnTestData(): TestDetails? {
//
// return PatientData(name.toString(), age.toString().toInt(), gender.toString(), TestRightResultType.UNDEFINED)
// }
/**
* Executing the commands sequentially each after successfully executing one.
* 1. command run
* 2. command print
*/
private fun startAcquiring() {
// binding.progressBar.visibility = View.VISIBLE
sendCmdToRun()
}
@@ -133,9 +120,6 @@ class TestRightExpSample : Fragment() {
val stringData = String(it)
fullReadOutput.append(stringData)
Log.d(TAG, stringData)
// if (stringData.contains("OK", true)) {
// if (stringData.contains("OK", true) || fullReadOutput.substring(Math.max(fullReadOutput.length - 15, 0)).contains("OK", true)) {
// if (fullReadOutput.substring(Math.max(fullReadOutput.length - 15, 0)).contains("OK", true)) {
if (fullReadOutput.substring(Math.max(fullReadOutput.length - 15, 0)).contains("OK [0]", true)) {
Log.d(TAG, "onUsbRead() called in sendCmdToRun()")
Handler(Looper.getMainLooper()).postDelayed(
@@ -172,17 +156,10 @@ class TestRightExpSample : Fragment() {
val stringData = String(it)
fullReadOutput.append(stringData)
Log.d(TAG, stringData)
// if (stringData.contains("OK", true)) {
// if (stringData.contains("OK", true) || stringData.contains("O", true) || stringData.contains("K", true)) {
// if (stringData.contains("OK", true) || fullReadOutput.substring(Math.max(fullReadOutput.length - 15, 0)).contains("OK", true)) {
// if (fullReadOutput.substring(Math.max(fullReadOutput.length - 15, 0)).contains("OK", true)) {
if (stringData.trim().isNotEmpty() && fullReadOutput.substring(Math.max(fullReadOutput.length - 15, 0)).contains("OK [0]", true)) {
Log.d(TAG, "onUsbRead() called in sendCmdToFetchLightIntensities()")
viewModel.mapIntensityValues(fullReadOutput.toString(), false)
// viewModel.saveLogTest(requireContext().applicationContext, false, fullReadOutput.toString())
// showResultsAfterAcquiring()
Handler(Looper.getMainLooper()).postDelayed(
{
checkIfToRunAgain()
@@ -208,15 +185,11 @@ class TestRightExpSample : Fragment() {
viewModel.mapWavelengthToAbsorbance()
// Todo: Save CSV + Test CSV
if (DataHolder.selectedTestType == TestType.SICKLECERT) {
viewModel.calculateResults()
} else {
viewModel.calculateResultsForSickleFind()
}
// Todo: Save Log
saveDataLocally()
if (viewModel.numberOfSampleRun < Constants.NO_OF_TIMES_TO_RUN_SAMPLE) {
@@ -233,33 +206,13 @@ class TestRightExpSample : Fragment() {
}
private fun showResultsAfterAcquiring() {
// viewModel.mapWavelengthToAbsorbance()
// viewModel.calculateResults()
viewModel.progressBar.postValue(false)
// binding.progressBar.visibility = View.GONE
parentFragmentManager.beginTransaction().replace(R.id.fl_main, TestRightResults())
.commit()
}
private fun saveDataLocally() {
// OLD ------------------------------
// val patientName = viewModel.testDetails?.patientName
// if (patientName.length > 5){
// patientName = patientName.substring(0, 5)
// }
// val id = PreferenceUtility.generateId(requireContext())
// val prefixCsv: String = if (DataHolder.selectedTestType == TestType.SICKLECERT)
// "HPOSSC_${DataHolder.deviceSerialNumber}_${patientName}_"
// else
// "HPOSSF_${DataHolder.deviceSerialNumber}_${patientName}_"
// val fileNameCsv = prefixCsv + id + fileExtensionCsv
// NEW ------------------------------
viewModel.saveCsv(requireContext().applicationContext, viewModel.getCSVFileName())
// viewModel.saveCsvForTesting(requireContext().applicationContext, viewModel.getDetailedCSVFileName())
viewModel.saveLogWithPatient(requireContext().applicationContext, viewModel.getLogFileName())
}

View File

@@ -16,9 +16,17 @@ import com.example.hpostesting.data.model.test.TestRightResultType
import com.example.hpostesting.data.model.test.TestType
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.example.hpostesting.util.MyUtils.calculateAgeFromYOB
import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.firestore.ktx.firestore
import com.google.firebase.ktx.Firebase
import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentTestRightResultsBinding
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.tasks.await
import kotlinx.coroutines.withContext
@AndroidEntryPoint
class TestRightResults : Fragment() {
@@ -30,7 +38,6 @@ class TestRightResults : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
// Inflate the layout for this fragment
binding = FragmentTestRightResultsBinding.inflate(inflater, container, false)
sharedPreference =
requireContext().getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE)
@@ -55,8 +62,9 @@ class TestRightResults : Fragment() {
private fun setupListeners() {
binding.ivHome.setOnClickListener {
val i = Intent(requireContext().applicationContext, DashboardActivity::class.java)
startActivity(i)
CoroutineScope(Dispatchers.IO).launch {
checkBloodGroup()
}
}
binding.ivNext.setOnClickListener {
val i = Intent(requireContext().applicationContext, DashboardActivity::class.java)
@@ -65,6 +73,31 @@ class TestRightResults : Fragment() {
}
}
private suspend fun checkBloodGroup() {
binding.apply {
val bloodGroup = etBloodGroup.text.toString()
if (bloodGroup.isEmpty()) {
etBloodGroup.error = "Please enter your blood group"
} else {
val db: FirebaseFirestore = Firebase.firestore
val userdata =
db.collection("patientData").whereEqualTo("_id", viewModel.testDetails?._id)
.get().await()
if (userdata.documents.isNotEmpty()) {
db.collection("patientData").document(userdata.documents[0].id)
.update("bloodGroup", bloodGroup)
withContext(Dispatchers.Main) {
val i = Intent(
requireContext().applicationContext,
DashboardActivity::class.java
)
startActivity(i)
}
}
}
}
}
private fun updateResults() {
if (viewModel.testDetails?.name == "" && viewModel.testDetails?.birthYear == "") {
binding.tvName.visibility = View.GONE
@@ -81,37 +114,7 @@ class TestRightResults : Fragment() {
if (DataHolder.selectedTestType == TestType.SICKLECERT) {
when (viewModel.testDetails?.result) {
TestRightResultType.NORMAL -> {
binding.resultNormal.visibility = View.VISIBLE
}
TestRightResultType.SICKLECELLDISEASE -> {
binding.resultDisease.visibility = View.VISIBLE
}
TestRightResultType.SICKLECELLTRAIT -> {
binding.resultTrait.visibility = View.VISIBLE
}
TestRightResultType.POSITIVEBORDERLINE -> {
binding.resultPositiveBorderline.visibility = View.VISIBLE
binding.tvRecommended.visibility = View.VISIBLE
}
TestRightResultType.NEGATIVEBORDERLINE -> {
binding.resultNegativeBorderline.visibility = View.VISIBLE
binding.tvRecommended.visibility = View.VISIBLE
}
else -> {
// binding.resultUndefined.visibility = View.VISIBLE
Toast.makeText(
requireContext().applicationContext, "Please Test Again", Toast.LENGTH_LONG
).show()
moveToSamplePage()
}
}
} else {
when (viewModel.testDetails?.result) {
TestRightResultType.SICKLECELLDISEASE -> {
@@ -160,6 +163,4 @@ class TestRightResults : Fragment() {
.commit()
}
}
}

View File

@@ -64,8 +64,6 @@ class TestRightViewModel @Inject constructor(
val allUserData = userDao.getAll()
private lateinit var calculationData: TestRightCalculationData
/* (For exp sample) Contains pixel no. -> Intensity of light falling on that pixel */
val intensitySampleArray = ArrayList<Double>()
val wavelengthToAbsorbance = ArrayList<ArrayList<Double>>()
@@ -73,8 +71,6 @@ class TestRightViewModel @Inject constructor(
val calculationVariableList = ArrayList<CalculationVariableForTest>()
fun mapDeviceConstants(string: String) {
// Log.d(TAG, "mapDeviceConstants() called")
// Log.d(TAG, "mapDeviceConstants() value -> $string")
if (string.isNotEmpty()) {
val listOfStrings = string.split(",")
if (listOfStrings.size >= 4) {
@@ -137,7 +133,6 @@ class TestRightViewModel @Inject constructor(
if (isReference) DataHolder.intensityReferenceArray.clear()
else intensitySampleArray.clear()
Log.d("SURYAKUMAR", fullString)
val listOfString = fullString.split("\n")
for (line in listOfString) {
@@ -437,7 +432,6 @@ class TestRightViewModel @Inject constructor(
}
private fun addResultTestToDb() {
testDetails?.location = DataHolder.location
testDetails?.testTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
@@ -521,7 +515,6 @@ class TestRightViewModel @Inject constructor(
}
private fun bulkAddResultTestToDb(userData: UserData) {
userData.location = DataHolder.location
viewModelScope.launch {
userData.reportUploadTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
@@ -539,6 +532,4 @@ class TestRightViewModel @Inject constructor(
fun deleteById(userId: String) = viewModelScope.launch {
userDao.deleteById(id = userId)
}
}

View File

@@ -7,46 +7,40 @@ import android.os.Binder
import android.os.IBinder
import android.util.Log
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.constant.TestRightCommands
import com.example.hpostesting.presentation.UsbServiceListener
import com.hoho.android.usbserial.driver.UsbSerialDriver
import com.hoho.android.usbserial.driver.UsbSerialPort
import com.hoho.android.usbserial.util.SerialInputOutputManager
import java.io.IOException
class UsbService : Service() {
// Binder to be given to clients
private val binder = UsbServiceBinder()
private lateinit var mPort: UsbSerialPort
private var isUsbConnected = false
private val TAG = "UsbService"
inner class UsbServiceBinder : Binder() {
// Return this instance of UsbService so clients can call public methods
fun getService(): UsbService = this@UsbService
}
override fun onBind(intent: Intent): IBinder {
Log.d("surya", "onBind() called")
return binder
}
var listener: UsbServiceListener? = null
var bus: UsbServiceListener? = null
fun connect(driver: UsbSerialDriver, connection: UsbDeviceConnection) {
// Todo: Uncomment this
mPort = driver.ports[0] // Most devices have just one port (port 0)
mPort.open(connection)
mPort.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE)
//
isUsbConnected = true
Log.d(TAG, "My Usb Connected ${mPort.driver}")
val usbIoManager = SerialInputOutputManager(mPort,
object : SerialInputOutputManager.Listener{
override fun onNewData(data: ByteArray?) {
// Log.e(TAG, "onNewData() called inside eventDrivenWrite()")
listener?.onUsbRead(data)
}
override fun onRunError(e: Exception?) {
@@ -57,7 +51,6 @@ class UsbService : Service() {
})
usbIoManager.start();
}
fun disconnect() {
if(isUsbConnected){
mPort.close()
@@ -65,45 +58,6 @@ class UsbService : Service() {
Log.d(TAG, "My Usb disconnected:: ${mPort.driver}")
}
}
// Todo: comment this
// fun eventDrivenWrite(command: TestRightCommands, listener: UsbServiceListener) {
// this.listener = listener
// try {
// when (command) {
// TestRightCommands.autoset -> {
// this.listener!!.onUsbRead("OK".toByteArray())
// }
// TestRightCommands.led2Set50 -> {
// this.listener!!.onUsbRead("OK".toByteArray())
// }
// TestRightCommands.run -> {
// this.listener!!.onUsbRead("OK [0]".toByteArray())
// }
// TestRightCommands.read -> {
// this.listener!!.onUsbRead(InputData().inputRead.toByteArray())
// }
// TestRightCommands.printAll -> {
// if (DataHolder.testExp) {
// for (each in InputData().printForReference.lines()) {
// this.listener!!.onUsbRead((each + "\n").toByteArray())
// }
// } else {
// for (each in InputData().printForSample.lines()) {
// this.listener!!.onUsbRead((each + "\n").toByteArray())
// }
// }
// }
// else -> {
// this.listener!!.onUsbRead("OK".toByteArray())
// }
// }
// } catch (e: IOException) {
// listener.onUsbError(e)
// }
// }
// Todo: Uncomment this
fun eventDrivenWrite(command: TestRightCommands, listener: UsbServiceListener) {
this.listener = listener
try {
@@ -113,19 +67,21 @@ class UsbService : Service() {
}
}
// fun write(command: TestRightCommands){
// mPort.write(command.command.toByteArray(), Constants.WRITE_TIMEOUT_MILLIS)
// }
// fun read(){
// val byteArray = ByteArray(3700)
// val len = mPort.read(byteArray, Constants.READ_TIMEOUT_MILLIS)
//
// Log.d(TAG, "length is $len")
// val byteArrayCropped = ByteArray(len)
// System.arraycopy(byteArray, 0, byteArrayCropped, 0, len)
//
// listener?.onUsbRead(byteArrayCropped)
// }
fun listenToHemoCube(listener: UsbServiceListener) {
this.listener = listener
try {
} catch (e: IOException) {
listener.onUsbError(e)
}
}
fun sendAndListenToHemoCube(command: HemoCubeCommands, listener: UsbServiceListener) {
try {
this.bus = listener
mPort.write(command.command.toByteArray(), Constants.WRITE_TIMEOUT_MILLIS)
} catch (e: IOException) {
listener.onUsbError(e)
}
}
}

View File

@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.hpostesting.presentation.BloodCollectingMethodActivity">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:theme="@style/Theme.HPOS.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/Theme.HPOS.PopupOverlay" />
</com.google.android.material.appbar.AppBarLayout>
<TextView
android:id="@+id/tv_title"
style="@style/title1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:text="@string/select_blood_collecting_method"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/app_bar_layout" />
<RadioGroup
android:id="@+id/bloodTypeRadioGroup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_title">
<RadioButton
android:id="@+id/venousBloodRadioButton"
style="@style/title1_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/venous_blood" />
<RadioButton
android:id="@+id/fingerPrickBloodRadioButton"
style="@style/title1_1"
android:checked="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/finger_prick_blood" />
</RadioGroup>
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_go"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="24dp"
android:text="@string/go"
app:cornerRadius="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/bloodTypeRadioGroup" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

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

View File

@@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".presentation.KitScanActivity">
tools:context="com.example.hpostesting.presentation.KitScanActivity">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar_layout"

View File

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

View File

@@ -5,6 +5,19 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/pendingTest"
style="@style/title1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:visibility="gone"
android:text="@string/all_registered_user_are_tested_successfully"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/internetNotAvailableCL"
android:layout_width="match_parent"
@@ -57,7 +70,6 @@
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/internetAvailableCL"
android:layout_width="match_parent"

View File

@@ -117,7 +117,7 @@
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:background="@drawable/result_background_green"
android:text="@string/normal"
android:text="@string/test_completed"
android:textAlignment="center"
android:visibility="gone"
app:drawableStartCompat="@drawable/ic_baseline_check_circle_24"
@@ -241,6 +241,28 @@
<!-- app:layout_constraintStart_toStartOf="@id/iv_download"-->
<!-- app:layout_constraintTop_toBottomOf="@id/iv_download" />-->
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/til_blood_group"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cv_sample_details">
<AutoCompleteTextView
android:id="@+id/et_blood_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/select_blood_group"
android:inputType="none"
android:labelFor="@id/til_blood_group"
app:simpleItems="@array/blood_group" />
</com.google.android.material.textfield.TextInputLayout>
<ImageView
android:id="@+id/iv_home"
android:layout_width="wrap_content"
@@ -250,7 +272,7 @@
android:src="@drawable/ic_baseline_home_24"
app:layout_constraintEnd_toStartOf="@id/iv_next"
app:layout_constraintStart_toStartOf="@id/cv_sample_details"
app:layout_constraintTop_toBottomOf="@id/cv_sample_details" />
app:layout_constraintTop_toBottomOf="@id/til_blood_group" />
<TextView
style="@style/title2"
@@ -274,7 +296,7 @@
android:src="@drawable/ic_baseline_new_label_24"
app:layout_constraintEnd_toEndOf="@id/cv_sample_details"
app:layout_constraintStart_toEndOf="@id/iv_home"
app:layout_constraintTop_toBottomOf="@id/cv_sample_details" />
app:layout_constraintTop_toBottomOf="@id/til_blood_group" />
<TextView
style="@style/title2"

View File

@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
android:layout_height="wrap_content">
<androidx.cardview.widget.CardView
android:id="@+id/userCard"
@@ -24,48 +24,53 @@
android:id="@+id/userImage"
android:layout_width="100dp"
android:layout_height="100dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/ic_launcher_foreground" />
<TextView
android:id="@+id/userName"
style="@style/title1_1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_bold"
android:layout_marginTop="16dp"
android:gravity="center"
android:layout_marginStart="16dp"
android:gravity="start"
android:textColor="@color/black"
android:textSize="16sp"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/userImage" />
app:layout_constraintStart_toEndOf="@+id/userImage"
app:layout_constraintTop_toTopOf="@+id/userImage"
tools:text="Name: MohamedKaif" />
<TextView
android:id="@+id/userId"
style="@style/title1_1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_bold"
android:layout_marginTop="16dp"
android:gravity="center"
android:layout_marginStart="16dp"
android:layout_marginTop="4dp"
android:gravity="start"
android:textColor="@color/black"
android:textSize="16sp"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/userName" />
app:layout_constraintStart_toEndOf="@+id/userImage"
app:layout_constraintTop_toBottomOf="@id/userName"
tools:text="UserID: MohamedKaif" />
<TextView
android:id="@+id/teststatus"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_bold"
android:layout_marginTop="16dp"
android:gravity="center"
style="@style/title1_1"
android:layout_marginTop="4dp"
android:layout_marginStart="16dp"
android:gravity="start"
android:textColor="@color/black"
android:textSize="16sp"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/userId" />
app:layout_constraintStart_toEndOf="@+id/userImage"
app:layout_constraintTop_toBottomOf="@id/userId"
tools:text="Test Status: Completed"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -47,4 +47,5 @@
app:popUpTo="@id/mobile_navigation"
app:popUpToInclusive="true"/>
</fragment>
</navigation>

View File

@@ -1,5 +1,5 @@
<resources>
<string name="app_name">HPOS</string>
<string name="app_name">HPOS Testing</string>
<string-array name="instrument">
<item>TestRight</item>
@@ -44,6 +44,8 @@
<string name="please_place">Please place the cuvette containing sample for reference before running</string>
<string name="yes">Yes</string>
<string name="no">No</string>
<string name="noo"></string>
<string name="connect">Connect</string>
<string name="connected">Connected</string>
@@ -110,6 +112,8 @@
<string name="sickle_cert">Sickle Cert</string>
<string name="sickle_find">Sickle Find</string>
<string name="submit">Submit</string>
<string name="new_kit">New Kit</string>
<string name="new_buffer">New Buffer</string>
<string name="name_error_2">Invalid character, Allowed characters are Letters, Numbers and ( ) _ - , . only</string>
<string name="recommended">\*Result to be confirmed with laboratory test</string>
<string name="recommended_age">\*Result to be confirmed with laboratory test as age of the patient is less than 5 years</string>
@@ -130,7 +134,7 @@
<string name="scan_now">Scan Now</string>
<string name="enter_abha_number_manualy">Enter ABHA number manualy</string>
<string name="abha_id">ABHA ID</string>
<string name="patient_id_in_tv"><b>Patient ID</b> : %1$s</string>
<string name="patient_id_in_tv"><b>User ID</b> : %1$s</string>
<string name="go">GO</string>
<string name="click_here">Click Here</string>
<string name="title_activity_dashboard">DashboardActivity</string>
@@ -142,6 +146,7 @@
<string name="action_settings">Settings</string>
<string name="menu_home">Home</string>
<string name="show_hemocube_result">Show Result</string>
<string name="menu_gallery">Gallery</string>
<string name="menu_settings">Settings</string>
<string name="profile">Profile</string>
@@ -182,5 +187,11 @@
<string name="upload">Upload</string>
<string name="cancel">Cancel</string>
<string name="upload_success_message">Upload done successfully</string>
<string name="test_completed">Test Completed</string>
<string name="select_blood_group">Select Blood Group</string>
<string name="all_registered_user_are_tested_successfully">All registered user are tested successfully</string>
<string name="venous_blood">Venous Blood</string>
<string name="finger_prick_blood">Finger Prick Blood</string>
<string name="select_blood_collecting_method">Select blood collecting method</string>
</resources>

View File

@@ -10,6 +10,7 @@
<!-- <usb-device vendor-id="1027" product-id="24593" /> &lt;!&ndash; 0x6011: FT4232H &ndash;&gt;-->
<!-- <usb-device vendor-id="1027" product-id="24596" /> &lt;!&ndash; 0x6014: FT232H &ndash;&gt;-->
<usb-device vendor-id="1027" product-id="24597" /> <!-- 0x6015: FT230X, FT231X, FT234XD -->
<usb-device vendor-id="6790" product-id="29987" /> <!-- 0x6015: FT230X, FT231X, FT234XD -->
<!-- 0x10C4 / 0xEA??: Silabs CP210x -->
<!-- <usb-device vendor-id="4292" product-id="60000" /> &lt;!&ndash; 0xea60: CP2102 and other CP210x single port devices &ndash;&gt;-->

View File

@@ -19,6 +19,7 @@ plugins {
id 'androidx.navigation.safeargs' version '2.7.0-beta01' apply false
id 'com.google.dagger.hilt.android' version '2.46' apply false
id "com.google.gms.google-services" version "4.3.15" apply false
id 'com.google.firebase.crashlytics' version "2.9.8" apply false
}
task clean(type: Delete) {