Compare commits

..

2 Commits

Author SHA1 Message Date
Mariya
da9a2296d6 Apk url for app update 2024-01-23 14:42:26 +05:30
Mariya
30fde87f95 Added version in login request 2024-01-22 13:12:06 +05:30
125 changed files with 791 additions and 11228 deletions

View File

@@ -1,101 +0,0 @@
# This file is a template, and might need editing before it works on your project.
# To contribute improvements to CI/CD templates, please follow the Development guide at:
# https://docs.gitlab.com/ee/development/cicd/templates.html
# This specific template is located at:
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Android.gitlab-ci.yml
# Read more about this script on this blog post https://about.gitlab.com/2018/10/24/setting-up-gitlab-ci-for-android-projects/, by Jason Lenny
# If you are interested in using Android with FastLane for publishing take a look at the Android-Fastlane template.
image: eclipse-temurin:17-jdk-jammy
variables:
# ANDROID_COMPILE_SDK is the version of Android you're compiling with.
# It should match compileSdkVersion.
ANDROID_COMPILE_SDK: "34"
# ANDROID_BUILD_TOOLS is the version of the Android build tools you are using.
# It should match buildToolsVersion.
ANDROID_BUILD_TOOLS: "33.0.2"
# It's what version of the command line tools we're going to download from the official site.
# Official Site-> https://developer.android.com/studio/index.html
# There, look down below at the cli tools only, sdk tools package is of format:
# commandlinetools-os_type-ANDROID_SDK_TOOLS_latest.zip
# when the script was last modified for latest compileSdkVersion, it was which is written down below
ANDROID_SDK_TOOLS: "9477386"
# Packages installation before running script
before_script:
- apt-get --quiet update --yes
- apt-get --quiet install --yes wget unzip
# Setup path as android_home for moving/exporting the downloaded sdk into it
- export ANDROID_HOME="${PWD}/android-sdk-root"
# Create a new directory at specified location
- install -d $ANDROID_HOME
# Here we are installing androidSDK tools from official source,
# (the key thing here is the url from where you are downloading these sdk tool for command line, so please do note this url pattern there and here as well)
# after that unzipping those tools and
# then running a series of SDK manager commands to install necessary android SDK packages that'll allow the app to build
- wget --no-verbose --output-document=$ANDROID_HOME/cmdline-tools.zip https://dl.google.com/android/repository/commandlinetools-linux-${ANDROID_SDK_TOOLS}_latest.zip
- unzip -q -d "$ANDROID_HOME/cmdline-tools" "$ANDROID_HOME/cmdline-tools.zip"
- mv -T "$ANDROID_HOME/cmdline-tools/cmdline-tools" "$ANDROID_HOME/cmdline-tools/tools"
- export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/cmdline-tools/tools/bin
# Nothing fancy here, just checking sdkManager version
- sdkmanager --version
# use yes to accept all licenses
- yes | sdkmanager --licenses > /dev/null || true
- sdkmanager "platforms;android-${ANDROID_COMPILE_SDK}"
- sdkmanager "platform-tools"
- sdkmanager "build-tools;${ANDROID_BUILD_TOOLS}"
# Not necessary, but just for surity
- chmod +x ./gradlew
# Basic android and gradle stuff
# Check linting
lintDebug:
interruptible: true
stage: build
script:
- ./gradlew -Pci --console=plain :app:lintDebug -PbuildDir=lint
artifacts:
paths:
- app/lint/reports/lint-results-debug.html
expose_as: "lint-report"
when: always
# Make Project
assembleDebug:
interruptible: true
stage: build
script:
- ./gradlew assembleDebug
artifacts:
paths:
- app/build/outputs/
# Run all tests, if any fails, interrupt the pipeline(fail it)
debugTests:
needs: [lintDebug, assembleDebug]
interruptible: true
stage: test
script:
- ./gradlew -Pci --console=plain :app:testDebug
artifacts:
paths:
- app/build/test-results/
publishTestResults:
stage: test
script:
- echo "Publishing JUnit test results"
needs: [debugTests]
artifacts:
when: always
reports:
junit: app/build/test-results/testDebugUnitTest/*.xml

View File

@@ -14,18 +14,17 @@ android {
compileSdk 34 compileSdk 34
namespace 'in.sminnovations.hpostesting' namespace 'in.sminnovations.hpostesting'
// prod - production, preprod - preproduction, quality - qc, dev - development // prod - production, preprod - preproduction, quality - qc
defaultConfig { defaultConfig {
applicationId "in.sminnovations.hpostesting.quality" applicationId "in.sminnovations.hpostesting"
minSdk 21 minSdk 21
targetSdk 34 targetSdk 34
versionCode 99 versionCode 26
versionName "2.1.99" versionName "2.1.26"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }
buildTypes { buildTypes {
release { release {
minifyEnabled false minifyEnabled false
@@ -53,11 +52,6 @@ android {
packagingOptions { packagingOptions {
exclude 'mockito-extensions/org.mockito.plugins.MockMaker' exclude 'mockito-extensions/org.mockito.plugins.MockMaker'
} }
// testOptions {
// unitTests {
// includeAndroidResources = true
// }
// }
} }
dependencies { dependencies {
@@ -68,7 +62,7 @@ dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.11.0' implementation 'com.google.android.material:material:1.11.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.7.0' implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.2'
implementation 'androidx.fragment:fragment-ktx:1.6.2' implementation 'androidx.fragment:fragment-ktx:1.6.2'
//firebase //firebase
@@ -81,7 +75,7 @@ dependencies {
implementation 'com.google.firebase:firebase-storage-ktx' implementation 'com.google.firebase:firebase-storage-ktx'
implementation 'com.firebaseui:firebase-ui-firestore:8.0.2' implementation 'com.firebaseui:firebase-ui-firestore:8.0.2'
implementation 'com.google.android.gms:play-services-auth:20.7.0' implementation 'com.google.android.gms:play-services-auth:20.7.0'
implementation 'com.google.android.gms:play-services-location:21.1.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.gms:play-services-ads-identifier:18.0.1'
implementation 'com.google.android.things:androidthings:1.0' implementation 'com.google.android.things:androidthings:1.0'
implementation 'com.google.firebase:firebase-appdistribution:16.0.0-beta11' implementation 'com.google.firebase:firebase-appdistribution:16.0.0-beta11'
@@ -96,41 +90,28 @@ dependencies {
// Testing // Testing
testImplementation 'junit:junit:4.13.2' testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test:rules:1.0.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
testImplementation "androidx.work:work-testing:2.9.0"
androidTestImplementation 'androidx.test:core-ktx:1.5.0'
testImplementation 'androidx.fragment:fragment-testing:1.6.2'
testImplementation "org.robolectric:robolectric:4.7"
// mockk
testImplementation 'io.mockk:mockk:1.10.6'
// Mockito dependencies // Mockito dependencies
testImplementation 'org.mockito:mockito-core:3.12.4' testImplementation 'org.mockito:mockito-core:3.12.4'
androidTestImplementation 'org.mockito:mockito-android:3.12.4' androidTestImplementation 'org.mockito:mockito-android:3.12.4'
androidTestImplementation 'org.mockito:mockito-inline:3.12.4' androidTestImplementation 'org.mockito:mockito-inline:3.12.4'
androidTestImplementation 'org.mockito:mockito-android:3.12.4'
testImplementation 'org.powermock:powermock-api-mockito2:2.0.9'
testImplementation 'org.powermock:powermock-module-junit4:2.0.9'
testImplementation "androidx.arch.core:core-testing:2.2.0" testImplementation "androidx.arch.core:core-testing:2.2.0"
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.1' testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.1'
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0"
implementation 'com.opencsv:opencsv:5.9' implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2"
implementation 'com.opencsv:opencsv:5.5'
implementation 'com.github.mik3y:usb-serial-for-android:3.5.1' implementation 'com.github.mik3y:usb-serial-for-android:3.5.1'
implementation "androidx.fragment:fragment-ktx:1.6.2" implementation "androidx.fragment:fragment-ktx:1.6.2"
// CSV read, write // CSV read, write
implementation 'com.opencsv:opencsv:5.9' implementation 'com.opencsv:opencsv:5.5'
// Barcode scanner // Barcode scanner
implementation 'com.journeyapps:zxing-android-embedded:4.3.0' implementation 'com.journeyapps:zxing-android-embedded:4.3.0'
// Google ML Kit using play services // Google ML Kit usign play services
implementation 'com.google.android.gms:play-services-code-scanner:16.1.0' implementation 'com.google.android.gms:play-services-code-scanner:16.1.0'
//Room //Room
@@ -157,14 +138,7 @@ dependencies {
implementation("com.squareup.okhttp3:okhttp:4.9.3") implementation("com.squareup.okhttp3:okhttp:4.9.3")
implementation "androidx.preference:preference-ktx:1.2.1" implementation "androidx.preference:preference-ktx:1.2.1"
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1' implementation 'io.nats:jnats:2.11.2'
implementation("androidx.work:work-runtime-ktx:2.9.0")
// implementation("io.nats:jnats:2.11.2")
implementation 'com.google.android.play:core:1.10.3' implementation 'com.google.android.play:core:1.10.3'
implementation fileTree(dir: 'libs', include: ['*.aar'])
implementation 'io.nats:jnats:2.11.4'
} }

View File

@@ -1,48 +0,0 @@
{
"project_info": {
"project_number": "1004619739289",
"project_id": "hpos-qa",
"storage_bucket": "hpos-qa.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:1004619739289:android:f669b47552748433e5c808",
"android_client_info": {
"package_name": "in.sminnovations.hposregistration.quality"
}
},
"oauth_client": [],
"api_key": [
{
"current_key": "AIzaSyC4d4GhWHr_NMJAeBvnztQ_yQ3Qe9MAnLs"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": []
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:1004619739289:android:8397cd1f0357bd89e5c808",
"android_client_info": {
"package_name": "in.sminnovations.hpostesting.quality"
}
},
"oauth_client": [],
"api_key": [
{
"current_key": "AIzaSyC4d4GhWHr_NMJAeBvnztQ_yQ3Qe9MAnLs"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": []
}
}
}
],
"configuration_version": "1"
}

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

Binary file not shown.

View File

@@ -4,15 +4,15 @@
"type": "APK", "type": "APK",
"kind": "Directory" "kind": "Directory"
}, },
"applicationId": "in.sminnovations.hpostesting.quality", "applicationId": "com.example.hpos",
"variantName": "release", "variantName": "release",
"elements": [ "elements": [
{ {
"type": "SINGLE", "type": "SINGLE",
"filters": [], "filters": [],
"attributes": [], "attributes": [],
"versionCode": 101, "versionCode": 1,
"versionName": "2.1.101", "versionName": "1.0",
"outputFile": "app-release.apk" "outputFile": "app-release.apk"
} }
], ],

View File

@@ -1,42 +0,0 @@
package com.example.hpostesting
import androidx.test.core.app.ActivityScenario
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.ext.junit.runners.AndroidJUnit4
//import com.example.hpostesting.R
import com.example.hpostesting.presentation.assurance.AssuranceControlsActivity
import `in`.sminnovations.hpostesting.databinding.ActivityAssuranceControlsBinding
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
@RunWith(AndroidJUnit4::class)
class AssuranceControlsActivityTest {
//
// @Test
// fun testViewBinding() {
// val activityScenario = ActivityScenario.launch(AssuranceControlsActivity::class.java)
// activityScenario.onActivity { activity ->
// assertNotNull(activity.binding)
// assertEquals(ActivityAssuranceControlsBinding::class.java, activity.binding.javaClass)
// }
// }
//
// @Test
// fun testSharedPreferencesInitialization() {
// val activityScenario = ActivityScenario.launch(AssuranceControlsActivity::class.java)
// activityScenario.onActivity { activity ->
// assertNotNull(activity.sharedPreference)
// assertEquals("HEMOCUBE", activity.sharedPreference.getString("HEMOCUBE", null))
// }
// }
// @Test
// fun testFragmentTransaction() {
// val activityScenario = ActivityScenario.launch(AssuranceControlsActivity::class.java)
// onView(withId(R.id.fgAssuranceControls)).check(matches(isDisplayed())) // Using Espresso for UI verification
// }
}

View File

@@ -17,6 +17,6 @@ class ExampleInstrumentedTest {
fun useAppContext() { fun useAppContext() {
// Context of the app under test. // Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext val appContext = InstrumentationRegistry.getInstrumentation().targetContext
// assertEquals("com.example.refactoredapp", appContext.packageName) assertEquals("com.example.refactoredapp", appContext.packageName)
} }
} }

View File

@@ -1,5 +0,0 @@
<vector android:height="24dp" android:tint="@color/primary"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@color/primary" android:pathData="M19,9h-4V3H9v6H5l7,7 7,-7zM5,18v2h14v-2H5z"/>
</vector>

View File

@@ -34,34 +34,12 @@
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.HPOSTesting" android:theme="@style/Theme.HPOSTesting"
tools:targetApi="31"> tools:targetApi="31">
<activity
android:name="com.example.hpostesting.presentation.deviceinfo.DeviceActivity"
android:exported="false" />
<activity <activity
android:name="com.example.hpostesting.presentation.hemocube.DigitalCardActivity" android:name="com.example.hpostesting.presentation.hemocube.DigitalCardActivity"
android:exported="false" /> android:exported="false" />
<activity <activity
android:name="com.example.hpostesting.presentation.diagnostics.DiagnosticsActivity" android:name="com.example.hpostesting.presentation.diagnostics.DiagnosticsActivity"
android:exported="false" android:exported="false" />
android:theme="@style/Theme.HPOS.NoActionBar" />
<activity
android:name="com.example.hpostesting.presentation.autodac.AutoDacActivity"
android:exported="false"
android:theme="@style/Theme.HPOS.NoActionBar" />
<activity
android:name="com.example.hpostesting.presentation.deviceprovision.DeviceProvisionActivity"
android:exported="false"
android:theme="@style/Theme.HPOS.NoActionBar" />
<activity
android:name="com.example.hpostesting.presentation.calibration.CalibrationActivity"
android:exported="false"
android:theme="@style/Theme.HPOS.NoActionBar"/>
<activity
android:name="com.example.hpostesting.presentation.assurance.AssuranceControlsActivity"
android:exported="false"
android:theme="@style/Theme.HPOS.NoActionBar"/>
<activity <activity
android:name="com.example.hpostesting.presentation.hemocube.HemocubeActivity" android:name="com.example.hpostesting.presentation.hemocube.HemocubeActivity"
android:exported="false" android:exported="false"
@@ -69,15 +47,6 @@
android:parentActivityName="com.example.hpostesting.presentation.MainActivity" android:parentActivityName="com.example.hpostesting.presentation.MainActivity"
android:theme="@style/Theme.HPOS.NoActionBar" android:theme="@style/Theme.HPOS.NoActionBar"
android:windowSoftInputMode="adjustPan" /> android:windowSoftInputMode="adjustPan" />
<activity
android:name="com.example.hpostesting.presentation.trueheme.TrueHemeActivity"
android:exported="false"
android:noHistory="true"
android:parentActivityName="com.example.hpostesting.presentation.MainActivity"
android:theme="@style/Theme.HPOS.NoActionBar"
android:windowSoftInputMode="adjustPan" />
<activity <activity
android:name="com.example.hpostesting.presentation.buffercheck.HemocubeBufferCheckActivity" android:name="com.example.hpostesting.presentation.buffercheck.HemocubeBufferCheckActivity"
android:exported="false" android:exported="false"
@@ -119,8 +88,7 @@
android:theme="@style/AppTheme.NoActionBar"> android:theme="@style/AppTheme.NoActionBar">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>

View File

@@ -1,50 +0,0 @@
package com.example.hpostesting.data
import android.content.Context
import android.os.Environment
import java.io.File
import java.io.FileWriter
import java.io.IOException
class CsvWriter(private val context: Context) {
fun writeCsv(fileName: String, data: List<Array<String>>): Boolean {
try {
val filePath = File(getExternalStorageDirectory(), fileName)
val writer = FileWriter(filePath)
// Write header row
val header = arrayOf(
"ID",
"Blood Group",
"Birth Year",
"Classification Result",
"Test Time",
"User Image URL",
"Name"
)
writer.write(header.joinToString(",") + "\n")
// Write data rows
for (line in data) {
writer.write(line.joinToString(",") + "\n")
}
writer.close()
return true
} catch (e: IOException) {
e.printStackTrace()
return false
}
}
private fun getExternalStorageDirectory(): File {
val folder = File(Environment.getExternalStorageDirectory(), "HposFolder")
if (!folder.exists()) {
folder.mkdirs()
}
return folder
}
}

View File

@@ -7,11 +7,8 @@ import com.example.hpostesting.data.model.updates.CheckUpdateRequest
import com.example.hpostesting.data.model.updates.CheckUpdateResponse import com.example.hpostesting.data.model.updates.CheckUpdateResponse
import com.example.hpostesting.data.model.updates.DeviceUpdateRequest import com.example.hpostesting.data.model.updates.DeviceUpdateRequest
import okhttp3.MultipartBody import okhttp3.MultipartBody
import okhttp3.Response
import okhttp3.ResponseBody import okhttp3.ResponseBody
import retrofit2.http.Body import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.Multipart import retrofit2.http.Multipart
import retrofit2.http.POST import retrofit2.http.POST
import retrofit2.http.PUT import retrofit2.http.PUT
@@ -34,10 +31,6 @@ interface MolbioResultApi {
@Body deviceUpdateRequest: DeviceUpdateRequest @Body deviceUpdateRequest: DeviceUpdateRequest
): ResponseBody ): ResponseBody
@GET("deviceService/device/getClientCertificate")
suspend fun downloadClientCertificate(
): ResponseBody
@Multipart @Multipart
@POST("deviceService/device/uploadLogs") @POST("deviceService/device/uploadLogs")
suspend fun uploadLogs( suspend fun uploadLogs(

View File

@@ -1,16 +1,9 @@
package com.example.hpostesting.data.constant package com.example.hpostesting.data.constant
enum class HemoCubeCommands(val command: String) { enum class HemoCubeCommands(val command: String) {
START_BUFFER_COMMAND("B\r"), startBuffer("B\r"),
AUTO_DAC_COMMAND("C\r"), runDiagnostics("D\r"),
DIAGNOSTICS_COMMAND("D\r"), startSample("S\r"),
FIRMWARE_INFO_COMMAND("F\r"), getSample("P\r"),
START_SAMPLE("S\r"), getDeviceId("I\r"),
PRINT_COMMAND("P\r"),
READ_DAC_COMMAND("R\r"),
DEVICE_CONFIGURATION_COMMAND("I\r"),
FIRST_GAIN_COMMAND("T\r"),
SECOND_GAIN_COMMAND("U\r"),
THIRD_GAIN_COMMAND("V\r"),
FORTH_GAIN_COMMAND("W\r"),
} }

View File

@@ -1,40 +0,0 @@
package com.example.hpostesting.data.constant
enum class TestStatus(val code: Double) {
TEST_STARTED(1.0),
CONFIG_STARTED(2.0),
CONFIG_COMPLETED(3.0),
FIRST_EMPTY_AIR_READING_STARTED(4.1),
FIRST_EMPTY_AIR_READING_COMPLETED(4.2),
FIRST_EMPTY_AIR_READING_PRINT_STARTED(4.3),
FIRST_EMPTY_AIR_READING_PRINT_COMPLETED(4.4),
BUFFER_STARTED(4.0),
BUFFER_COMPLETED(5.0),
BUFFER_PRINT_STARTED(6.0),
BUFFER_PRINT_COMPLETED(7.0),
SAMPLE_STARTED(8.0),
SAMPLE_COMPLETED(9.0),
SAMPLE_PRINT_STARTED(10.0),
SAMPLE_PRINT_COMPLETED(11.0),
SECOND_EMPTY_AIR_READING_STARTED(11.1),
SECOND_EMPTY_AIR_READING_COMPLETED(11.2),
SECOND_EMPTY_AIR_PRINT_STARTED(11.3),
SECOND_EMPTY_AIR_PRINT_COMPLETED(11.4),
FIRST_GAIN_STARTED(12.0),
FIRST_GAIN_COMPLETED(13.0),
FIRST_GAIN_PRINT_STARTED(14.0),
FIRST_GAIN_PRINT_COMPLETED(15.0),
SECOND_GAIN_STARTED(16.0),
SECOND_GAIN_COMPLETED(17.0),
SECOND_GAIN_PRINT_STARTED(18.0),
SECOND_GAIN_PRINT_COMPLETED(19.0),
THIRD_GAIN_STARTED(20.0),
THIRD_GAIN_COMPLETED(21.0),
THIRD_GAIN_PRINT_STARTED(22.0),
THIRD_GAIN_PRINT_COMPLETED(23.0),
FORTH_GAIN_STARTED(24.0),
FORTH_GAIN_COMPLETED(25.0),
FORTH_GAIN_PRINT_STARTED(26.0),
FORTH_GAIN_PRINT_COMPLETED(27.0),
TEST_COMPLETED(30.0)
}

View File

@@ -1,26 +0,0 @@
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.BufferCheckData
@Dao
interface HemoCubeBufferDao {
@Query("SELECT * from hemo_cube_buffer_test_table")
fun getAll(): LiveData<List<BufferCheckData>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAll(bufferCheckData: BufferCheckData)
@Query("SELECT * FROM hemo_cube_buffer_test_table WHERE _id = :id")
suspend fun getUserByID(id: String): BufferCheckData
@Query("DELETE FROM hemo_cube_buffer_test_table WHERE _id = :id")
suspend fun deleteById(id: String)
@Query("UPDATE hemo_cube_buffer_test_table SET localFlag = :newValue WHERE _id = :id")
suspend fun updateFieldById(id: String, newValue: Boolean)
}

View File

@@ -23,10 +23,4 @@ interface HemoCubeDao {
@Query("UPDATE hemo_cube_test_table SET localFlag = :newValue WHERE _id = :id") @Query("UPDATE hemo_cube_test_table SET localFlag = :newValue WHERE _id = :id")
suspend fun updateFieldById(id: String, newValue: Boolean) suspend fun updateFieldById(id: String, newValue: Boolean)
@Query("UPDATE hemo_cube_test_table SET molbioFlag = :newValue WHERE _id = :id")
suspend fun updateMolbioFlag(id: String, newValue: Boolean)
@Query("UPDATE hemo_cube_test_table SET isCSVCreated = :newValue WHERE _id = :id")
suspend fun updateCSVFieldById(id: String, newValue: Boolean)
} }

View File

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

View File

@@ -1,19 +1,23 @@
package com.example.hpostesting.data.datasource package com.example.hpostesting.data.datasource
import android.os.Environment
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.opencsv.CSVWriter import com.opencsv.CSVWriter
import java.io.File import java.io.File
import java.io.FileWriter import java.io.FileWriter
import java.io.IOException
interface LocalFileDataSource { class LocalFileDataSource {
fun saveCsvToDisk(filepath: String, contents: ArrayList<Array<String>>) fun saveCsvToDisk(filepath: String, contents: ArrayList<Array<String>>){
val writer = CSVWriter(FileWriter(filepath))
writer.writeAll(contents) // data is adding to csv
writer.close()
}
fun saveTextToDisk(filepath: String, contents: String) fun saveTextToDisk(filepath: String, contents: String){
val writer = FileWriter(File(filepath))
writer.append(contents)
writer.flush()
writer.close()
}
fun exportDataToCSV(
fileName: String, dataList: List<HemoCubeTestData>
): Boolean
} }

View File

@@ -1,161 +0,0 @@
package com.example.hpostesting.data.datasource
import android.os.Environment
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.opencsv.CSVWriter
import java.io.File
import java.io.FileWriter
import java.io.IOException
import javax.inject.Inject
class LocalFileDataSourceImpl @Inject constructor(): LocalFileDataSource {
override fun saveCsvToDisk(filepath: String, contents: ArrayList<Array<String>>) {
val writer = CSVWriter(FileWriter(filepath))
writer.writeAll(contents) // data is adding to csv
writer.close()
}
override fun saveTextToDisk(filepath: String, contents: String) {
val writer = FileWriter(File(filepath))
writer.append(contents)
writer.flush()
writer.close()
}
override fun exportDataToCSV(
fileName: String, dataList: List<HemoCubeTestData>
): Boolean {
try {
val formattedFileName = fileName.replace(Regex("[^a-zA-Z0-9.-]"), "_") // Replace special characters with underscores
val filePath = File(getExternalStorageDirectory(), formattedFileName)
val writer = FileWriter(filePath)
val csvWriter = CSVWriter(writer)
// Write CSV header
val header = arrayOf(
"_id",
"name",
"incubationTime",
"bloodGroup",
"birthYear", // Include other fields from the data class
"state",
"abhaId",
"userImageURL",
"location",
"reportUploadTime",
"testType",
"testTime",
"testStatus",
"gender",
"localFlag", // Add more fields as necessary
"deviceId",
"appVersion",
"deviceSerialNumber",
"deviceType",
"kitSerial",
"resultData",
"led1Buffer",
"led2Buffer",
"led3Buffer",
"led4Buffer",
"led1Sample",
"led2Sample",
"led3Sample",
"led4Sample",
"led1Average",
"led2Average",
"led3Average",
"led4Average",
"abs1",
"abs2",
"abs3",
"abs4",
"deviceRatio",
"calculatedRatio",
"predictedDenovixRatio",
"coefficients",
"classificationResult",
"prdClassification",
"errorMessages",
"batteryLevel",
"batteryCapacity",
"batteryMaxCapacity",
"batteryTemperature",
"batteryVoltage"
)
csvWriter.writeNext(header)
// Write data rows
for (data in dataList) {
val row = arrayOf(
data._id,
data.name,
data.incubationTime,
data.bloodGroup,
data.birthYear, // Include other fields similarly
data.state,
data.abhaId,
data.userImageURL,
data.location?.toString(),
data.reportUploadTime ?: "",
data.testType ?: "",
data.testTime ?: "",
data.testStatus?.toString() ?: "",
data.gender,
data.localFlag.toString(),
data.deviceId ?: "",
data.appVersion ?: "",
data.deviceSerialNumber,
data.deviceType,
data.kitSerial,
data.resultData,
data.led1Buffer?.toString() ?: "",
data.led2Buffer?.toString() ?: "",
data.led3Buffer?.toString() ?: "",
data.led4Buffer?.toString() ?: "",
data.led1Sample?.toString() ?: "",
data.led2Sample?.toString() ?: "",
data.led3Sample?.toString() ?: "",
data.led4Sample?.toString() ?: "",
data.led1Average?.toString() ?: "",
data.led2Average?.toString() ?: "",
data.led3Average?.toString() ?: "",
data.led4Average?.toString() ?: "",
data.abs1?.toString() ?: "",
data.abs2?.toString() ?: "",
data.abs3?.toString() ?: "",
data.abs4?.toString() ?: "",
data.deviceRatio?.toString() ?: "",
data.calculatedRatio?.toString() ?: "",
data.predictedDenovixRatio?.toString() ?: "",
data.coefficients ?: "",
data.classificationResult,
data.prdClassification,
data.errorMessages,
data.batteryLevel,
data.batteryCapacity,
data.batteryMaxCapacity,
data.batteryTemperature,
data.batteryVoltage
)
csvWriter.writeNext(row)
}
writer.close()
return true
} catch (e: IOException) {
e.printStackTrace()
return false
}
}
private fun getExternalStorageDirectory(): File {
val folder = File(Environment.getExternalStorageDirectory(), "HposFolder")
if (!folder.exists()) {
folder.mkdirs()
}
return folder
}
}

View File

@@ -1,44 +0,0 @@
package com.example.hpostesting.data.model
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.HemoCubeTestData
data class TestState (
var testDetails: HemoCubeTestData? = null,
var isOnline: Boolean = false,
var currentDeviceData: DeviceData? = null,
var resultData: String = "",
var currentResultData: String = "",
var isUsingExistingBuffer: Boolean = false,
var isTestOngoing: Boolean = false,
var led1BufferForDevice: Double = 0.0,
var led2BufferForDevice: Double = 0.0,
var led3BufferForDevice: Double = 0.0,
var led4BufferForDevice: Double = 0.0,
var led1SampleForDevice: Double = 0.0,
var led2SampleForDevice: Double = 0.0,
var led3SampleForDevice: Double = 0.0,
var led4SampleForDevice: Double = 0.0,
var fittedAbs1: Double = 0.0,
var fittedAbs2: Double = 0.0,
var fittedAbs3: Double = 0.0,
var fittedAbs4: Double = 0.0,
// var led1Air1: Double? = null,
// var led2Air1: Double? = null,
// var led3Air1: Double? = null,
// var led4Air1: Double? = null,
// var led1Air2: Double? = null,
// var led2Air2: Double? = null,
// var led3Air2: Double? = null,
// var led4Air2: Double? = null,
var calculatedPredictedDenovixRatio: Double = 0.0,
var validationError: Boolean = false,
var deviceHardwareId: String = "",
var allErrorMessages: String = "",
var testStatusCode: Double = 0.0,
var repeatReadingCount: Int = 0,
var readingsPerSample: Int = Constants.READINGS_PER_SAMPLE,
var uploadedToCloud: Boolean = false,
var uploadedToMolbio: Boolean = false
)

View File

@@ -1,13 +0,0 @@
package com.example.hpostesting.data.model.calibration
data class CalibrationData (
var led1Slope: Double = 1.0,
var led1Intercept: Double = 0.0,
var led2Slope: Double = 1.0,
var led2Intercept: Double = 0.0,
var led3Slope: Double = 1.0,
var led3Intercept: Double = 0.0,
var led4Slope: Double = 1.0,
var led4Intercept: Double = 0.0,
var calibratedAt: String = ""
)

View File

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

View File

@@ -9,5 +9,5 @@ data class LoginRequest(
val password: String? = "", val password: String? = "",
val serialNumber: String? = "", val serialNumber: String? = "",
val username: String? = "", val username: String? = "",
val version: String? = "" val version: String? = "2.1.26"
) )

View File

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

View File

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

View File

@@ -1,47 +1,21 @@
package com.example.hpostesting.data.model.patient package com.example.hpostesting.data.model.patient
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "hemo_cube_buffer_test_table")
data class BufferCheckData( data class BufferCheckData(
@PrimaryKey
var _id: String = "",
var kitno: String = "", var kitno: String = "",
var deviceId: String? = "", var deviceId: String? = "",
var appVersion:String? = "", var appVersion:String? = "",
var deviceSerialNumber: String = "", var deviceSerialNumber: String = "",
var deviceType: String = "HEMOCUBE", var deviceType: String = "HEMOCUBE",
var localFlag: Boolean = false,
var resultData: String = "", var resultData: String = "",
var led1Buffer: Double? = null, var led1Buffer: Double? = null,
var led2Buffer: Double? = null, var led2Buffer: Double? = null,
var led3Buffer: Double? = null,
var led4Buffer: Double? = null,
var led1Sample: Double? = null, var led1Sample: Double? = null,
var led2Sample: Double? = null, var led2Sample: Double? = null,
var led3Sample: Double? = null,
var led4Sample: Double? = null,
var led1Average: Double? = null, var led1Average: Double? = null,
var led2Average: Double? = null, var led2Average: Double? = null,
var led3Average: Double? = null,
var led4Average: Double? = null,
var abs1: Double? = null,
var abs2: Double? = null,
var abs3: Double? = null,
var abs4: Double? = null,
var deviceRatio: Double? = null, var deviceRatio: Double? = null,
var calculatedRatio: Double? = null, var calculatedRatio: Double? = null,
var predictedDenovixRatio: Double? = null,
var coefficients: String? = "", var coefficients: String? = "",
var classificationResult: String = "", var classificationResult: String = "",
var testTime: String = "", var testTime: String = ""
var prdClassification: String = "",
var errorMessages: String = "",
var batteryLevel: String = "",
var batteryCapacity: String = "",
var batteryMaxCapacity: String = "",
var batteryTemperature: String = "",
var batteryVoltage: String = "",
var reportUploadTime: String? = "",
) )

View File

@@ -43,51 +43,17 @@ data class HemoCubeTestData(
var abs2: Double? = null, var abs2: Double? = null,
var abs3: Double? = null, var abs3: Double? = null,
var abs4: Double? = null, var abs4: Double? = null,
var hb3: Double? = null,
var hb4: Double? = null,
var led1Gain1: Double? = null,
var led2Gain1: Double? = null,
var led3Gain1: Double? = null,
var led4Gain1: Double? = null,
var led1Gain2: Double? = null,
var led2Gain2: Double? = null,
var led3Gain2: Double? = null,
var led4Gain2: Double? = null,
var led1Gain3: Double? = null,
var led2Gain3: Double? = null,
var led3Gain3: Double? = null,
var led4Gain3: Double? = null,
var led1Gain4: Double? = null,
var led2Gain4: Double? = null,
var led3Gain4: Double? = null,
var led4Gain4: Double? = null,
var led1Air1: Double? = null,
var led2Air1: Double? = null,
var led3Air1: Double? = null,
var led4Air1: Double? = null,
var led1Air2: Double? = null,
var led2Air2: Double? = null,
var led3Air2: Double? = null,
var led4Air2: Double? = null,
var deviceRatio: Double? = null, var deviceRatio: Double? = null,
var calculatedRatio: Double? = null, var calculatedRatio: Double? = null,
var predictedDenovixRatio: Double? = null, var predictedDenovixRatio: Double? = null,
var slopeRatio: Double? = null,
var coefficients: String? = "", var coefficients: String? = "",
var classificationResult: String = "", var classificationResult: String = "",
var prdClassification: String = "", var prdClassification: String = "",
var deviceRatioClass: String = "",
var slopeRatioClass: String = "",
var errorMessages: String = "", var errorMessages: String = "",
var batteryLevel: String = "", var batteryLevel: String = "",
var batteryCapacity: String = "", var batteryCapacity: String = "",
var batteryMaxCapacity: String = "", var batteryMaxCapacity: String = "",
var batteryTemperature: String = "", var batteryTemperature: String = "",
var batteryVoltage: String = "", var batteryVoltage: String = "",
var molbioFlag: Boolean = false, var molbioFlag: Boolean = false
var quickCapture: Boolean = false,
var solution: String? = "",
var concentration: String? = "",
var volume: String? = "",
var isCSVCreated: Boolean = false
) )

View File

@@ -10,11 +10,11 @@ data class UserData(
var _id: String = "", var _id: String = "",
var name: String = "", var name: String = "",
var incubationTime: String = "", var incubationTime: String = "",
var gender: String = "",
var birthYear: String = "", var birthYear: String = "",
var abhaId: String = "", var abhaId: String = "",
var bloodGroup: String = "", var bloodGroup: String = "",
var userImageURL: String = "", var userImageURL: String = "",
var gender: String ="",
var location: Location? = null, var location: Location? = null,
var createdBy: String? = "", var createdBy: String? = "",
var reportUploadTime: String? = "", var reportUploadTime: String? = "",
@@ -46,14 +46,14 @@ data class UserData(
fun UserData.toHemoCubeTestData() = HemoCubeTestData( fun UserData.toHemoCubeTestData() = HemoCubeTestData(
_id = _id, _id = _id,
name = name, name = name,
bloodGroup = bloodGroup,
birthYear = birthYear, birthYear = birthYear,
gender = gender,
state = state,
abhaId = abhaId,
userImageURL = userImageURL, userImageURL = userImageURL,
testStatus = testStatus, testStatus = testStatus,
location = location, location = location,
gender = gender,
state = state,
abhaId = abhaId,
bloodGroup = bloodGroup,
prdClassification = prdClassification, prdClassification = prdClassification,
testTime = testTime testTime = testTime
) )

View File

@@ -1,29 +0,0 @@
package com.example.hpostesting.di
import android.content.Context
import com.example.hpostesting.data.repository.DatabaseRepository
import com.example.hpostesting.data.dao.UserDao
import com.example.hpostesting.domain.SaveRawData
import com.example.hpostesting.domain.SaveRawDataTest
import com.example.hpostesting.presentation.testRight.TestRightViewModel
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ViewModelComponent
import dagger.hilt.android.qualifiers.ApplicationContext
@Module
@InstallIn(ViewModelComponent::class)
object ViewModelModule {
@Provides
fun provideTestRightViewModel(
saveRawData: SaveRawData,
saveRawDataTest: SaveRawDataTest,
databaseRepository: DatabaseRepository,
userDao: UserDao,
context: Context
): TestRightViewModel {
return TestRightViewModel(saveRawData, saveRawDataTest, databaseRepository, userDao, context)
}
}

View File

@@ -57,30 +57,27 @@ class DatabaseRepository @Inject constructor(
} }
} }
override suspend fun deviceProvision(deviceProvisionRequest: DeviceProvisionRequest): Result<DeviceProvisionResponse> { suspend fun deviceProvision(deviceProvisionRequest: DeviceProvisionRequest): Result<DeviceProvisionResponse> {
return safeApiCall { molbioAuthApi.deviceProvision(deviceProvisionRequest) } return safeApiCall { molbioAuthApi.deviceProvision(deviceProvisionRequest) }
} }
override suspend fun login(loginRequest: LoginRequest): Result<LoginResponse> { suspend fun login(loginRequest: LoginRequest): Result<LoginResponse> {
return safeApiCall { molbioAuthApi.login(loginRequest) } return safeApiCall { molbioAuthApi.login(loginRequest) }
} }
override suspend fun uploadResults(molbioV2ResultRequest: MolbioV2ResultRequest): Result<MolbioV2ResultResponse> { suspend fun uploadResults(molbioV2ResultRequest: MolbioV2ResultRequest): Result<MolbioV2ResultResponse> {
return safeApiCall { molbioResultApi.uploadResults(molbioV2ResultRequest) } return safeApiCall { molbioResultApi.uploadResults(molbioV2ResultRequest) }
} }
override suspend fun checkUpdate(checkUpdateRequest: CheckUpdateRequest): Result<CheckUpdateResponse> { suspend fun checkUpdate(checkUpdateRequest: CheckUpdateRequest): Result<CheckUpdateResponse> {
return safeApiCall { molbioResultApi.checkUpdate(checkUpdateRequest) } return safeApiCall { molbioResultApi.checkUpdate(checkUpdateRequest) }
} }
override suspend fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest): Result<ResponseBody> { suspend fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest): Result<ResponseBody> {
return safeApiCall { molbioResultApi.deviceUpdate(deviceUpdateRequest) } return safeApiCall { molbioResultApi.deviceUpdate(deviceUpdateRequest) }
} }
override suspend fun downloadClientCertificate(): Result<ResponseBody> { suspend fun uploadLogs(logFile: MultipartBody.Part): Result<UploadLogsResponse> {
return safeApiCall { molbioResultApi.downloadClientCertificate() }
}
override suspend fun uploadLogs(logFile: MultipartBody.Part): Result<UploadLogsResponse> {
return safeApiCall { molbioResultApi.uploadLogs(logFile) } return safeApiCall { molbioResultApi.uploadLogs(logFile) }
} }
@@ -205,8 +202,4 @@ class DatabaseRepository @Inject constructor(
// Find the DeviceData object with the specified deviceId // Find the DeviceData object with the specified deviceId
return allDeviceDataList.find { it.deviceId == deviceId } return allDeviceDataList.find { it.deviceId == deviceId }
} }
override fun <UserData> addTestToDatabase(testDetails: UserData): Any {
TODO("Not yet implemented")
}
} }

View File

@@ -1,12 +1,6 @@
package com.example.hpostesting.data.repository package com.example.hpostesting.data.repository
import android.os.Environment
import com.example.hpostesting.data.datasource.LocalFileDataSource import com.example.hpostesting.data.datasource.LocalFileDataSource
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.opencsv.CSVWriter
import java.io.File
import java.io.FileWriter
import java.io.IOException
class LocalFileRepository(private val localFileDataSource: LocalFileDataSource) { class LocalFileRepository(private val localFileDataSource: LocalFileDataSource) {
fun saveCsvToDisk(filepath: String, contents: ArrayList<Array<String>>) = fun saveCsvToDisk(filepath: String, contents: ArrayList<Array<String>>) =

View File

@@ -1,24 +1,11 @@
package com.example.hpostesting.data.repository package com.example.hpostesting.data.repository
import com.example.hpostesting.data.Result
import com.example.hpostesting.data.model.Response import com.example.hpostesting.data.model.Response
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionRequest
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionResponse
import com.example.hpostesting.data.model.diagnostics.DiagnosticsData import com.example.hpostesting.data.model.diagnostics.DiagnosticsData
import com.example.hpostesting.data.model.log.UploadLogsResponse
import com.example.hpostesting.data.model.login.LoginRequest
import com.example.hpostesting.data.model.login.LoginResponse
import com.example.hpostesting.data.model.molbioresult.MolbioV2ResultRequest
import com.example.hpostesting.data.model.molbioresult.MolbioV2ResultResponse
import com.example.hpostesting.data.model.patient.BufferCheckData import com.example.hpostesting.data.model.patient.BufferCheckData
import com.example.hpostesting.data.model.patient.DeviceData import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.HemoCubeTestData import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.UserData import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.data.model.updates.CheckUpdateRequest
import com.example.hpostesting.data.model.updates.CheckUpdateResponse
import com.example.hpostesting.data.model.updates.DeviceUpdateRequest
import okhttp3.MultipartBody
import okhttp3.ResponseBody
interface Repository { interface Repository {
suspend fun addTestToDatabase(data: HemoCubeTestData?): Response<String> suspend fun addTestToDatabase(data: HemoCubeTestData?): Response<String>
@@ -32,19 +19,4 @@ interface Repository {
suspend fun uploadFileToStorage(patientID: String, filePath: String): Response<Boolean> suspend fun uploadFileToStorage(patientID: String, filePath: String): Response<Boolean>
suspend fun getDeviceDataById(deviceId: String): DeviceData? suspend fun getDeviceDataById(deviceId: String): DeviceData?
abstract fun <UserData> addTestToDatabase(testDetails: UserData): Any
// suspend fun addToDatabase(data: PatientDetails)
suspend fun deviceProvision(deviceProvisionRequest: DeviceProvisionRequest): Result<DeviceProvisionResponse>
suspend fun login(loginRequest: LoginRequest): Result<LoginResponse>
suspend fun uploadResults(molbioV2ResultRequest: MolbioV2ResultRequest): Result<MolbioV2ResultResponse>
suspend fun checkUpdate(checkUpdateRequest: CheckUpdateRequest): Result<CheckUpdateResponse>
suspend fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest): Result<ResponseBody>
suspend fun downloadClientCertificate(): Result<ResponseBody>
suspend fun uploadLogs(logFile: MultipartBody.Part): Result<UploadLogsResponse>
} }

View File

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

View File

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

View File

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

View File

@@ -8,18 +8,15 @@ import androidx.room.Room
import com.example.hpostesting.data.api.MolbioAuthApi import com.example.hpostesting.data.api.MolbioAuthApi
import com.example.hpostesting.data.api.MolbioResultApi import com.example.hpostesting.data.api.MolbioResultApi
import com.example.hpostesting.data.api.PropertyProvider import com.example.hpostesting.data.api.PropertyProvider
import com.example.hpostesting.data.dao.HemoCubeBufferDao
import com.example.hpostesting.data.dao.HemoCubeDao import com.example.hpostesting.data.dao.HemoCubeDao
import com.example.hpostesting.data.dao.MyDatabase import com.example.hpostesting.data.dao.MyDatabase
import com.example.hpostesting.data.dao.UserDao import com.example.hpostesting.data.dao.UserDao
import com.example.hpostesting.data.datasource.LocalFileDataSource import com.example.hpostesting.data.datasource.LocalFileDataSource
import com.example.hpostesting.data.datasource.LocalFileDataSourceImpl
import com.example.hpostesting.data.repository.DatabaseRepository import com.example.hpostesting.data.repository.DatabaseRepository
import com.example.hpostesting.data.repository.LocalFileRepository import com.example.hpostesting.data.repository.LocalFileRepository
import com.example.hpostesting.data.repository.Repository import com.example.hpostesting.data.repository.Repository
import com.example.hpostesting.domain.AuthInterceptor import com.example.hpostesting.domain.AuthInterceptor
import com.example.hpostesting.domain.LogFileManager import com.example.hpostesting.domain.LogFileManager
import com.example.hpostesting.domain.LogFileManagerImpl
import com.example.hpostesting.domain.SaveRawData import com.example.hpostesting.domain.SaveRawData
import com.example.hpostesting.domain.SaveRawDataTest import com.example.hpostesting.domain.SaveRawDataTest
import com.example.hpostesting.util.PropertyProviderImpl import com.example.hpostesting.util.PropertyProviderImpl
@@ -59,13 +56,6 @@ object AppModule {
return myDatabase.hemoCubeDao() return myDatabase.hemoCubeDao()
} }
@Provides
@Singleton
fun provideMyHemoCubeBuffer(myDatabase: MyDatabase): HemoCubeBufferDao {
return myDatabase.hemoCubeBufferDao()
}
@Provides @Provides
@Singleton @Singleton
fun provideContext(application: Application): Context { fun provideContext(application: Application): Context {
@@ -75,14 +65,14 @@ object AppModule {
@Provides @Provides
@Singleton @Singleton
fun provideSaveRawData(): SaveRawData { fun provideSaveRawData(): SaveRawData {
val repository = LocalFileRepository(LocalFileDataSourceImpl()) val repository = LocalFileRepository(LocalFileDataSource())
return SaveRawData(repository) return SaveRawData(repository)
} }
@Provides @Provides
@Singleton @Singleton
fun provideSaveRawDataTest(): SaveRawDataTest { fun provideSaveRawDataTest(): SaveRawDataTest {
val repository = LocalFileRepository(LocalFileDataSourceImpl()) val repository = LocalFileRepository(LocalFileDataSource())
return SaveRawDataTest(repository) return SaveRawDataTest(repository)
} }
@@ -119,7 +109,7 @@ object AppModule {
@Provides @Provides
@Singleton @Singleton
fun provideSharedPreferences(@ApplicationContext context: Context): SharedPreferences { fun provideSharedPreferences(@ApplicationContext context: Context): SharedPreferences {
return context.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE) return context.getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE)
} }
@Provides @Provides
@@ -172,11 +162,5 @@ object AppModule {
@Provides @Provides
@Singleton @Singleton
fun provideLogFileManager(context: Context): LogFileManager = LogFileManagerImpl(context) fun provideLogFileManager(context: Context): LogFileManager = LogFileManager(context)
@Provides
@Singleton
fun provideLocalFileDataSource(): LocalFileDataSource {
return LocalFileDataSourceImpl()
}
} }

View File

@@ -1,19 +1,18 @@
package com.example.hpostesting.presentation package com.example.hpostesting.presentation
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Bundle import android.os.Bundle
import android.text.Editable
import android.util.Log import android.util.Log
import android.view.View import android.view.View
import android.widget.EditText
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import com.example.hpostesting.data.DataHolder import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.Constants import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.LanguageManager import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.example.hpostesting.presentation.hemocube.HemocubeActivity import com.example.hpostesting.presentation.hemocube.HemocubeActivity
import com.example.hpostesting.presentation.testRight.TestRightActivity import com.example.hpostesting.presentation.testRight.TestRightActivity
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
@@ -21,28 +20,16 @@ import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.journeyapps.barcodescanner.ScanContract import com.journeyapps.barcodescanner.ScanContract
import com.journeyapps.barcodescanner.ScanIntentResult import com.journeyapps.barcodescanner.ScanIntentResult
import com.journeyapps.barcodescanner.ScanOptions import com.journeyapps.barcodescanner.ScanOptions
import com.zebra.barcode.sdk.sms.ConfigurationUpdateEvent
import com.zebra.scannercontrol.DCSSDKDefs
import com.zebra.scannercontrol.DCSSDKDefs.DCSSDK_COMMAND_OPCODE
import com.zebra.scannercontrol.DCSSDKDefs.DCSSDK_RESULT
import com.zebra.scannercontrol.DCSScannerInfo
import com.zebra.scannercontrol.FirmwareUpdateEvent
import com.zebra.scannercontrol.IDcsSdkApiDelegate
import com.zebra.scannercontrol.SDKHandler
import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityKitScanBinding import `in`.sminnovations.hpostesting.databinding.ActivityKitScanBinding
class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate { class KitScanActivity : AppCompatActivity() {
private val TAG = "KitScanActivity" private val TAG = "KitScanActivity"
private lateinit var binding: ActivityKitScanBinding private lateinit var binding: ActivityKitScanBinding
private lateinit var sharedPreference: SharedPreferences private lateinit var sharedPreference: SharedPreferences
var sdkHandler: SDKHandler? = null
var editBarcode: EditText? = null
var mScannerInfoList = ArrayList<DCSScannerInfo>()
private val barcodeLauncher = registerForActivityResult( private val barcodeLauncher = registerForActivityResult(
ScanContract() ScanContract()
) { result: ScanIntentResult -> ) { result: ScanIntentResult ->
@@ -64,40 +51,11 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
super.attachBaseContext(newBase) super.attachBaseContext(newBase)
} }
override fun dcssdkEventScannerAppeared(dcsScannerInfo: DCSScannerInfo?) {}
override fun dcssdkEventScannerDisappeared(i: Int) {}
override fun dcssdkEventCommunicationSessionEstablished(dcsScannerInfo: DCSScannerInfo?) {}
override fun dcssdkEventCommunicationSessionTerminated(i: Int) {}
// override fun dcssdkEventBarcode(p0: ByteArray?, p1: Int, p2: Int) {
// TODO("Not yet implemented")
// }
override fun dcssdkEventImage(bytes: ByteArray?, i: Int) {}
override fun dcssdkEventVideo(bytes: ByteArray?, i: Int) {}
override fun dcssdkEventBinaryData(bytes: ByteArray?, i: Int) {}
override fun dcssdkEventFirmwareUpdate(firmwareUpdateEvent: FirmwareUpdateEvent?) {}
override fun dcssdkEventAuxScannerAppeared(
dcsScannerInfo: DCSScannerInfo?,
dcsScannerInfo1: DCSScannerInfo?
) {
}
override fun dcssdkEventConfigurationUpdate(configurationUpdateEvent: ConfigurationUpdateEvent?) {}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
binding = ActivityKitScanBinding.inflate(layoutInflater) binding = ActivityKitScanBinding.inflate(layoutInflater)
sharedPreference = this.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE) sharedPreference = this.getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE)
setContentView(binding.root) setContentView(binding.root)
if (DataHolder.sampleReadCounter <= Constants.MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE && DataHolder.isReferenceTaken) { if (DataHolder.sampleReadCounter <= Constants.MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE && DataHolder.isReferenceTaken) {
@@ -152,8 +110,7 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
setSupportActionBar(binding.toolbar) setSupportActionBar(binding.toolbar)
binding.btnScanNow.setOnClickListener { binding.btnScanNow.setOnClickListener {
// startScanningNow() startScanningNow()
pullTrigger()
} }
@@ -207,64 +164,6 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
Toast.makeText(this, R.string.invalid_kit_number, Toast.LENGTH_LONG).show() Toast.makeText(this, R.string.invalid_kit_number, Toast.LENGTH_LONG).show()
} }
} }
//Setting up the SDK handler
sdkHandler = SDKHandler(this)
//Registers a particular object which conforms to IDcsSdkApiDelegate interface as a receiver of SDK notifications.
sdkHandler!!.dcssdkSetDelegate(this)
//this command is telling the sdk that we're going to be connecting to the scanner via USB
sdkHandler!!.dcssdkSetOperationalMode(DCSSDKDefs.DCSSDK_MODE.DCSSDK_OPMODE_SNAPI)
//deciding what kind of notifications we want to receive. Explained more in the function
//first we use bitmapping to set these values into the notifications_mask.
var notifications_mask = 0
// We would like to subscribe to all barcode events
notifications_mask =
notifications_mask or DCSSDKDefs.DCSSDK_EVENT.DCSSDK_EVENT_BARCODE.value
sdkHandler!!.dcssdkSubsribeForEvents(notifications_mask)
mScannerInfoList.addAll(sdkHandler!!.dcssdkGetAvailableScannersList())
Log.e("scannersize",sdkHandler!!.dcssdkGetAvailableScannersList().size.toString())
if (mScannerInfoList.isNotEmpty()) {
sdkHandler!!.dcssdkEstablishCommunicationSession(mScannerInfoList[0].scannerID)
} else {
Toast.makeText(this,"Error", Toast.LENGTH_LONG).show()
}
}
private fun pullTrigger() {
// Check if the list is not empty before accessing its elements
if (mScannerInfoList.isNotEmpty()) {
// Only proceed if the scanner is not active
if (!mScannerInfoList[0].isActive) {
sdkHandler?.dcssdkEstablishCommunicationSession(mScannerInfoList[0].scannerID)
}
val inXML = "<inArgs><scannerID> 1 </scannerID></inArgs>"
val outXML = StringBuilder()
val result: DCSSDK_RESULT =
sdkHandler!!.dcssdkExecuteCommandOpCodeInXMLForScanner(
DCSSDK_COMMAND_OPCODE.DCSSDK_DEVICE_PULL_TRIGGER, inXML, outXML, mScannerInfoList[0].scannerID // Ensure you're using the correct scanner ID
)
if (result == DCSSDK_RESULT.DCSSDK_RESULT_SUCCESS) {
Log.d("Scanning", "Success")
} else if (result == DCSSDK_RESULT.DCSSDK_RESULT_FAILURE) {
Log.d("Scanning", "Failed")
}
} else {
// Handle the case where the list is empty, perhaps notify the user or log an error
Log.e("ScannerError", "No scanners are connected or available.")
}
}
//this function is called if barcode is detected.
override fun dcssdkEventBarcode(barcodeData: ByteArray?, barcodeType: Int, fromScannerID: Int) {
val result = String(barcodeData!!)
Log.d("BARCODE", result)
runOnUiThread {
val editableResult: Editable = Editable.Factory.getInstance().newEditable(result)
binding.nameEditText.text = editableResult
}
} }
private fun checkHemoCubeKitData(): Boolean { private fun checkHemoCubeKitData(): Boolean {
@@ -286,7 +185,7 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
DataHolder.deviceType.observe(this) { deviceType -> DataHolder.deviceType.observe(this) { deviceType ->
when (deviceType) { when (deviceType) {
Constants.DEVICE_TYPE_HEMOCUBE -> { Constants.DEVICE_TYPE_HOMOCUBE -> {
val i = Intent(applicationContext, HemocubeActivity::class.java) val i = Intent(applicationContext, HemocubeActivity::class.java)
startActivity(i) startActivity(i)
} }
@@ -295,11 +194,6 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
val i = Intent(applicationContext, TestRightActivity::class.java) val i = Intent(applicationContext, TestRightActivity::class.java)
startActivity(i) startActivity(i)
} }
Constants.DEVICE_TYPE_TRUEHEME -> {
val i = Intent(applicationContext, HemocubeActivity::class.java)
startActivity(i)
}
} }
} }
} }

View File

@@ -1,10 +1,8 @@
package com.example.hpostesting.presentation package com.example.hpostesting.presentation
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import android.Manifest import android.Manifest
import android.content.BroadcastReceiver import android.content.*
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.hardware.usb.UsbManager import android.hardware.usb.UsbManager
import android.location.Location import android.location.Location
@@ -22,12 +20,7 @@ import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.LanguageManager import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.data.model.patient.UserData import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.data.model.test.TestType import com.example.hpostesting.data.model.test.TestType
import com.example.hpostesting.presentation.dashboard.DashboardActivity import com.google.android.gms.location.*
import com.google.android.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.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import com.google.firebase.crashlytics.FirebaseCrashlytics import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.hoho.android.usbserial.driver.UsbSerialProber import com.hoho.android.usbserial.driver.UsbSerialProber
@@ -88,7 +81,7 @@ class MainActivity : AppCompatActivity() {
DataHolder.deviceType.observe(this) { deviceType -> DataHolder.deviceType.observe(this) { deviceType ->
with(binding) { with(binding) {
if (deviceType == Constants.DEVICE_TYPE_HEMOCUBE) { if (deviceType == Constants.DEVICE_TYPE_HOMOCUBE) {
cvItem1.visibility = View.VISIBLE cvItem1.visibility = View.VISIBLE
cvItem3.visibility = View.VISIBLE cvItem3.visibility = View.VISIBLE
cvItem2.visibility = View.GONE cvItem2.visibility = View.GONE
@@ -111,15 +104,15 @@ class MainActivity : AppCompatActivity() {
val deviceType = when { val deviceType = when {
availableDrivers.isNotEmpty() -> { availableDrivers.isNotEmpty() -> {
val device = availableDrivers[0].device val device = availableDrivers[0].device
Toast.makeText(this, "Connected, productId: ${device.productId}, vendorId: ${device.vendorId}", Toast.LENGTH_SHORT).show() Toast.makeText(this, R.string.device, Toast.LENGTH_SHORT).show()
when { when {
device.productId == Constants.HOMO_CUBE_ID && device.vendorId == Constants.VENDOR_ID -> { device.productId == Constants.HOMO_CUBE_ID && device.vendorId == Constants.VENDOR_ID -> {
binding.cvItem1.visibility = View.VISIBLE binding.cvItem1.visibility = View.VISIBLE
binding.cvItem3.visibility = View.VISIBLE binding.cvItem3.visibility = View.VISIBLE
binding.cvItem2.visibility = View.GONE binding.cvItem2.visibility = View.GONE
binding.cvItem4.visibility = View.GONE binding.cvItem4.visibility = View.GONE
DataHolder.deviceType.postValue(Constants.DEVICE_TYPE_HEMOCUBE) DataHolder.deviceType.postValue(Constants.DEVICE_TYPE_HOMOCUBE)
Constants.DEVICE_TYPE_HEMOCUBE Constants.DEVICE_TYPE_HOMOCUBE
} }
device.productId == Constants.HEMO_CUBE_V2_PRODUCT_ID && device.vendorId == Constants.HEMO_CUBE_V2_VENDOR_ID -> { device.productId == Constants.HEMO_CUBE_V2_PRODUCT_ID && device.vendorId == Constants.HEMO_CUBE_V2_VENDOR_ID -> {
@@ -127,26 +120,8 @@ class MainActivity : AppCompatActivity() {
binding.cvItem3.visibility = View.VISIBLE binding.cvItem3.visibility = View.VISIBLE
binding.cvItem2.visibility = View.GONE binding.cvItem2.visibility = View.GONE
binding.cvItem4.visibility = View.GONE binding.cvItem4.visibility = View.GONE
DataHolder.deviceType.postValue(Constants.DEVICE_TYPE_HEMOCUBE) DataHolder.deviceType.postValue(Constants.DEVICE_TYPE_HOMOCUBE)
Constants.DEVICE_TYPE_HEMOCUBE Constants.DEVICE_TYPE_HOMOCUBE
}
device.productId == 24577 && device.vendorId == 1027 -> {
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_TRUEHEME)
Constants.DEVICE_TYPE_TRUEHEME
}
device.productId == 8963 && device.vendorId == 1659 -> {
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_HEMOCUBE)
Constants.DEVICE_TYPE_HEMOCUBE
} }
device.productId == Constants.DEVICE_PRODUCT_ID && device.vendorId == Constants.DEVICE_VENDOR_ID -> { device.productId == Constants.DEVICE_PRODUCT_ID && device.vendorId == Constants.DEVICE_VENDOR_ID -> {
@@ -285,6 +260,7 @@ class MainActivity : AppCompatActivity() {
// exception.printStackTrace() // exception.printStackTrace()
// } // }
fusedLocationClient.lastLocation.addOnSuccessListener { location: Location? -> fusedLocationClient.lastLocation.addOnSuccessListener { location: Location? ->
location?.let { location?.let {
if (DataHolder.selectedTest != null) { if (DataHolder.selectedTest != null) {
@@ -308,6 +284,9 @@ class MainActivity : AppCompatActivity() {
val rootView = findViewById<View>(android.R.id.content) val rootView = findViewById<View>(android.R.id.content)
Snackbar.make(rootView, errorMessage, Snackbar.LENGTH_LONG).show() Snackbar.make(rootView, errorMessage, Snackbar.LENGTH_LONG).show()
} }
} }
private fun requestLocationUpdates() { private fun requestLocationUpdates() {

View File

@@ -1,195 +0,0 @@
package com.example.hpostesting.presentation
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import com.example.hpostesting.presentation.assurance.AssuranceControlsActivity
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import io.nats.client.AuthHandler
import io.nats.client.Connection
import io.nats.client.Message
import io.nats.client.NKey
import io.nats.client.Nats
import io.nats.client.Options
import java.io.BufferedInputStream
import java.io.File
import java.io.FileInputStream
import java.io.IOException
import java.nio.charset.StandardCharsets
import java.nio.file.Paths
import java.security.GeneralSecurityException
import java.security.KeyStore
import java.security.SecureRandom
import java.security.cert.CertificateFactory
import javax.net.ssl.KeyManager
import javax.net.ssl.KeyManagerFactory
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManager
import javax.net.ssl.TrustManagerFactory
class NatsManager(datacollector: DashboardActivity) {
val TAG = "Nats Service"
var nc: Connection? = null
val datacollector = datacollector
var connect = false
private fun createSSLContext(): SSLContext {
val keyStorePassword = "prime24".toCharArray() // Change as necessary
val clientCertPath = "/storage/sdcard0/Download/client.p12"
// Load client certificate and key
val keyStore = KeyStore.getInstance("PKCS12")
FileInputStream(clientCertPath).use { keyStoreInputStream ->
keyStore.load(keyStoreInputStream, keyStorePassword)
}
val caCertPath = "/storage/sdcard0/Android/data/in.sminnovations.hpostesting.quality/files/NATS/clientCertificate/client-cert.pem"
val caCert = FileInputStream(caCertPath).use { inputStream ->
val certificateFactory = CertificateFactory.getInstance("X.509")
certificateFactory.generateCertificate(inputStream)
}
val trustStore = KeyStore.getInstance(KeyStore.getDefaultType()).apply {
load(null, null) // Initialize the keystore
setCertificateEntry("caCert", caCert) // Add the CA certificate
}
// Initialize key manager factory
val kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm())
kmf.init(keyStore, keyStorePassword)
// Initialize trust manager factory
val tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
tmf.init(trustStore)
// Initialize SSLContext
val sslContext = SSLContext.getInstance("TLS")
sslContext.init(kmf.keyManagers, tmf.trustManagers, SecureRandom())
return sslContext
}
@RequiresApi(Build.VERSION_CODES.O)
fun connect() {
Log.d(TAG, "TRY TO CONNECT")
Thread {
val seedString = "SUAJH5VMO6GDRQA6QTXCLIJMS74IWIUTU3NJVYIOTZF2LBWUPD77DA2ZEA"
Log.e("seedString",seedString)
val seedBytes = seedString.toCharArray()
val theNKey = NKey.fromSeed(seedBytes) // really should load from somewhere
val options = Options.Builder()
.server("nats://nanodgx.in:4222")
.sslContext(createSSLContext())
.authHandler(object : AuthHandler {
override fun getID(): CharArray? {
return try {
theNKey?.publicKey
} catch (ex: GeneralSecurityException) {
null
} catch (ex: IOException) {
null
} catch (ex: NullPointerException) {
null
}
}
override fun sign(nonce: ByteArray): ByteArray? {
return try {
theNKey?.sign(nonce)
} catch (ex: GeneralSecurityException) {
null
} catch (ex: IOException) {
null
} catch (ex: NullPointerException) {
null
}
}
override fun getJWT(): CharArray? {
return null
}
})
.build()
try {
nc = Nats.connect(options)
Log.d(TAG, "Connected to Nats server ${options.servers.first()}")
connect = true
datacollector.setConnect(true)
if (nc?.status == Connection.Status.CONNECTED) {
Log.e("NATSCONNECTION", "NATS is successfully connected.")
} else {
Log.e("NATSCONNECTION", "NATS is not connected. Current status: ${nc?.status}")
}
nc?.publish(
"server.hpos.HCV-000-3001.ping",
"ALIVE".toByteArray(StandardCharsets.UTF_8)
)
nc?.publish(
"server.hpos.HCV-000-3001.health",
"ALIVE".toByteArray(StandardCharsets.UTF_8)
)
Log.d(TAG, "Published msg server.hpos.HCV-000-3001.ping on topic Testing")
val d = nc?.createDispatcher { msg: Message? ->
println("PRITIMOI SARKAR $msg")
}
d?.subscribe("device.hpos.HCV-000-3001.update") { msg ->
val response = String(msg.data, StandardCharsets.UTF_8)
datacollector. setResponse(response)
println("Message received (up to 100 times): $response")
}
d?.subscribe("device.hpos.HCV-000-3001.uploadlogs") { msg ->
val response = String(msg.data, StandardCharsets.UTF_8)
datacollector.setResponse(response + "uPLOAD")
println("Message received (up to 100 times): $response")
}
d?.subscribe("device.hpos.HCV-000-3001.disable") { msg ->
val response = String(msg.data, StandardCharsets.UTF_8)
datacollector.setResponse(response)
println("Message received (up to 100 times): $response")
}
d?.subscribe("device.hpos.HCV-000-3001.updatecustomer") { msg ->
val response = String(msg.data, StandardCharsets.UTF_8)
datacollector.setResponse(response)
println("Message received (up to 100 times): $response")
}
d?.subscribe("device.hpos.HCV-000-3001.checkupdate") { msg ->
val response = String(msg.data, StandardCharsets.UTF_8)
datacollector.setResponse(response)
println("Message received (up to 100 times): $response")
}
} catch (exp: Exception) {
println(exp.printStackTrace())
connect = false
datacollector.setConnect(false)
}
}.start()
}
fun pub(topic: String, msg: String) {
nc?.publish(topic, msg.toByteArray(StandardCharsets.UTF_8))
Log.d(TAG, "Published msg ${msg} on topic ${topic}")
}
fun close() {
nc?.close()
Log.d(TAG, "Nats connection close")
}
}

View File

@@ -1,8 +1,6 @@
package com.example.hpostesting.presentation.adapter package com.example.hpostesting.presentation.adapter
import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.content.res.Resources
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@@ -28,8 +26,7 @@ class OfflineUserListAdapter(private val view: View, private val batLevel: Int)
RecyclerView.Adapter<OfflineUserListAdapter.OfflineUserListViewHolder>() { RecyclerView.Adapter<OfflineUserListAdapter.OfflineUserListViewHolder>() {
inner class OfflineUserListViewHolder(val binding: OfflineUserListViewBinding) : inner class OfflineUserListViewHolder(val binding: OfflineUserListViewBinding) :
RecyclerView.ViewHolder(binding.root) { RecyclerView.ViewHolder(binding.root)
}
private val differCallback = object : DiffUtil.ItemCallback<HemoCubeTestData>() { private val differCallback = object : DiffUtil.ItemCallback<HemoCubeTestData>() {
override fun areItemsTheSame( override fun areItemsTheSame(
@@ -57,29 +54,14 @@ class OfflineUserListAdapter(private val view: View, private val batLevel: Int)
return differ.currentList.size return differ.currentList.size
} }
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: OfflineUserListViewHolder, position: Int) { override fun onBindViewHolder(holder: OfflineUserListViewHolder, position: Int) {
val userList = differ.currentList[position] val userList = differ.currentList[position]
holder.binding.apply { holder.binding.apply {
userID.text = "User ID: ${userList._id}" userID.text = "User ID: ${userList._id}"
bloodGroup.text = "Blood group: ${userList.bloodGroup}" bloodGroup.text = "Blood group: ${userList.bloodGroup}"
time.text = "Time: ${isBetween15And30Minutes(userList.incubationTime)} \n Started at: ${ time.text = "Time: ${userList.incubationTime}"
SimpleDateFormat("HH:mm:ss").format(
SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).parse(userList.incubationTime)!!
)
}"
if (userList.testStatus!!) {
teststatus.text = view.context.getString(R.string.test_concluded)
} else {
teststatus.text = view.context.getString(R.string.test_pending)
}
userCard.setOnClickListener { userCard.setOnClickListener {
if (false) { if (batLevel < 40) {
Toast.makeText( Toast.makeText(
view.context, view.context,
view.context.getString(R.string.low_battery_warning), view.context.getString(R.string.low_battery_warning),
@@ -128,7 +110,6 @@ class OfflineUserListAdapter(private val view: View, private val batLevel: Int)
} }
} }
} }
} }
} }
@@ -142,21 +123,4 @@ class OfflineUserListAdapter(private val view: View, private val batLevel: Int)
return diffMillis / (60 * 1000) return diffMillis / (60 * 1000)
} }
private fun showWarningToast(resId: Int) {
val contextToUse = view.context ?: return
val message = try {
contextToUse.getString(resId)
} catch (e: Resources.NotFoundException) {
"Resource not found for ID: $resId"
}
Toast.makeText(
contextToUse,
message,
Toast.LENGTH_SHORT
).show()
}
} }

View File

@@ -26,6 +26,7 @@ import android.widget.AutoCompleteTextView
import androidx.core.content.ContextCompat.getSystemService import androidx.core.content.ContextCompat.getSystemService
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.google.firebase.firestore.FirebaseFirestore import com.google.firebase.firestore.FirebaseFirestore
@@ -213,13 +214,13 @@ class UserListAdapter(
).show() ).show()
} else { } else {
if (model.incubationTime != "") { if (model.incubationTime != "") {
if (isBetween15And30Minutes(model.incubationTime) < -15000) { if (isBetween15And30Minutes(model.incubationTime) < 15) {
Toast.makeText( Toast.makeText(
view.context, view.context,
context?.getString(R.string.incubation_not_completed), context?.getString(R.string.incubation_not_completed),
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
} else if (isBetween15And30Minutes(model.incubationTime) > 300000) { } else if (isBetween15And30Minutes(model.incubationTime) > 30) {
Toast.makeText( Toast.makeText(
view.context, view.context,
context?.getString(R.string.incubation_crossed_30_minutes), context?.getString(R.string.incubation_crossed_30_minutes),
@@ -243,6 +244,8 @@ class UserListAdapter(
} }
} }
private fun isBetween15And30Minutes(createdAt: String): Long { private fun isBetween15And30Minutes(createdAt: String): Long {
val formatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()) val formatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
val createdAtDate: Date = formatter.parse(createdAt)!! val createdAtDate: Date = formatter.parse(createdAt)!!

View File

@@ -1,49 +0,0 @@
package com.example.hpostesting.presentation.assurance
import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import com.example.hpostesting.presentation.NatsManager
import com.example.hpostesting.presentation.dashboard.IDataCollector
import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.databinding.ActivityAssuranceControlsBinding
@AndroidEntryPoint
class AssuranceControlsActivity: AppCompatActivity(), IDataCollector {
lateinit var binding: ActivityAssuranceControlsBinding
lateinit var sharedPreference: SharedPreferences
lateinit var nats: NatsManager
var responses: String = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityAssuranceControlsBinding.inflate(layoutInflater)
sharedPreference = this.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
setContentView(binding.root)
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction()
.replace(binding.fgAssuranceControls.id, AssuranceControlsFragment())
.commit()
}
// nats = NatsManager(this)
// nats.connect()
// nats.pub("server.hpos.HCV-000-3001.ping", "THIS IS A TEST MSG")
}
override fun setConnect(connect: Boolean) {
if(connect){
Log.i("NATS Connection", connect.toString())
}
}
override fun setResponse(response: String) {
responses = responses+response+"\n"
println(responses)
}
}

View File

@@ -1,160 +0,0 @@
package com.example.hpostesting.presentation.assurance
import android.R
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.Spinner
import androidx.fragment.app.Fragment
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.presentation.hemocube.HemocubeActivity
import `in`.sminnovations.hpostesting.databinding.FragmentAssuranceControlsBinding
import java.time.Instant
class AssuranceControlsFragment: Fragment() {
lateinit var binding: FragmentAssuranceControlsBinding
private lateinit var sharedPreferences: SharedPreferences
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
): View {
binding = FragmentAssuranceControlsBinding.inflate(inflater, container, false)
sharedPreferences =
requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initViews()
}
private fun initViews() {
// binding.btnSubmit.visibility = View.GONE
val solutionSpinner: Spinner = binding.spinnerSolutions
val solutionOptions = arrayOf("Select solution", "Tartrazine", "AR")
val solutionAdapter = ArrayAdapter(requireContext(), R.layout.simple_spinner_item, solutionOptions)
solutionAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
solutionSpinner.adapter = solutionAdapter
solutionSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long
) {
val selectedValue: String = solutionOptions[position]
if (!selectedValue.equals("Select solution")) {
DataHolder.hemoCubeTestData!!.solution = selectedValue
}
}
override fun onNothingSelected(parent: AdapterView<*>?) {
}
}
val concentrationSpinner: Spinner = binding.spinnerConcentration
val concentrationOptions = arrayOf("Select concentration", "65umol", "45umol", "22.5umol", "12.25umol", "6.125umol", "75umol", "50umol", "25umol", "12.5umol", "6.25umol")
val concentrationAdapter = ArrayAdapter(requireContext(), R.layout.simple_spinner_item, concentrationOptions)
concentrationAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
concentrationSpinner.adapter = concentrationAdapter
concentrationSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long
) {
val selectedValue: String = concentrationOptions[position]
if (!selectedValue.equals("Select concentration")) {
DataHolder.hemoCubeTestData!!.concentration = selectedValue
}
}
override fun onNothingSelected(parent: AdapterView<*>?) {
}
}
val volumeSpinner: Spinner = binding.spinnerVolume
val volumeOptions = arrayOf("Select volume", "1uml", "2uml", "4uml", "4.5uml", "5uml")
val volumeAdapter = ArrayAdapter(requireContext(), R.layout.simple_spinner_item, volumeOptions)
volumeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
volumeSpinner.adapter = volumeAdapter
volumeSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long
) {
val selectedValue: String = volumeOptions[position]
if (!selectedValue.equals("Select volume")) {
DataHolder.hemoCubeTestData!!.volume = selectedValue
}
}
override fun onNothingSelected(parent: AdapterView<*>?) {
}
}
// load saved values
val savedSolution = sharedPreferences.getString(Constants.QUICK_CAPTURE_SOLUTION, "").toString()
val solutionPosition = getPositionOfValue(savedSolution, solutionOptions.toList())
solutionSpinner.setSelection(solutionPosition)
val savedConcentration = sharedPreferences.getString(Constants.QUICK_CAPTURE_CONCENTRATION, "").toString()
val concentrationPosition = getPositionOfValue(savedConcentration, concentrationOptions.toList())
concentrationSpinner.setSelection(concentrationPosition)
val savedVolume = sharedPreferences.getString(Constants.QUICK_CAPTURE_VOLUME, "").toString()
val volumePosition = getPositionOfValue(savedVolume, volumeOptions.toList())
volumeSpinner.setSelection(volumePosition)
binding.btnSubmit.setOnClickListener {
DataHolder.hemoCubeTestData!!.quickCapture = true
val currentUnixTime = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Instant.now().epochSecond
} else {
""
}
DataHolder.hemoCubeTestData!!._id = currentUnixTime.toString() + "SMI"
DataHolder.hemoCubeTestData!!.name = "${DataHolder.hemoCubeTestData!!.solution} ${DataHolder.hemoCubeTestData!!.concentration} ${DataHolder.hemoCubeTestData!!.volume}"
DataHolder.selectedTest = UserData()
DataHolder.selectedTest?._id = DataHolder.hemoCubeTestData!!._id
DataHolder.selectedTest?.name = DataHolder.hemoCubeTestData!!.name
with(sharedPreferences.edit()) {
putString(Constants.QUICK_CAPTURE_SOLUTION, DataHolder.hemoCubeTestData!!.solution)
putString(Constants.QUICK_CAPTURE_CONCENTRATION, DataHolder.hemoCubeTestData!!.concentration)
putString(Constants.QUICK_CAPTURE_VOLUME, DataHolder.hemoCubeTestData!!.volume)
apply()
}
val i = Intent(requireContext(), HemocubeActivity::class.java)
startActivity(i)
}
}
fun <T> getPositionOfValue(value: T, data: List<T>?): Int {
data?.let {
for (i in it.indices) {
if (it[i] == value) {
return i
}
}
}
return 0
}
}

View File

@@ -1,6 +0,0 @@
package com.example.hpostesting.presentation.assurance
import androidx.lifecycle.ViewModel
class AssuranceControlsViewModel : ViewModel() {
}

View File

@@ -1,183 +0,0 @@
package com.example.hpostesting.presentation.autodac
import android.annotation.SuppressLint
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.ServiceConnection
import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbDeviceConnection
import android.hardware.usb.UsbManager
import android.os.Bundle
import android.os.IBinder
import android.util.Log
import android.view.Menu
import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.get
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.presentation.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.ActivityAutoDacBinding
@AndroidEntryPoint
class AutoDacActivity: AppCompatActivity() {
private lateinit var binding: ActivityAutoDacBinding
val viewModel: AutoDacViewModel by viewModels()
private var myMenu: Menu? = null
private lateinit var mDriver: UsbSerialDriver
private var mConnection: UsbDeviceConnection? = null
lateinit var mService: UsbService
private val TAG = "HemoCube"
private val broadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
synchronized(this) {
val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
device?.apply {
connectUsb(true)
DataHolder.usbConnected.postValue(true)
}
} else {
onErrorReported("permission denied for device")
DataHolder.usbConnected.postValue(true)
}
}
}
}
private val connection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) {
val binder = service as UsbService.UsbServiceBinder
mService = binder.getService()
viewModel.isServiceConnected = true
mConnection.let { mService.connect(mDriver, mConnection!!) }
moveToNext()
}
override fun onServiceDisconnected(arg0: ComponentName) {
viewModel.isServiceConnected = false
}
}
override fun attachBaseContext(newBase: Context?) {
val languageCode = LanguageManager.getSavedLanguage(newBase!!)
LanguageManager.setLocale(newBase, languageCode)
super.attachBaseContext(newBase)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityAutoDacBinding.inflate(layoutInflater)
setContentView(binding.root)
// setSupportActionBar(binding.myToolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
setupListener()
connectUsb(false)
}
private fun setupListener() {
DataHolder.usbConnected.observe(this) {
Log.d("USB OBSERVE", "HemoCube called -> $it")
if (it) {
myMenu?.get(0)?.icon =
ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_24)
} else {
myMenu?.get(0)?.icon =
ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_off_24)
Toast.makeText(this, "Device is Disconnected", Toast.LENGTH_SHORT).show()
}
}
}
open fun connectUsb(permissionGranted: Boolean) {
Log.d(TAG, "connectUsb() called, permission variable = $permissionGranted")
val manager = getSystemService(Context.USB_SERVICE) as UsbManager
val availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager)
if (availableDrivers.isEmpty()) {
onErrorReported("No Device is Connected")
} else {
mDriver = availableDrivers[0]
mConnection = manager.openDevice(mDriver.device)
if (mConnection == null) {
requestUserPermission(manager, mDriver.device)
} else {
setupService()
}
}
}
fun onErrorReported(msg: String) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
if (!isFinishing) onBackPressed()
}
private fun moveToNext() {
if (supportFragmentManager.isDestroyed) return
supportFragmentManager.beginTransaction().replace(binding.fgAutoDac.id, AutoDacFragment())
.commit()
}
@SuppressLint("MutableImplicitPendingIntent")
private fun requestUserPermission(manager: UsbManager, device: UsbDevice) {
val mPendingIntent: PendingIntent
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
mPendingIntent = PendingIntent.getBroadcast(
this, 0, Intent(Constants.HEMOCUBE_USB_PERMISSION), PendingIntent.FLAG_MUTABLE
)
} else {
mPendingIntent = PendingIntent.getBroadcast(
this,
0,
Intent(Constants.HEMOCUBE_USB_PERMISSION),
PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
)
}
val filter = IntentFilter(Constants.HEMOCUBE_USB_PERMISSION)
registerReceiver(broadcastReceiver, filter)
manager.requestPermission(device, mPendingIntent)
}
fun setupService() {
val intent = Intent(this, UsbService::class.java)
bindService(intent, connection, Context.BIND_AUTO_CREATE)
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.my_menu, menu)
return true
}
override fun onDestroy() {
super.onDestroy()
if (viewModel.isServiceConnected) {
mService.disconnect()
unbindService(connection)
viewModel.isServiceConnected = false
}
}
}

View File

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

View File

@@ -1,52 +0,0 @@
package com.example.hpostesting.presentation.autodac
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.NetworkStatusLiveData
import com.example.hpostesting.data.dao.HemoCubeDao
import com.example.hpostesting.data.model.Response
import com.example.hpostesting.data.model.diagnostics.DiagnosticsData
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.repository.Repository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class AutoDacViewModel @Inject constructor(
private val hemoCubeDao: HemoCubeDao,
private val repository: Repository,
context: Context
) : ViewModel() {
var isServiceConnected = false
val progressBar = MutableLiveData(false)
val messages = MutableLiveData<String>()
private val sharedPreference: SharedPreferences =
context.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
val deviceData = MutableLiveData<DeviceData?>()
val fireBaseUpload = MutableLiveData<String>()
fun addAutoDacDataToDb(data: DiagnosticsData) {
viewModelScope.launch {
try {
when (val response = repository.addDiagnostics(data)) {
is Response.Success -> {
fireBaseUpload.postValue("Success")
}
is Response.Error -> {
fireBaseUpload.postValue("Error")
}
}
} catch (e: Exception) {
fireBaseUpload.postValue("Error")
}
}
}
}

View File

@@ -7,26 +7,30 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import android.widget.Toast import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.Constants import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.HemoCubeCommands import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.model.patient.BufferCheckData import com.example.hpostesting.data.model.patient.BufferCheckData
import com.example.hpostesting.data.model.patient.DeviceData import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.toHemoCubeTestData
import com.example.hpostesting.presentation.UsbServiceListener import com.example.hpostesting.presentation.UsbServiceListener
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.example.hpostesting.presentation.utils.MyDialogListener
import com.example.hpostesting.presentation.utils.UIUtils
import com.google.firebase.crashlytics.ktx.crashlytics import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.ktx.Firebase import com.google.firebase.ktx.Firebase
import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentHemoCubeReferenceBinding import `in`.sminnovations.hpostesting.databinding.FragmentHemoCubeReferenceBinding
import kotlin.math.log10
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Calendar import java.util.Calendar
import java.util.Locale import java.util.Locale
import java.util.UUID
import kotlin.math.log10
class HemoCubeBufferCheckFragment : Fragment() { class HemoCubeBufferCheckFragment : Fragment() {
@@ -37,30 +41,15 @@ class HemoCubeBufferCheckFragment : Fragment() {
private var resultData: String = "" private var resultData: String = ""
private var kitno: String = "" private var kitno: String = ""
private var isOnline = false private var isOnline = false
private val messages = MutableLiveData<String>()
private var isTestOngoing = false private var isTestOngoing = false
private var startListening = MutableLiveData(false) private var startListening = MutableLiveData(false)
private var led1BufferForDevice = 0.0
private var led2BufferForDevice = 0.0
private var led3BufferForDevice = 0.0
private var led4BufferForDevice = 0.0
private var led1SampleForDevice = 0.0
private var led2SampleForDevice = 0.0
private var led3SampleForDevice = 0.0
private var led4SampleForDevice = 0.0
private var fittedAbs1 = 0.0
private var fittedAbs2 = 0.0
private var fittedAbs3 = 0.0
private var fittedAbs4 = 0.0
private var _predictedDenovixRatio = 0.0
private var validationError = false
private var allErrorMessages = ""
private var deviceHardwareId = ""
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?, inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
): View { ): View {
binding = FragmentHemoCubeReferenceBinding.inflate(inflater, container, false) binding = FragmentHemoCubeReferenceBinding.inflate(inflater, container, false)
sharedPreferences = sharedPreferences =
requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE) requireContext().getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE)
return binding.root return binding.root
} }
@@ -75,14 +64,13 @@ class HemoCubeBufferCheckFragment : Fragment() {
binding.nameEditText.setText("SMI/SC/") binding.nameEditText.setText("SMI/SC/")
binding.tvTitle.visibility = View.GONE binding.tvTitle.visibility = View.GONE
binding.tvName.visibility = View.GONE binding.tvName.visibility = View.GONE
binding.btnPlacebuffer.visibility = View.GONE
binding.btnGo.setOnClickListener { binding.btnGo.setOnClickListener {
val serialNumber = binding.nameEditText.text.toString().trim() val serialNumber = binding.nameEditText.text.toString().trim()
if (serialNumber.isNotEmpty() && isSerialValid(serialNumber)) { if (serialNumber.isNotEmpty() && isSerialValid(serialNumber)) {
kitno = serialNumber kitno = serialNumber
listenToHemoCube() listenToHemoCube()
getDeviceInfo() startBufferProcess()
} else { } else {
Toast.makeText(context, R.string.invalid_kit_number, Toast.LENGTH_LONG).show() Toast.makeText(context, R.string.invalid_kit_number, Toast.LENGTH_LONG).show()
return@setOnClickListener return@setOnClickListener
@@ -96,17 +84,17 @@ class HemoCubeBufferCheckFragment : Fragment() {
} }
} }
binding.btnSamplestart.setOnClickListener {
startSampleProcess()
it.visibility = View.GONE activity?.runOnUiThread {
binding.btnSubmit.isEnabled = true
binding.btnSubmit.isClickable = true
}
binding.btnSubmit.setOnClickListener {
} }
binding.btnSubmit.isEnabled = false binding.btnSubmit.isEnabled = false
binding.btnSubmit.isClickable = false binding.btnSubmit.isClickable = false
binding.btnPlacebuffer.setOnClickListener {
checkAndStartProcess()
it.visibility = View.GONE
}
} }
private fun observeViewModel() { private fun observeViewModel() {
@@ -128,10 +116,6 @@ class HemoCubeBufferCheckFragment : Fragment() {
if (result == "Success") { if (result == "Success") {
showToast(R.string.kit_uploaded) showToast(R.string.kit_uploaded)
} }
if (result == "Error") {
showToast("Error uploading data, Kit result stored locally")
startActivity(Intent(requireActivity(), DashboardActivity::class.java))
}
if (result == "Local") { if (result == "Local") {
showToast(R.string.kit_upload_failed) showToast(R.string.kit_upload_failed)
} }
@@ -139,24 +123,27 @@ class HemoCubeBufferCheckFragment : Fragment() {
binding.progressBar.visibility = View.GONE binding.progressBar.visibility = View.GONE
} }
hemoCubeViewModel.messages.observe(viewLifecycleOwner) { messages.observe(viewLifecycleOwner) {
binding.tvSubtitle4.text = it binding.tvSubtitle4.text = it
} }
} }
private fun checkAndStartProcess() {
startBufferProcess()
}
private fun listenToHemoCube() { private fun listenToHemoCube() {
if (DataHolder.hemoCubeTestData == null) {
DataHolder.hemoCubeTestData = DataHolder.selectedTest?.toHemoCubeTestData()
}
val fullReadOutput = StringBuilder()
startListening.postValue(true) startListening.postValue(true)
try { try {
(activity as HemocubeBufferCheckActivity).mService.listenToHemoCube(object : (activity as HemocubeBufferCheckActivity).mService.listenToHemoCube(object :
UsbServiceListener { UsbServiceListener {
override fun onUsbRead(data: ByteArray?) { override fun onUsbRead(data: ByteArray?) {
data?.let { data?.let {
val stringData = String(it) val stringData = String(it)
handleUsbData(stringData) fullReadOutput.append(stringData)
handleUsbData(stringData, fullReadOutput)
} }
} }
@@ -169,212 +156,97 @@ class HemoCubeBufferCheckFragment : Fragment() {
} }
} }
private fun handleUsbData(stringData: String) { private fun handleUsbData(stringData: String, fullReadOutput: StringBuilder) {
if (stringData.contains("#")) { if (stringData.contains("#")) {
messages.postValue(stringData)
isTestOngoing = true isTestOngoing = true
} }
resultData += stringData resultData += fullReadOutput.toString()
when { when {
stringData.contains("SN") -> { stringData.contains("#Buffer Completed") -> showStartSampleDialog()
val slData = stringData.split(" ") stringData.contains("#Sample Completed") -> {
if (slData.size > 1) {
val hardwareId = slData[1].trim()
deviceHardwareId = hardwareId
with(sharedPreferences.edit()) {
putString(Constants.DEVICE_ID, hardwareId)
apply()
}
}
activity?.runOnUiThread { activity?.runOnUiThread {
binding.tvSubtitle4.visibility = View.VISIBLE binding.btnSubmit.isEnabled = true
binding.btnPlacebuffer.visibility = View.VISIBLE binding.btnSubmit.isClickable = true
} }
hemoCubeViewModel.messages.postValue("Start")
}
stringData.contains("#BS") -> {
hemoCubeViewModel.messages.postValue("Buffer Started")
}
stringData.contains("#BC") -> {
activity?.runOnUiThread {
binding.tvSubtitle4.text = "Buffer Completed"
binding.btnSamplestart.visibility = View.VISIBLE
}
}
stringData.contains("#SS") -> {
activity?.runOnUiThread {
binding.tvSubtitle4.text = "Sample Started"
binding.btnSamplestart.visibility = View.GONE
}
}
stringData.contains("#SC") -> {
hemoCubeViewModel.messages.postValue("Sample Completed \nGathering data")
fetchResult() fetchResult()
} }
resultData.contains("REND") -> { stringData.contains("RESULT") || resultData.contains("REND") -> {
hemoCubeViewModel.messages.postValue( var validString: String
"Data collected \n" + " Processing data" val results: List<String>
) if (stringData.contains("RESULT")) {
val resultLines = resultData.split("\\s+(?=LB|LS)".toRegex()) validString = isValidResult(stringData)
var bufferIntensity = resultLines[1].split(' ')[1].trim() if (validString.isEmpty()) {
led1BufferForDevice = bufferIntensity.toDoubleOrNull()!! results = resultData.split("\n")
bufferIntensity = resultLines[2].split(' ')[1].trim() validString = parseResult(results)
led2BufferForDevice = bufferIntensity.toDoubleOrNull()!! }
bufferIntensity = resultLines[3].split(' ')[1].trim() } else {
led3BufferForDevice = bufferIntensity.toDoubleOrNull()!! results = resultData.split("\n")
bufferIntensity = resultLines[4].split(' ')[1].trim() validString = parseResult(results)
led4BufferForDevice = bufferIntensity.toDoubleOrNull()!! }
led1SampleForDevice = resultLines[5].split(' ')[1].trim().toDoubleOrNull()!! if (validString.isNotEmpty()) {
led2SampleForDevice = resultLines[6].split(' ')[1].trim().toDoubleOrNull()!! handleValidResult(validString)
led3SampleForDevice = resultLines[7].split(' ')[1].trim().toDoubleOrNull()!! }
led4SampleForDevice =
resultLines[8].split(' ')[1].split('\r')[0].trim().toDoubleOrNull()!!
processResult()
} }
} }
} }
private fun processResult() { private fun showStartSampleDialog() {
activity?.runOnUiThread {
UIUtils.createAlertDialog(requireContext(),
"Start Sample",
"Do you want to start sample reading?",
getString(R.string.no),
"Yes",
object : MyDialogListener {
override fun onClickNegativeButton() {}
override fun onClickPositiveButton() {
listenToHemoCube()
startSampleProcess()
}
})
}
}
private fun handleValidResult(validString: String) {
try { try {
hemoCubeViewModel.messages.postValue("processing result") val result = validString.split(" ")
val deviceLog = resultData if (result.size == 8) {
val deviceId = result[2]
val pInfo = requireActivity().packageManager.getPackageInfo( val led1BufferForDevice = result[3].toDoubleOrNull()
requireActivity().packageName, 0 val led2BufferForDevice = result[4].toDoubleOrNull()
) val led1Sample = result[5].toDoubleOrNull()
val version = pInfo.versionName val led2Sample = result[6].toDoubleOrNull()
val led1Average = log10(led1BufferForDevice?.div(led1Sample!!) ?: 0.0)
val led1Average = log10(led1BufferForDevice.div(led1SampleForDevice)) val led2Average = log10(led2BufferForDevice?.div(led2Sample!!) ?: 0.0)
val led2Average = log10(led2BufferForDevice.div(led2SampleForDevice)) val deviceRatio = led1Average / led2Average
val led3Average = log10(led3BufferForDevice.div(led3SampleForDevice)) val calculateRatio = calculateRatio(deviceRatio)
val led4Average = log10(led4BufferForDevice.div(led4SampleForDevice)) val classificationResult = findResult(calculateRatio)
val deviceRatio = led3Average / led1Average messages.postValue(classificationResult)
val bufferData = BufferCheckData(
if (led1BufferForDevice < Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(0) deviceId= deviceId,
?.get(0)!! || led2BufferForDevice < Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get( kitno = kitno,
1 led1Buffer = led1BufferForDevice,
led2Buffer = led2BufferForDevice,
led1Average = led1Average,
led2Average = led2Average,
led1Sample = led1Sample,
led2Sample = led2Sample,
deviceRatio = deviceRatio,
calculatedRatio = calculateRatio,
coefficients = currentDeviceData?.coefficients?.get(0).toString() + ", " + currentDeviceData?.coefficients?.get(1).toString(),
classificationResult = classificationResult,
deviceSerialNumber = sharedPreferences.getString(Constants.USER_ID, "").toString(),
testTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
) )
?.get(0)!! || led3BufferForDevice < Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get( hemoCubeViewModel.uploadHemoCubeResultToDatabaseforbuffercheckN(bufferData)
2
)
?.get(0)!! || led4BufferForDevice < Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(
3
)?.get(0)!!
) {
validationError = true
allErrorMessages += "Error: Invalid Test. Improper buffer reading (low)"
activity?.runOnUiThread {
binding.errorMessage.text =
"Error: Invalid Test. Improper buffer reading (low)" + "\n"
binding.errorMessage.visibility = View.VISIBLE
}
} }
if (led1BufferForDevice > Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(0)
?.get(1)!! || led2BufferForDevice > Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(
1
)
?.get(1)!! || led3BufferForDevice > Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(
2
)
?.get(1)!! || led4BufferForDevice > Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(
3
)?.get(1)!!
) {
validationError = true
allErrorMessages += "Error: Invalid Test. Improper buffer reading (high)" + "\n"
activity?.runOnUiThread {
binding.errorMessage.text =
"Error: Invalid Test. Improper buffer reading (high)"
binding.errorMessage.visibility = View.VISIBLE
}
}
var gradient = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(0)?.get(0)
var constant = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(0)?.get(1)
fittedAbs1 = gradient?.times(led1Average)?.plus(constant!!)!!
gradient = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(1)?.get(0)
constant = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(1)?.get(1)
fittedAbs2 = gradient?.times(led2Average)?.plus(constant!!)!!
gradient = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(2)?.get(0)
constant = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(2)?.get(1)
fittedAbs3 = gradient?.times(led3Average)?.plus(constant!!)!!
gradient = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(3)?.get(0)
constant = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(3)?.get(1)
fittedAbs4 = gradient?.times(led4Average)?.plus(constant!!)!!
_predictedDenovixRatio = fittedAbs3.div(fittedAbs1)
if (fittedAbs1 <= fittedAbs2) {
validationError = true
allErrorMessages += "Error: Invalid Test. Problem with de-oxygenation" + "\n"
activity?.runOnUiThread {
binding.errorMessage.text = "Error: Invalid Test. Problem with de-oxygenation"
binding.errorMessage.visibility = View.VISIBLE
}
}
if (fittedAbs1 < 0 || fittedAbs2 < 0 || fittedAbs3 < 0 || fittedAbs4 < 0) {
validationError = true
activity?.runOnUiThread {
binding.errorMessage.text = "Error: Negative Abs. Redo Kit check Reading"
binding.errorMessage.visibility = View.VISIBLE
}
}
val prdClassification = absorbanceBasedClassification(_predictedDenovixRatio)
hemoCubeViewModel.messages.postValue(prdClassification)
val bufferData = BufferCheckData(
_id = UUID.randomUUID().toString(),
deviceId = deviceHardwareId,
kitno = kitno,
appVersion = version,
led1Buffer = led1BufferForDevice,
led2Buffer = led2BufferForDevice,
led3Buffer = led3BufferForDevice,
led4Buffer = led4BufferForDevice,
led1Sample = led1SampleForDevice,
led2Sample = led2SampleForDevice,
led3Sample = led3SampleForDevice,
led4Sample = led4SampleForDevice,
led1Average = led1Average,
led2Average = led2Average,
led3Average = led3Average,
led4Average = led4Average,
abs1 = fittedAbs1,
abs2 = fittedAbs2,
abs3 = fittedAbs3,
abs4 = fittedAbs4,
deviceRatio = deviceRatio,
resultData = deviceLog,
predictedDenovixRatio = _predictedDenovixRatio,
prdClassification = prdClassification,
errorMessages = allErrorMessages,
coefficients = currentDeviceData?.coefficients?.get(0)
.toString() + ", " + currentDeviceData?.coefficients?.get(1).toString(),
deviceSerialNumber = sharedPreferences.getString(Constants.USER_ID, "").toString(),
testTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time),
batteryLevel = hemoCubeViewModel.getBatteryLevel().toString(),
batteryCapacity = hemoCubeViewModel.getBatteryCapacity(requireContext()).toString(),
batteryMaxCapacity = hemoCubeViewModel.getBatteryMaxCapacity(requireContext())
.toString(),
batteryTemperature = hemoCubeViewModel.getBatteryTemperature().toString(),
batteryVoltage = hemoCubeViewModel.getBatteryVoltage(requireContext()).toString()
)
hemoCubeViewModel.uploadHemoCubeResultToDatabaseForBufferCheck(isOnline, bufferData)
} catch (e: Exception) { } catch (e: Exception) {
Toast.makeText( Toast.makeText(
requireContext(), "Error while processing device data", Toast.LENGTH_SHORT requireContext(), "Error while processing device data", Toast.LENGTH_SHORT
@@ -385,48 +257,23 @@ class HemoCubeBufferCheckFragment : Fragment() {
private fun findResult(calculatedRatio: Double?): String { private fun findResult(calculatedRatio: Double?): String {
try { try {
hemoCubeViewModel.messages.postValue("result classification")
if (calculatedRatio != null) { if (calculatedRatio != null) {
if (calculatedRatio < 0.05) return "Inconclusive. Very low Absorbance - Repeat test with Higher Blood Volume" if (calculatedRatio < 0.085) return "Kit Failed"
if (calculatedRatio in 0.05..0.155) return "Normal" if (calculatedRatio in 0.085..0.155) return "Kit Passed"
if (calculatedRatio in 0.155..0.175) return "Negative Borderline. Repeat Test" if (calculatedRatio in 0.155..0.175) return "Kit Failed"
if (calculatedRatio in 0.175..0.22) return "Sickle Cell Trait" if (calculatedRatio in 0.175..0.22) return "Kit Failed"
if (calculatedRatio in 0.22..0.25) return "Positive for Sickle Cell. HPLC for Confirmation" if (calculatedRatio in 0.22..0.25) return "Kit Failed"
if (calculatedRatio in 0.25..0.35) return "Sickle Cell Disease" if (calculatedRatio in 0.25..0.35) return "Kit Failed"
if (calculatedRatio > 0.35) return "Inconclusive. Repeat with test with lower volume of blood" if (calculatedRatio > 0.35) return "Kit Failed"
} else { } else {
return "INVALID" return "NULL"
} }
} catch (e: Exception) { } catch (e: Exception) {
showToast(R.string.error_classification) showToast(R.string.error_classification)
Firebase.crashlytics.recordException(e) Firebase.crashlytics.recordException(e)
return "ERROR" return "ERROR"
} }
return "INVALID" return "NULL"
}
private fun absorbanceBasedClassification(predictedDenovixRatio: Double?): String {
try {
hemoCubeViewModel.messages.postValue("result classification")
if (predictedDenovixRatio != null) {
if (predictedDenovixRatio in 0.0..0.16) return "Kit Passed"
if (predictedDenovixRatio in 0.16..0.165) return "Kit Passed"
if (predictedDenovixRatio in 0.165..0.235) return "Kit Failed"
if (predictedDenovixRatio in 0.235..0.24) return "Kit Failed"
if (predictedDenovixRatio in 0.24..1.0) return "Kit Failed"
} else {
return "INVALID"
}
} catch (e: Exception) {
showToast("error while performing classification")
Firebase.crashlytics.recordException(e)
return "ERROR"
}
return "INVALID"
}
private fun showToast(message: String) {
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
} }
private fun showToast(messageResId: Int) { private fun showToast(messageResId: Int) {
@@ -435,11 +282,8 @@ class HemoCubeBufferCheckFragment : Fragment() {
private fun startBufferProcess() { private fun startBufferProcess() {
activity?.runOnUiThread {
binding.btnPlacebuffer.visibility = View.GONE
}
(activity as HemocubeBufferCheckActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.START_BUFFER_COMMAND, (activity as HemocubeBufferCheckActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.startBuffer,
object : UsbServiceListener { object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {} override fun onUsbRead(data: ByteArray?) {}
@@ -449,11 +293,8 @@ class HemoCubeBufferCheckFragment : Fragment() {
} }
private fun startSampleProcess() { private fun startSampleProcess() {
activity?.runOnUiThread {
binding.btnPlacebuffer.visibility = View.GONE
}
(activity as HemocubeBufferCheckActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.START_SAMPLE, (activity as HemocubeBufferCheckActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.startSample,
object : UsbServiceListener { object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {} override fun onUsbRead(data: ByteArray?) {}
@@ -462,28 +303,9 @@ class HemoCubeBufferCheckFragment : Fragment() {
}) })
} }
private fun getDeviceInfo() {
hemoCubeViewModel.progressBar.postValue(true)
(activity as HemocubeBufferCheckActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.DEVICE_CONFIGURATION_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
data?.let {
val stringData = String(it)
hemoCubeViewModel.messages.postValue(stringData)
binding.tvSubtitle4.text = stringData
}
}
override fun onUsbError(e: Exception?) {
hemoCubeViewModel.progressBar.postValue(false)
}
})
}
private fun fetchResult() { private fun fetchResult() {
(activity as HemocubeBufferCheckActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.PRINT_COMMAND, (activity as HemocubeBufferCheckActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.getSample,
object : UsbServiceListener { object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {} override fun onUsbRead(data: ByteArray?) {}
@@ -498,6 +320,21 @@ class HemoCubeBufferCheckFragment : Fragment() {
return coefficient1 * ratio + coefficient2 return coefficient1 * ratio + coefficient2
} }
private fun parseResult(frames: List<String>): String {
val lines = mutableListOf<String>()
for (frame in frames.reversed()) {
if (frame.contains("REND") || frame.contains("RESULT")) lines += frame
if (frame.contains("RESULT")) {
break
}
}
val line = lines.reversed().joinToString("").trim()
if (line.contains("RESULT") && line.split(" ").size == 8) {
return line
}
return ""
}
private fun isSerialValid(s: String): Boolean { private fun isSerialValid(s: String): Boolean {
if (s.length != 17) { if (s.length != 17) {
binding.nameEditText.error = getString(R.string.invalid_kit) binding.nameEditText.error = getString(R.string.invalid_kit)
@@ -505,4 +342,13 @@ class HemoCubeBufferCheckFragment : Fragment() {
} }
return true return true
} }
private fun isValidResult(line: String): String {
return if (line.contains("RESULT") && line.split(" ").size == 8) {
line
} else {
""
}
}
} }

View File

@@ -1,6 +1,5 @@
package com.example.hpostesting.presentation.buffercheck package com.example.hpostesting.presentation.buffercheck
import android.annotation.SuppressLint
import android.app.PendingIntent import android.app.PendingIntent
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.ComponentName import android.content.ComponentName
@@ -125,22 +124,21 @@ open class HemocubeBufferCheckActivity : AppCompatActivity() {
} }
@SuppressLint("MutableImplicitPendingIntent")
private fun requestUserPermission(manager: UsbManager, device: UsbDevice) { private fun requestUserPermission(manager: UsbManager, device: UsbDevice) {
val mPendingIntent: PendingIntent = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) { val mPendingIntent: PendingIntent = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
PendingIntent.getBroadcast( PendingIntent.getBroadcast(
this, 0, Intent(Constants.HEMOCUBE_USB_PERMISSION), PendingIntent.FLAG_MUTABLE this, 0, Intent(Constants.HOMOCUBE_USB_PERMISSION), PendingIntent.FLAG_MUTABLE
) )
} else { } else {
PendingIntent.getBroadcast( PendingIntent.getBroadcast(
this, this,
0, 0,
Intent(Constants.HEMOCUBE_USB_PERMISSION), Intent(Constants.HOMOCUBE_USB_PERMISSION),
PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
) )
} }
val filter = IntentFilter(Constants.HEMOCUBE_USB_PERMISSION) val filter = IntentFilter(Constants.HOMOCUBE_USB_PERMISSION)
registerReceiver(broadcastReceiver, filter) registerReceiver(broadcastReceiver, filter)
manager.requestPermission(device, mPendingIntent) manager.requestPermission(device, mPendingIntent)
} }

View File

@@ -1,182 +0,0 @@
package com.example.hpostesting.presentation.calibration
import android.annotation.SuppressLint
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.ServiceConnection
import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbDeviceConnection
import android.hardware.usb.UsbManager
import android.os.Bundle
import android.os.IBinder
import android.util.Log
import android.view.Menu
import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.get
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.presentation.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.ActivityCalibrationBinding
@AndroidEntryPoint
class CalibrationActivity: AppCompatActivity() {
private lateinit var binding: ActivityCalibrationBinding
val viewModel: CalibrationViewModel by viewModels()
private var myMenu: Menu? = null
private lateinit var mDriver: UsbSerialDriver
private var mConnection: UsbDeviceConnection? = null
lateinit var mService: UsbService
private val TAG = "Calibration"
private val broadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
synchronized(this) {
val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
device?.apply {
connectUsb(true)
DataHolder.usbConnected.postValue(true)
}
} else {
onErrorReported("permission denied for device")
DataHolder.usbConnected.postValue(true)
}
}
}
}
private val connection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) {
val binder = service as UsbService.UsbServiceBinder
mService = binder.getService()
viewModel.isServiceConnected = true
mConnection.let { mService.connect(mDriver, mConnection!!) }
moveToNext()
}
override fun onServiceDisconnected(arg0: ComponentName) {
viewModel.isServiceConnected = false
}
}
override fun attachBaseContext(newBase: Context?) {
val languageCode = LanguageManager.getSavedLanguage(newBase!!)
LanguageManager.setLocale(newBase, languageCode)
super.attachBaseContext(newBase)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityCalibrationBinding.inflate(layoutInflater)
setContentView(binding.root)
// setSupportActionBar(binding.myToolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
setupListener()
connectUsb(false)
}
private fun setupListener() {
DataHolder.usbConnected.observe(this) {
Log.d("USB OBSERVE", "HemoCube called -> $it")
if (it) {
myMenu?.get(0)?.icon =
ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_24)
} else {
myMenu?.get(0)?.icon =
ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_off_24)
Toast.makeText(this, "Device is Disconnected", Toast.LENGTH_SHORT).show()
}
}
}
open fun connectUsb(permissionGranted: Boolean) {
Log.d(TAG, "connectUsb() called, permission variable = $permissionGranted")
val manager = getSystemService(Context.USB_SERVICE) as UsbManager
val availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager)
if (availableDrivers.isEmpty()) {
onErrorReported("No Device is Connected")
} else {
mDriver = availableDrivers[0]
mConnection = manager.openDevice(mDriver.device)
if (mConnection == null) {
requestUserPermission(manager, mDriver.device)
} else {
setupService()
}
}
}
fun onErrorReported(msg: String) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
if (!isFinishing) onBackPressed()
}
private fun moveToNext() {
if (supportFragmentManager.isDestroyed) return
supportFragmentManager.beginTransaction().replace(binding.fgCalibration.id, CalibrationFragment())
.commit()
}
@SuppressLint("MutableImplicitPendingIntent")
private fun requestUserPermission(manager: UsbManager, device: UsbDevice) {
val mPendingIntent: PendingIntent = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
PendingIntent.getBroadcast(
this, 0, Intent(Constants.HEMOCUBE_USB_PERMISSION), PendingIntent.FLAG_MUTABLE
)
} else {
PendingIntent.getBroadcast(
this,
0,
Intent(Constants.HEMOCUBE_USB_PERMISSION),
PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
)
}
val filter = IntentFilter(Constants.HEMOCUBE_USB_PERMISSION)
registerReceiver(broadcastReceiver, filter)
manager.requestPermission(device, mPendingIntent)
}
fun setupService() {
val intent = Intent(this, UsbService::class.java)
bindService(intent, connection, Context.BIND_AUTO_CREATE)
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.my_menu, menu)
return true
}
override fun onDestroy() {
super.onDestroy()
if (viewModel.isServiceConnected) {
mService.disconnect()
unbindService(connection)
viewModel.isServiceConnected = false
}
}
}

View File

@@ -1,278 +0,0 @@
package com.example.hpostesting.presentation.calibration
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.MutableLiveData
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.model.calibration.CalibrationData
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.presentation.UsbServiceListener
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.ktx.Firebase
import `in`.sminnovations.hpostesting.databinding.FragmentCalibrationBinding
class CalibrationFragment: Fragment() {
private lateinit var binding: FragmentCalibrationBinding
private val calibrationViewModel: CalibrationViewModel by activityViewModels()
private lateinit var sharedPreferences: SharedPreferences
private var currentDeviceData: DeviceData? = null
private var resultData: String = ""
private val messages = MutableLiveData<String>()
private var startListening = MutableLiveData(false)
private lateinit var calibrationData: CalibrationData
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
): View {
binding = FragmentCalibrationBinding.inflate(inflater, container, false)
sharedPreferences =
requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initViews()
observeViewModel()
loadSavedCalibration()
}
private fun initViews() {
binding.btnSubmit.visibility = View.GONE
listenToHemoCube()
getDeviceId()
binding.btnSubmit.setOnClickListener {
binding.btnSubmit.visibility = View.GONE
saveCalibration()
}
val etLed1Slope = binding.etLed1Slope
etLed1Slope.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable?) {
calibrationData.led1Slope = s.toString().toDoubleOrNull() ?: 0.0
}
})
val etLed1Intercept = binding.etLed1Intercept
etLed1Intercept.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable?) {
calibrationData.led1Intercept = s.toString().toDoubleOrNull() ?: 0.0
}
})
val etLed2Slope = binding.etLed2Slope
etLed2Slope.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable?) {
calibrationData.led2Slope = s.toString().toDoubleOrNull() ?: 0.0
}
})
val etLed2Intercept = binding.etLed2Intercept
etLed2Intercept.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable?) {
calibrationData.led2Intercept = s.toString().toDoubleOrNull() ?: 0.0
}
})
val etLed3Slope = binding.etLed3Slope
etLed3Slope.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable?) {
calibrationData.led3Slope = s.toString().toDoubleOrNull() ?: 0.0
}
})
val etLed3Intercept = binding.etLed3Intercept
etLed3Intercept.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable?) {
calibrationData.led3Intercept = s.toString().toDoubleOrNull() ?: 0.0
}
})
val etLed4Slope = binding.etLed4Slope
etLed4Slope.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable?) {
calibrationData.led4Slope = s.toString().toDoubleOrNull() ?: 0.0
}
})
val etLed4Intercept = binding.etLed4Intercept
etLed4Intercept.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable?) {
calibrationData.led4Intercept = s.toString().toDoubleOrNull() ?: 0.0
}
})
}
private fun loadSavedCalibration() {
calibrationData = calibrationViewModel.loadSavedCalibrationData()
activity?.runOnUiThread() {
binding.etLed1Slope.text =
Editable.Factory.getInstance().newEditable(calibrationData.led1Slope.toString())
binding.etLed1Intercept.text =
Editable.Factory.getInstance().newEditable(calibrationData.led1Intercept.toString())
binding.etLed2Slope.text =
Editable.Factory.getInstance().newEditable(calibrationData.led2Slope.toString())
binding.etLed2Intercept.text =
Editable.Factory.getInstance().newEditable(calibrationData.led2Intercept.toString())
binding.etLed3Slope.text =
Editable.Factory.getInstance().newEditable(calibrationData.led3Slope.toString())
binding.etLed3Intercept.text =
Editable.Factory.getInstance().newEditable(calibrationData.led3Intercept.toString())
binding.etLed4Slope.text =
Editable.Factory.getInstance().newEditable(calibrationData.led4Slope.toString())
binding.etLed4Intercept.text =
Editable.Factory.getInstance().newEditable(calibrationData.led4Intercept.toString())
}
}
private fun saveCalibration() {
if (calibrationViewModel.saveCalibration(calibrationData)) {
startActivity(Intent(requireActivity(), DashboardActivity::class.java))
}
}
private fun observeViewModel() {
calibrationViewModel.deviceData.observe(viewLifecycleOwner) {
currentDeviceData = it
}
messages.observe(viewLifecycleOwner) {
binding.tvSubtitle4.text = it
}
calibrationViewModel.fireBaseUpload.observe(viewLifecycleOwner) { result ->
if (result == "Success") {
showToast("Auto Dac data uploaded successfully")
}
if (result == "Local") {
showToast("Auto Dac uploading failed, note it down manually")
}
binding.progressBar.visibility = View.GONE
}
}
private fun getDeviceId() {
calibrationViewModel.progressBar.postValue(true)
(activity as CalibrationActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.DEVICE_CONFIGURATION_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
data?.let {
val stringData = String(it)
calibrationViewModel.messages.postValue(stringData)
binding.tvSubtitle4.text = stringData
}
}
override fun onUsbError(e: Exception?) {
calibrationViewModel.progressBar.postValue(false)
}
})
}
private fun listenToHemoCube() {
val fullReadOutput = StringBuilder()
startListening.postValue(true)
try {
(activity as CalibrationActivity).mService.listenToHemoCube(object :
UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
data?.let {
val stringData = String(it)
calibrationViewModel.messages.postValue(stringData)
fullReadOutput.append(stringData)
resultData += stringData
binding.tvSubtitle4.text = resultData
if (stringData.contains("SN")) {
val slData = stringData.split(" ")
if (slData.size > 1) {
val hardwareId = slData[1].trim()
with(sharedPreferences.edit()) {
putString(Constants.DEVICE_ID, hardwareId)
apply()
}
}
activity?.runOnUiThread {
binding.btnSubmit.visibility = View.VISIBLE
}
}
}
}
override fun onUsbError(e: Exception?) {
calibrationViewModel.progressBar.postValue(false)
}
})
} catch (e: Exception) {
Firebase.crashlytics.recordException(e)
}
}
private fun showToast(message: String) {
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
}
}

View File

@@ -1,90 +0,0 @@
package com.example.hpostesting.presentation.calibration
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.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.calibration.CalibrationData
import com.example.hpostesting.data.model.diagnostics.DiagnosticsData
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.repository.Repository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class CalibrationViewModel @Inject constructor(
private val repository: Repository,
context: Context
) : ViewModel() {
var isServiceConnected = false
val progressBar = MutableLiveData(false)
val messages = MutableLiveData<String>()
private val sharedPreference: SharedPreferences =
context.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
// private val _networkStatusLiveData = NetworkStatusLiveData(context)
val deviceData = MutableLiveData<DeviceData?>()
// val networkStatusLiveData: LiveData<Boolean>
// get() = _networkStatusLiveData
val fireBaseUpload = MutableLiveData<String>()
val savedCalibrationData = MutableLiveData<String>()
fun loadSavedCalibrationData(): CalibrationData {
val calibrationData = CalibrationData()
val sharedPreferenceKeys = arrayOf(
"LED1SLOPE", "LED1INTERCEPT",
"LED2SLOPE", "LED2INTERCEPT",
"LED3SLOPE", "LED3INTERCEPT",
"LED4SLOPE", "LED4INTERCEPT",
"CALIBRATED_AT"
)
with(calibrationData) {
led1Slope = sharedPreference.getString(sharedPreferenceKeys[0], "")?.toDoubleOrNull() ?: 0.0
led1Intercept = sharedPreference.getString(sharedPreferenceKeys[1], "")?.toDoubleOrNull() ?: 0.0
led2Slope = sharedPreference.getString(sharedPreferenceKeys[2], "")?.toDoubleOrNull() ?: 0.0
led2Intercept = sharedPreference.getString(sharedPreferenceKeys[3], "")?.toDoubleOrNull() ?: 0.0
led3Slope = sharedPreference.getString(sharedPreferenceKeys[4], "")?.toDoubleOrNull() ?: 0.0
led3Intercept = sharedPreference.getString(sharedPreferenceKeys[5], "")?.toDoubleOrNull() ?: 0.0
led4Slope = sharedPreference.getString(sharedPreferenceKeys[6], "")?.toDoubleOrNull() ?: 0.0
led4Intercept = sharedPreference.getString(sharedPreferenceKeys[7], "")?.toDoubleOrNull() ?: 0.0
calibratedAt = sharedPreference.getString(sharedPreferenceKeys[8], "") ?: ""
}
return calibrationData
}
fun saveCalibration(calibrationData: CalibrationData): Boolean {
try {
with(sharedPreference.edit()) {
putString("LED1SLOPE", calibrationData.led1Slope.toString())
putString("LED1INTERCEPT", calibrationData.led1Intercept.toString())
putString("LED2SLOPE", calibrationData.led2Slope.toString())
putString("LED2INTERCEPT", calibrationData.led2Intercept.toString())
putString("LED3SLOPE", calibrationData.led3Slope.toString())
putString("LED3INTERCEPT", calibrationData.led3Intercept.toString())
putString("LED4SLOPE", calibrationData.led4Slope.toString())
putString("LED4INTERCEPT", calibrationData.led4Intercept.toString())
putString("CALIBRATED_AT", calibrationData.calibratedAt)
apply()
}
return true
} catch (e: Exception) {
return false
}
}
}

View File

@@ -4,6 +4,7 @@ import android.app.DownloadManager
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.IntentFilter
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
@@ -20,9 +21,9 @@ import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController import androidx.navigation.ui.setupWithNavController
import com.example.hpostesting.data.Result import com.example.hpostesting.data.Result
import com.example.hpostesting.data.constant.LanguageManager import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.presentation.NatsManager
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.google.android.material.navigation.NavigationView import com.google.android.material.navigation.NavigationView
import com.google.firebase.appdistribution.FirebaseAppDistribution import com.google.firebase.appdistribution.FirebaseAppDistribution
import com.google.firebase.appdistribution.FirebaseAppDistributionException import com.google.firebase.appdistribution.FirebaseAppDistributionException
import com.google.firebase.crashlytics.FirebaseCrashlytics import com.google.firebase.crashlytics.FirebaseCrashlytics
@@ -30,21 +31,15 @@ import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityDashboardBinding import `in`.sminnovations.hpostesting.databinding.ActivityDashboardBinding
import okhttp3.ResponseBody import okhttp3.ResponseBody
import java.io.File import java.io.File
open interface IDataCollector {
fun setConnect(connect: Boolean)
fun setResponse(response: String)
}
@AndroidEntryPoint @AndroidEntryPoint
class DashboardActivity : AppCompatActivity(), IDataCollector { class DashboardActivity : AppCompatActivity() {
private lateinit var appBarConfiguration: AppBarConfiguration private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var binding: ActivityDashboardBinding private lateinit var binding: ActivityDashboardBinding
var responses: String = ""
lateinit var nats: NatsManager
private var downloadId: Long = 0 private var downloadId: Long = 0
// TODO: Remove hemocube viewmodel
private val hemocubeViewModel: HemoCubeViewModel by viewModels() private val hemocubeViewModel: HemoCubeViewModel by viewModels()
override fun attachBaseContext(newBase: Context?) { override fun attachBaseContext(newBase: Context?) {
@@ -59,36 +54,37 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
binding = ActivityDashboardBinding.inflate(layoutInflater) binding = ActivityDashboardBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
setSupportActionBar(binding.appBarDashboard.toolbar) setSupportActionBar(binding.appBarDashboard.toolbar)
nats = NatsManager(this)
nats.connect()
nats.pub("server.hpos.HCV-000-3001.ping", "THIS IS A TEST MSG")
hemocubeViewModel.deviceUpdate.observe(this) { result -> hemocubeViewModel.deviceUpdate.observe(this) { result ->
when (result) { when (result) {
is Result.Success -> { is Result.Success -> {
// Handle success // val apkUrl = result.data
val apkUrl = result.data val apkUrl = "https://dl.dropboxusercontent.com/s/fi/1c3nn7t0co431hicl3hrt/app-debug.apk?rlkey=e4uf13ty1dpcked614vy1aaqp&dl=0"
// val apkUrl = "https://dl.dropboxusercontent.com/s/fi/1c3nn7t0co431hicl3hrt/app-debug.apk?rlkey=e4uf13ty1dpcked614vy1aaqp&dl=0"
initiateUpdate(apkUrl.toString()) initiateUpdate(apkUrl.toString())
Log.d("ApI", "APK URL: $apkUrl") Log.d("ApI", "APK URL For App Update: $apkUrl")
Toast.makeText( Toast.makeText(
this, this,
"APK UPLOAD ${result.data}", "APK UPLOAD ${result.data}",
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
// The APK URL LiveData will be updated automatically
} }
is Result.Error -> { is Result.Error -> {
result.exception.let { message -> result.exception.let { message ->
Toast.makeText(this, "An error occurred On Updating App: $message", Toast.LENGTH_LONG) Toast.makeText(this, "An error occurred On Updating App: $message", Toast.LENGTH_LONG)
.show() .show()
} }
} }
is Result.Loading -> { is Result.Loading -> {
} }
else -> { else -> {
} }
} }
} }
@@ -105,6 +101,9 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
) )
setupActionBarWithNavController(navController, appBarConfiguration) setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController) navView.setupWithNavController(navController)
} }
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
@@ -119,8 +118,12 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
} }
private fun initiateUpdate(responseBody: String) { private fun initiateUpdate(responseBody: String) {
// Extract the URL from the ResponseBody
val apkUrl = responseBody val apkUrl = responseBody
// Check if the extracted APK URL is valid
if (!isValidHttpUrl(apkUrl)) { if (!isValidHttpUrl(apkUrl)) {
// Handle the case where the URL is not valid
return return
} }
@@ -134,12 +137,18 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
downloadId = downloadManager.enqueue(request) downloadId = downloadManager.enqueue(request)
// Register a BroadcastReceiver to receive the download complete event // Register a BroadcastReceiver to receive the download complete event
// val filter = IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE) val filter = IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)
// registerReceiver(downloadReceiver, filter) registerReceiver(downloadReceiver, filter)
} }
// Function to check if a URL has a valid HTTP/HTTPS scheme
// Function to extract the APK URL from the ResponseBody
private fun extractApkUrl(responseBody: ResponseBody): String { private fun extractApkUrl(responseBody: ResponseBody): String {
// Assuming your ResponseBody contains the APK URL as a string
return responseBody.string() return responseBody.string()
} }
// Function to check if a URL has a valid HTTP/HTTPS scheme
private fun isValidHttpUrl(url: String): Boolean { private fun isValidHttpUrl(url: String): Boolean {
return url.startsWith("http://") || url.startsWith("https://") return url.startsWith("http://") || url.startsWith("https://")
} }
@@ -147,6 +156,7 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
override fun onReceive(context: Context?, intent: Intent?) { override fun onReceive(context: Context?, intent: Intent?) {
val id = intent?.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1) val id = intent?.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)
if (id == downloadId) { if (id == downloadId) {
// Install the downloaded APK
installApk() installApk()
} }
} }
@@ -179,9 +189,10 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
// unregisterReceiver(downloadReceiver) unregisterReceiver(downloadReceiver)
} }
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
@@ -222,15 +233,6 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
} }
} }
override fun setConnect(connect: Boolean) {
if(connect){
Log.i("NATS Connection", connect.toString())
}
}
override fun setResponse(response: String) {
responses = responses+response+"\n"
println(responses)
}
} }

View File

@@ -1,67 +1,38 @@
package com.example.hpostesting.presentation.dashboard package com.example.hpostesting.presentation.dashboard
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.presentation.autodac.AutoDacActivity
import com.example.hpostesting.presentation.buffercheck.HemocubeBufferCheckActivity import com.example.hpostesting.presentation.buffercheck.HemocubeBufferCheckActivity
import com.example.hpostesting.presentation.calibration.CalibrationActivity
import com.example.hpostesting.presentation.deviceprovision.DeviceProvisionActivity
import com.example.hpostesting.presentation.deviceinfo.DeviceActivity
import com.example.hpostesting.presentation.diagnostics.DiagnosticsActivity import com.example.hpostesting.presentation.diagnostics.DiagnosticsActivity
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import `in`.sminnovations.hpostesting.databinding.FragmentGalleryBinding import `in`.sminnovations.hpostesting.databinding.FragmentGalleryBinding
class GalleryFragment : Fragment() { class GalleryFragment : Fragment() {
private var _binding: FragmentGalleryBinding? = null private var _binding: FragmentGalleryBinding? = null
private lateinit var sharedPreferences: SharedPreferences
private var userid = ""
// This property is only valid between onCreateView and // This property is only valid between onCreateView and
// onDestroyView. // onDestroyView.
private val binding get() = _binding!! private val binding get() = _binding!!
private lateinit var sharedPreference: SharedPreferences
private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels()
@SuppressLint("SetTextI18n")
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View { ): View {
// val galleryViewModel = // val galleryViewModel =
// ViewModelProvider(this).get(GalleryViewModel::class.java) // ViewModelProvider(this).get(GalleryViewModel::class.java)
_binding = FragmentGalleryBinding.inflate(inflater, container, false) _binding = FragmentGalleryBinding.inflate(inflater, container, false)
val root: View = binding.root val root: View = binding.root
sharedPreferences =
requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
sharedPreference = requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
if (sharedPreference.getString(
Constants.USER_ID, ""
) == "FACTORY" && sharedPreference.getString(Constants.DEVICE_ID_API, "").toString()
.isEmpty() && sharedPreference.getString(Constants.DEVICE_PASSWORD_API, "")
.toString().isEmpty()
) {
binding.btnDeviceProvision.visibility = View.VISIBLE
} else {
binding.btnDeviceProvision.visibility = View.GONE
}
binding.btnDeviceProvision.setOnClickListener {
startActivity(Intent(requireContext(), DeviceProvisionActivity::class.java))
}
// val textView: TextView = binding.textGallery
// galleryViewModel.text.observe(viewLifecycleOwner) {
//// textView.text = it
// }
binding.btnSubmit.setOnClickListener { binding.btnSubmit.setOnClickListener {
startActivity(Intent(requireContext(), HemocubeBufferCheckActivity::class.java)) startActivity(Intent(requireContext(), HemocubeBufferCheckActivity::class.java))
} }
@@ -70,20 +41,6 @@ class GalleryFragment : Fragment() {
startActivity(Intent(requireContext(), DiagnosticsActivity::class.java)) startActivity(Intent(requireContext(), DiagnosticsActivity::class.java))
} }
binding.btnAutoDac.setOnClickListener {
startActivity(Intent(requireContext(), AutoDacActivity::class.java))
}
binding.btnCalibration.setOnClickListener {
startActivity(Intent(requireContext(), CalibrationActivity::class.java))
}
binding.btnDeviceInfo.setOnClickListener {
startActivity(Intent(requireContext(), DeviceActivity::class.java))
}
userid = sharedPreferences.getString(Constants.USER_ID, "").toString()
binding.tvSubtitle4.text = "Login ID : ${userid}"
return root return root
} }

View File

@@ -9,7 +9,6 @@ import android.content.SharedPreferences
import android.os.BatteryManager import android.os.BatteryManager
import android.os.Bundle import android.os.Bundle
import android.util.Base64 import android.util.Base64
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@@ -22,8 +21,6 @@ import com.example.hpostesting.data.Result
import com.example.hpostesting.data.constant.Constants import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.model.login.LoginRequest import com.example.hpostesting.data.model.login.LoginRequest
import com.example.hpostesting.data.model.login.LoginResponse import com.example.hpostesting.data.model.login.LoginResponse
import com.example.hpostesting.data.model.molbioresult.MolbioV2Result
import com.example.hpostesting.data.model.molbioresult.MolbioV2ResultRequest
import com.example.hpostesting.data.model.patient.HemoCubeTestData import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.UserData import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.data.model.updates.CheckUpdateRequest import com.example.hpostesting.data.model.updates.CheckUpdateRequest
@@ -31,7 +28,6 @@ import com.example.hpostesting.data.model.updates.DeviceUpdateRequest
import com.example.hpostesting.presentation.KitScanActivity import com.example.hpostesting.presentation.KitScanActivity
import com.example.hpostesting.presentation.adapter.OfflineUserListAdapter import com.example.hpostesting.presentation.adapter.OfflineUserListAdapter
import com.example.hpostesting.presentation.adapter.UserListAdapter import com.example.hpostesting.presentation.adapter.UserListAdapter
import com.example.hpostesting.presentation.assurance.AssuranceControlsActivity
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.example.hpostesting.presentation.testRight.TestRightViewModel import com.example.hpostesting.presentation.testRight.TestRightViewModel
import com.firebase.ui.firestore.FirestoreRecyclerOptions import com.firebase.ui.firestore.FirestoreRecyclerOptions
@@ -43,19 +39,11 @@ import com.google.firebase.perf.ktx.performance
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentHomeBinding import `in`.sminnovations.hpostesting.databinding.FragmentHomeBinding
import okhttp3.ResponseBody
import org.json.JSONObject import org.json.JSONObject
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.net.URL
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Calendar import java.util.Calendar
import java.util.Date import java.util.Date
import java.util.Locale import java.util.Locale
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
@AndroidEntryPoint @AndroidEntryPoint
class HomeFragment : Fragment() { class HomeFragment : Fragment() {
@@ -64,15 +52,15 @@ class HomeFragment : Fragment() {
private val viewModel: TestRightViewModel by activityViewModels() private val viewModel: TestRightViewModel by activityViewModels()
private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels() private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels()
private lateinit var rvAdapter: UserListAdapter private lateinit var rvAdapter: UserListAdapter
private lateinit var sharedPreferences: SharedPreferences
private var batLevel: Int = private var batLevel: Int =
0 // Initialize with a default value, or obtain the actual battery level 0 // Initialize with a default value, or obtain the actual battery level
private lateinit var adapter: OfflineUserListAdapter private lateinit var adapter: OfflineUserListAdapter
private val homeViewModel: HemoCubeViewModel by activityViewModels()
private var isTokenAvailable = false
private lateinit var sharedPreference: SharedPreferences private lateinit var sharedPreference: SharedPreferences
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?, inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? { ): View? {
_binding = FragmentHomeBinding.inflate(inflater, container, false) _binding = FragmentHomeBinding.inflate(inflater, container, false)
@@ -83,7 +71,8 @@ class HomeFragment : Fragment() {
return super.onCreateView(inflater, container, savedInstanceState) return super.onCreateView(inflater, container, savedInstanceState)
} }
sharedPreference = requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE) sharedPreference =
requireContext().getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE)
DataHolder.selectedTest = null DataHolder.selectedTest = null
return binding.root return binding.root
@@ -91,13 +80,6 @@ class HomeFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
if (sharedPreference.getString(Constants.USER_ID, "").toString() == "ADMIN") {
binding.labelQuickCapture.visibility = View.VISIBLE
binding.btnQuickCapture.visibility = View.VISIBLE
}
checkUnprocessedCSVData()
viewModel.allUserData.observe(viewLifecycleOwner) { userData -> viewModel.allUserData.observe(viewLifecycleOwner) { userData ->
deleteIncompleteRegistrations(userData) deleteIncompleteRegistrations(userData)
} }
@@ -117,9 +99,8 @@ class HomeFragment : Fragment() {
binding.rvOrderOffline.adapter = adapter binding.rvOrderOffline.adapter = adapter
} }
} }
viewModel.networkStatusLiveData?.observe(viewLifecycleOwner) { isConnected -> viewModel.networkStatusLiveData.observe(viewLifecycleOwner) { isConnected ->
if (isConnected) { if (isConnected) {
binding.internetAvailableCL.visibility = View.VISIBLE binding.internetAvailableCL.visibility = View.VISIBLE
binding.internetNotAvailableCL.visibility = View.GONE binding.internetNotAvailableCL.visibility = View.GONE
loadUserData() loadUserData()
@@ -146,32 +127,9 @@ class HomeFragment : Fragment() {
binding.btnLogout.setOnClickListener { binding.btnLogout.setOnClickListener {
logoutUser(requireContext()) logoutUser(requireContext())
} }
binding.uploadData.setOnClickListener { binding.uploadData.setOnClickListener {
showUploadDialog(requireContext()) showUploadDialog(requireContext())
} }
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userData ->
val btnSaveLocalVisibility =
if (userData.any { it.testStatus == true }) View.VISIBLE else View.GONE
binding.btnSaveLocal.visibility = btnSaveLocalVisibility
binding.btnSaveLocal.setOnClickListener {
if (btnSaveLocalVisibility == View.VISIBLE) {
// Execute the action when the button is visible (testStatus is true for at least one user)
showDownloadDialog(requireContext())
} else {
// Handle the case when the button is not visible
Toast.makeText(
requireContext(),
"No test details stored locally",
Toast.LENGTH_SHORT
).show()
}
}
}
binding.btnNewKit.setOnClickListener { binding.btnNewKit.setOnClickListener {
with(sharedPreference.edit()) { with(sharedPreference.edit()) {
putString(Constants.KIT_NUMBER, "") putString(Constants.KIT_NUMBER, "")
@@ -181,63 +139,55 @@ class HomeFragment : Fragment() {
startActivity(Intent(requireContext(), KitScanActivity::class.java)) startActivity(Intent(requireContext(), KitScanActivity::class.java))
requireActivity().finish() requireActivity().finish()
} }
binding.btnQuickCapture.setOnClickListener {
DataHolder.hemoCubeTestData = HemoCubeTestData()
val i = Intent(
requireContext().applicationContext, AssuranceControlsActivity::class.java
)
startActivity(i)
}
binding.downloadCSV.setOnClickListener {
showDownloadDialog(requireContext())
}
} }
private fun checkForTokenAndUpdate() { private fun checkForTokenAndUpdate() {
val accessToken = sharedPreference.getString(Constants.ACCESS_TOKEN, "").toString() val accessToken = sharedPreference.getString(Constants.ACCESS_TOKEN, "").toString()
val password = sharedPreference.getString(Constants.DEVICE_PASSWORD_API, "").toString() val natsToken = sharedPreference.getString(Constants.NATS_TOKEN, "").toString()
val userID = sharedPreference.getString(Constants.DEVICE_ID_API, "").toString() if (accessToken.isEmpty() && natsToken.isEmpty()) {
if (userID.isNotEmpty() && password.isNotEmpty()) { hemoCubeViewModel.login(createLoginRequestData())
if (accessToken.isEmpty()) {
hemoCubeViewModel.login(createLoginRequestData(userID, password))
} else {
if (isTokenExpired(accessToken)) {
hemoCubeViewModel.login(createLoginRequestData(userID, password))
} else {
isTokenAvailable = true
hemoCubeViewModel.deviceUpdate(createDeviceUpdateRequestData())
hemoCubeViewModel.uploadLogs()
hemoCubeViewModel.startPeriodicCheckUpdate()
hemoCubeViewModel.downloadClientCertificate()
}
}
} else { } else {
Toast.makeText( if (isTokenExpired(accessToken)) {
requireContext(), hemoCubeViewModel.login(createLoginRequestData())
"Contact Help and get your device provision done", } else {
Toast.LENGTH_SHORT hemoCubeViewModel.checkUpdate(createCheckUpdateRequestData())
).show() hemoCubeViewModel.uploadLogs()
hemoCubeViewModel.deviceUpdate(createDeviceRequestData())
}
} }
hemoCubeViewModel.loginResponse.observe(viewLifecycleOwner) { response -> hemoCubeViewModel.loginResponse.observe(viewLifecycleOwner) { response ->
when (response) { when (response) {
is Result.Success -> { is Result.Success -> {
updateTokens(response) updateTokens(response)
checkForTokenAndUpdate()
} }
is Result.Error -> { is Result.Error -> {
response.exception.let { message -> response.exception.let { message ->
Toast.makeText( Toast.makeText(activity, "An error occurred: $message", Toast.LENGTH_LONG)
activity, .show()
"An error occurred in login: $message", }
Toast.LENGTH_LONG }
)
is Result.Loading -> {
}
else -> {}
}
}
hemoCubeViewModel.checkUpdate.observe(viewLifecycleOwner) { response ->
when (response) {
is Result.Success -> {
Toast.makeText(
requireContext(), response.data.data?.version, Toast.LENGTH_SHORT
).show()
}
is Result.Error -> {
response.exception.let { message ->
Toast.makeText(activity, "An error occurred: $message", Toast.LENGTH_LONG)
.show() .show()
} }
} }
@@ -262,88 +212,21 @@ class HomeFragment : Fragment() {
is Result.Error -> { is Result.Error -> {
response.exception.let { message -> response.exception.let { message ->
Toast.makeText(
activity,
"An error occurred in uploading logs: $message",
Toast.LENGTH_LONG
)
.show()
}
}
is Result.Loading -> {
}
else -> {}
}
}
hemoCubeViewModel.downloadcertificate.observe(viewLifecycleOwner) { response ->
when (response) {
is Result.Success -> {
val url = response.data
val fileName = "nats_certificate.zip"
val downloadDirectory = "NATS"
val file = downloadFile(url, requireContext(), fileName, downloadDirectory)
Toast.makeText(requireContext(), "NATS certificate Downloaded", Toast.LENGTH_SHORT).show()
val unzipDirectoryPath = requireContext().getExternalFilesDir(null)?.absolutePath + "/$downloadDirectory"
unzip(file.absolutePath, unzipDirectoryPath)
Toast.makeText(requireContext(), "NATS certificate Extracted", Toast.LENGTH_SHORT).show()
}
is Result.Error -> {
response.exception.let { message ->
Toast.makeText(
activity,
"An error occurred in nats download: $message",
Toast.LENGTH_LONG
)
.show()
}
}
is Result.Loading -> {
}
else -> {}
}
}
hemoCubeViewModel.resultUpload.observe(viewLifecycleOwner) {
when (it) {
is Result.Success -> {
it.data.data?.forEach { id ->
id.rawData?.let { it1 ->
hemoCubeViewModel.updateMolbioFlag(
it1._id
)
}
}
}
is Result.Error -> {
binding.btnSubmit.visibility = View.VISIBLE
//Remove this line of code while deploying to IOCL
it.exception.let { message ->
Toast.makeText(activity, "An error occurred: $message", Toast.LENGTH_LONG) Toast.makeText(activity, "An error occurred: $message", Toast.LENGTH_LONG)
.show() .show()
} }
} }
is Result.Loading -> {
}
else -> {} else -> {}
} }
} }
} }
fun isTokenExpired(token: String): Boolean {
private fun isTokenExpired(token: String): Boolean {
val parts = token.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() val parts = token.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val decodedPayload = String(Base64.decode(parts[1], Base64.DEFAULT)) val decodedPayload = String(Base64.decode(parts[1], Base64.DEFAULT))
val jsonPayload = JSONObject(decodedPayload) val jsonPayload = JSONObject(decodedPayload)
@@ -358,21 +241,17 @@ class HomeFragment : Fragment() {
with(sharedPreference.edit()) { with(sharedPreference.edit()) {
putString(Constants.ACCESS_TOKEN, response.data.data?.accessToken) putString(Constants.ACCESS_TOKEN, response.data.data?.accessToken)
putString(Constants.NATS_TOKEN, response.data.data?.deviceUser?.natsToken) putString(Constants.NATS_TOKEN, response.data.data?.deviceUser?.natsToken)
putString( putString(Constants.DEVICE_ID, response.data.data?.deviceUser?.deviceId?.toString())
Constants.NATS_TOKEN_EXPIRE_DATE, response.data.data?.deviceUser?.natsTokenExpiry
)
apply() apply()
} }
isTokenAvailable = true
} }
private fun createLoginRequestData(userID: String, password: String): LoginRequest { private fun createLoginRequestData(): LoginRequest {
val pInfo = requireActivity().packageManager.getPackageInfo(
requireActivity().packageName, 0
)
val version = pInfo.versionName
return LoginRequest( return LoginRequest(
password = password, serialNumber = userID, username = userID, version = version password = Constants.devicePassword,
serialNumber = Constants.deviceID,
username = Constants.deviceID
) )
} }
@@ -386,71 +265,18 @@ class HomeFragment : Fragment() {
) )
} }
private fun createDeviceUpdateRequestData(): DeviceUpdateRequest { private fun createDeviceRequestData(): DeviceUpdateRequest {
return DeviceUpdateRequest( return DeviceUpdateRequest(
serial_no = sharedPreference.getString(Constants.DEVICE_ID, "") serial_no = Constants.DEVICE_ID
) )
} }
private fun downloadFile(responseBody: ResponseBody, context: Context, fileName: String, downloadDirectory: String): File {
// Ensure the download directory exists
val fileDir = File(context.getExternalFilesDir(null), downloadDirectory)
if (!fileDir.exists()) {
fileDir.mkdirs()
}
val file = File(fileDir, fileName)
Log.d("Download", "Starting download to $file")
responseBody.byteStream().use { inputStream ->
FileOutputStream(file).use { outputStream ->
inputStream.copyTo(outputStream)
}
}
// After download
Log.d("Download", "Download completed to ${file.absolutePath}")
return file
}
private fun unzip(zipFilePath: String, destDirectory: String) {
val destDir = File(destDirectory)
if (!destDir.exists()) {
destDir.mkdir()
}
ZipInputStream(FileInputStream(zipFilePath)).use { zipIn ->
var entry: ZipEntry? = zipIn.nextEntry
while (entry != null) {
val filePath = destDirectory + File.separator + entry.name
if (!entry.isDirectory) {
extractFile(zipIn, filePath)
} else {
val dir = File(filePath)
dir.mkdir()
}
zipIn.closeEntry()
entry = zipIn.nextEntry
}
}
}
private fun extractFile(zipIn: ZipInputStream, filePath: String) {
BufferedOutputStream(FileOutputStream(filePath)).use { bos ->
val bytesIn = ByteArray(4096)
var read: Int
while (zipIn.read(bytesIn).also { read = it } != -1) {
bos.write(bytesIn, 0, read)
}
}
}
private fun setUserId() { private fun setUserId() {
binding.btnSubmit.setOnClickListener { binding.btnSubmit.setOnClickListener {
val userId = binding.userId.text.toString() val userId = binding.userId.text.toString()
val bloodGroup = binding.etBloodGroup.text val bloodGroup = binding.etBloodGroup.text
if (userId.length >= 10 && !bloodGroup.equals("Select Blood Group") || !bloodGroup.isNullOrBlank()) { if (userId.length >= 18 && !bloodGroup.equals("Select Blood Group") || !bloodGroup.isNullOrBlank()) {
hemoCubeViewModel.addUser( hemoCubeViewModel.addUser(
HemoCubeTestData( HemoCubeTestData(
_id = userId, _id = userId,
@@ -626,23 +452,9 @@ class HomeFragment : Fragment() {
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList -> hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
val uploadDataVisibility = val uploadDataVisibility =
if (userDataList.any { !it.localFlag && !it.molbioFlag && it.testStatus == true }) View.VISIBLE else View.GONE if (userDataList.any { !it.localFlag && it.testStatus == true }) View.VISIBLE else View.GONE
binding.uploadData.visibility = uploadDataVisibility binding.uploadData.visibility = uploadDataVisibility
} }
hemoCubeViewModel.allKitTestData.observe(viewLifecycleOwner) { bufferData ->
val uploadDataVisibility =
if (bufferData.any { !it.localFlag }) View.VISIBLE else View.GONE
binding.uploadData.visibility = uploadDataVisibility
}
}
private fun checkUnprocessedCSVData() {
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
val downloadDataVisibility =
if (userDataList.any { !it.isCSVCreated && it.testStatus == true }) View.VISIBLE else View.GONE
binding.downloadCSV.visibility = downloadDataVisibility
}
} }
private fun showUploadDialog(context: Context) { private fun showUploadDialog(context: Context) {
@@ -662,23 +474,6 @@ class HomeFragment : Fragment() {
dialog.show() dialog.show()
} }
// private fun showDownloadDialog(context: Context) {
// val builder = AlertDialog.Builder(context)
// builder.setTitle(R.string.download_db_registration_title)
// builder.setMessage(R.string.download_db_registration_message)
//
// builder.setPositiveButton(R.string.downloadcsv) { dialog, _ ->
// downloadLocalDBData(dialog)
// }
//
// builder.setNegativeButton(R.string.cancel) { dialog, _ ->
// dialog.dismiss()
// }
//
// val dialog = builder.create()
// dialog.show()
// }
private fun uploadLocalDBData(dialog: DialogInterface) { private fun uploadLocalDBData(dialog: DialogInterface) {
viewModel.allUserData.observe(viewLifecycleOwner) { userDataList -> viewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
if (userDataList.isEmpty()) { if (userDataList.isEmpty()) {
@@ -696,68 +491,16 @@ class HomeFragment : Fragment() {
} }
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList -> hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
val resultList = MolbioV2ResultRequest(mutableListOf(MolbioV2Result()))
userDataList.forEach { userData -> userDataList.forEach { userData ->
if (!userData.localFlag) { if (!userData.localFlag) {
userData.localFlag = true userData.localFlag = true
hemoCubeViewModel.bulkAddResultTestToDb(userData) hemoCubeViewModel.bulkAddResultTestToDb(userData)
if (!userData.molbioFlag && isTokenAvailable) {
resultList.results?.add(
MolbioV2Result(
rawData = userData,
analysisId = userData._id,
analysisDate = userData.testTime,
analysisStatus = userData.classificationResult,
thresholds = Constants.BUFFER_INTENSITY_THRESHOLDS[userData.deviceId].toString(),
interpretation = userData.classificationResult,
testId = userData._id,
testTime = userData.testTime,
collectionTime = userData.testTime,
expiryTime = userData.testTime,
)
)
}
}
}
if (isTokenAvailable) {
hemoCubeViewModel.uploadResult(resultList)
}
dialog.dismiss()
}
hemoCubeViewModel.allKitTestData.observe(viewLifecycleOwner) { kitDataList ->
kitDataList.forEach { userData ->
if (!userData.localFlag) {
userData.localFlag = true
hemoCubeViewModel.bulkAddResultKitTestToDb(userData)
} }
} }
dialog.dismiss() dialog.dismiss()
} }
} }
// private fun downloadLocalDBData(dialog: DialogInterface) {
// hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
// val downloadList = mutableListOf<HemoCubeTestData>()
//
// userDataList.forEach { userData ->
// if (!userData.isCSVCreated) {
// downloadList.add(userData) // Add the userData to downloadList
// }
// }
//
// if (downloadList.isNotEmpty()) {
// // Call ViewModel function to create CSV with filtered data
// hemoCubeViewModel.createCSV(downloadList, requireContext())
// Toast.makeText(requireContext(), "Done", Toast.LENGTH_SHORT).show()
// } else {
// Toast.makeText(requireContext(), "Failed", Toast.LENGTH_SHORT).show()
// }
//
// dialog.dismiss()
// }
// }
private fun deleteIncompleteRegistrations(userDataList: List<UserData>) { private fun deleteIncompleteRegistrations(userDataList: List<UserData>) {
userDataList.forEach { userData -> userDataList.forEach { userData ->
if (userData.csvPath.isEmpty()) { if (userData.csvPath.isEmpty()) {
@@ -778,79 +521,4 @@ class HomeFragment : Fragment() {
super.onDestroyView() super.onDestroyView()
_binding = null _binding = null
} }
private fun downloadCsv() {
context?.let { context ->
val success = homeViewModel.getLocalUserDataForCsv(context)
if (success) {
// Provide feedback to the user if needed
Toast.makeText(context, "CSV file downloaded successfully", Toast.LENGTH_SHORT)
.show()
} else {
// Handle the case where CSV file generation failed
Toast.makeText(context, "Failed to download CSV file", Toast.LENGTH_SHORT).show()
}
}
}
private fun showDownloadDialog(context: Context) {
val builder = AlertDialog.Builder(context)
builder.setTitle(R.string.download_db_registration_title)
builder.setMessage(R.string.download_db_registration_message)
builder.setPositiveButton(R.string.downloadcsv) { dialog, _ ->
downloadLocalDBData(dialog)
}
builder.setNegativeButton(R.string.cancel) { dialog, _ ->
dialog.dismiss()
}
val dialog = builder.create()
dialog.show()
}
private fun downloadLocalDBData(dialog: DialogInterface) {
var csvDownloaded = false
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
try {
if (!csvDownloaded) {
val downloadList = mutableListOf<HemoCubeTestData>()
userDataList.forEach { userData ->
if (userData.testStatus == true) {
// if (!userData.isCSVCreated) {
downloadList.add(userData) // Add the userData to downloadList
}
// }
}
if (downloadList.isNotEmpty()) {
// Call ViewModel function to create CSV with filtered data
hemoCubeViewModel.createCSV(downloadList, requireContext())
csvDownloaded = true
Toast.makeText(
requireContext(),
"CSV file downloaded successfully",
Toast.LENGTH_SHORT
).show()
} else {
Toast.makeText(
requireContext(),
"No data to download",
Toast.LENGTH_SHORT
)
.show()
}
}
} catch (e: Exception) {
e.printStackTrace()
Toast.makeText(requireContext(), "Error downloading CSV file", Toast.LENGTH_SHORT)
.show()
} finally {
dialog.dismiss()
}
}
}
} }

View File

@@ -37,7 +37,7 @@ class SlideshowFragment : PreferenceFragmentCompat() {
// App Version Preference // App Version Preference
val appVersionPreference = Preference(requireContext()) val appVersionPreference = Preference(requireContext())
appVersionPreference.title = "App Version" appVersionPreference.title = "App Version"
appVersionPreference.summary = getAppVersion(requireContext()) + " [ " + getAppEnvironment(requireContext()) + " ]" appVersionPreference.summary = getAppVersion(requireContext())
preferenceScreen.addPreference(languagePreference) preferenceScreen.addPreference(languagePreference)
preferenceScreen.addPreference(appVersionPreference) preferenceScreen.addPreference(appVersionPreference)
@@ -63,13 +63,4 @@ class SlideshowFragment : PreferenceFragmentCompat() {
"N/A" "N/A"
} }
} }
private fun getAppEnvironment(context: Context): String {
return try {
val pInfo = context.packageManager.getPackageInfo(context.packageName, 0)
pInfo.packageName.substringAfterLast('.')
} catch (e: PackageManager.NameNotFoundException) {
"N/A"
}
}
} }

View File

@@ -24,7 +24,7 @@ class LoginFragment : Fragment() {
): View { ): View {
_binding = FragmentLoginBinding.inflate(inflater, container, false) _binding = FragmentLoginBinding.inflate(inflater, container, false)
sharedPreference = sharedPreference =
requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE) requireContext().getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE)
return binding.root return binding.root
} }

View File

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

View File

@@ -1,180 +0,0 @@
package com.example.hpostesting.presentation.deviceinfo
import android.annotation.SuppressLint
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.ServiceConnection
import android.content.SharedPreferences
import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbDeviceConnection
import android.hardware.usb.UsbManager
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.IBinder
import android.util.Log
import android.view.Menu
import android.widget.Toast
import androidx.activity.viewModels
import androidx.core.content.ContextCompat
import androidx.core.view.get
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.presentation.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.ActivityDeviceBinding
@Suppress("MemberVisibilityCanBePrivate")
@AndroidEntryPoint
class DeviceActivity : AppCompatActivity() {
private lateinit var binding: ActivityDeviceBinding
private val deviceViewModel by viewModels<DeviceViewModel>()
private var myMenu: Menu? = null
private lateinit var sharedPreferences: SharedPreferences
private lateinit var mDriver: UsbSerialDriver
private var mConnection: UsbDeviceConnection? = null
lateinit var mService: UsbService
private var deviceId = ""
private val TAG = "Calibration"
private val broadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
synchronized(this) {
val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
device?.apply {
connectUsb(true)
DataHolder.usbConnected.postValue(true)
}
} else {
onErrorReported("permission denied for device")
DataHolder.usbConnected.postValue(true)
}
}
}
}
private val connection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) {
val binder = service as UsbService.UsbServiceBinder
mService = binder.getService()
deviceViewModel.isServiceConnected = true
mConnection.let { mService.connect(mDriver, mConnection!!) }
moveToNext()
}
override fun onServiceDisconnected(arg0: ComponentName) {
deviceViewModel.isServiceConnected = false
}
}
override fun attachBaseContext(newBase: Context?) {
val languageCode = LanguageManager.getSavedLanguage(newBase!!)
LanguageManager.setLocale(newBase, languageCode)
super.attachBaseContext(newBase)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityDeviceBinding.inflate(layoutInflater)
setContentView(binding.root)
// setSupportActionBar(binding.myToolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
setupListener()
connectUsb(false)
}
private fun setupListener() {
DataHolder.usbConnected.observe(this) {
Log.d("USB OBSERVE", "HemoCube called -> $it")
if (it) {
myMenu?.get(0)?.icon =
ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_24)
} else {
myMenu?.get(0)?.icon =
ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_off_24)
Toast.makeText(this, "Device is Disconnected", Toast.LENGTH_SHORT).show()
}
}
}
open fun connectUsb(permissionGranted: Boolean) {
Log.d(TAG, "connectUsb() called, permission variable = $permissionGranted")
val manager = getSystemService(Context.USB_SERVICE) as UsbManager
val availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager)
if (availableDrivers.isEmpty()) {
onErrorReported("No Device is Connected")
} else {
mDriver = availableDrivers[0]
mConnection = manager.openDevice(mDriver.device)
if (mConnection == null) {
requestUserPermission(manager, mDriver.device)
} else {
setupService()
}
}
}
fun onErrorReported(msg: String) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
if (!isFinishing) onBackPressed()
}
private fun moveToNext() {
if (supportFragmentManager.isDestroyed) return
supportFragmentManager.beginTransaction().replace(binding.fgDevice.id, DeviceFragment())
.commit()
}
@SuppressLint("MutableImplicitPendingIntent")
private fun requestUserPermission(manager: UsbManager, device: UsbDevice) {
val mPendingIntent: PendingIntent
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
mPendingIntent = PendingIntent.getBroadcast(
this, 0, Intent(Constants.HEMOCUBE_USB_PERMISSION), PendingIntent.FLAG_MUTABLE
)
} else {
mPendingIntent = PendingIntent.getBroadcast(
this,
0,
Intent(Constants.HEMOCUBE_USB_PERMISSION),
PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
)
}
val filter = IntentFilter(Constants.HEMOCUBE_USB_PERMISSION)
registerReceiver(broadcastReceiver, filter)
manager.requestPermission(device, mPendingIntent)
}
fun setupService() {
val intent = Intent(this, UsbService::class.java)
bindService(intent, connection, Context.BIND_AUTO_CREATE)
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.my_menu, menu)
return true
}
override fun onDestroy() {
super.onDestroy()
if (deviceViewModel.isServiceConnected) {
mService.disconnect()
unbindService(connection)
deviceViewModel.isServiceConnected = false
}
}
}

View File

@@ -1,109 +0,0 @@
package com.example.hpostesting.presentation.deviceinfo
import android.annotation.SuppressLint
import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.MutableLiveData
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.presentation.UsbServiceListener
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.ktx.Firebase
import `in`.sminnovations.hpostesting.databinding.FragmentDeviceBinding
class DeviceFragment : Fragment() {
private lateinit var binding: FragmentDeviceBinding
private val deviceViewModel: HemoCubeViewModel by activityViewModels()
private lateinit var sharedPreferences: SharedPreferences
private var deviceId = ""
private var startListening = MutableLiveData(false)
private var resultData: String = ""
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
): View {
binding = FragmentDeviceBinding.inflate(inflater, container, false)
sharedPreferences =
requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initViews()
}
private fun initViews() {
deviceId = sharedPreferences.getString(Constants.DEVICE_ID, "").toString()
listenToHemoCube()
getDeviceId()
}
private fun getDeviceId() {
deviceViewModel.progressBar.postValue(true)
(activity as DeviceActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.DEVICE_CONFIGURATION_COMMAND,
object : UsbServiceListener {
@SuppressLint("SetTextI18n")
override fun onUsbRead(data: ByteArray?) {
data?.let {
val stringData = String(it)
deviceViewModel.messages.postValue(stringData)
binding.tvSubtitle4.text = "Device ID: ${stringData}"
}
}
override fun onUsbError(e: Exception?) {
deviceViewModel.progressBar.postValue(false)
}
})
}
private fun listenToHemoCube() {
val fullReadOutput = StringBuilder()
startListening.postValue(true)
try {
(activity as DeviceActivity).mService.listenToHemoCube(object : UsbServiceListener {
@SuppressLint("SetTextI18n")
override fun onUsbRead(data: ByteArray?) {
data?.let {
val stringData = String(it)
deviceViewModel.messages.postValue(stringData)
fullReadOutput.append(stringData)
resultData += stringData
binding.tvSubtitle4.text = "Device ID : ${resultData}"
if (stringData.contains("SN")) {
val slData = stringData.split(" ")
if (slData.size > 1) {
val hardwareId = slData[1].trim()
with(sharedPreferences.edit()) {
putString(Constants.DEVICE_ID, hardwareId)
apply()
}
// binding.tvSubtitle4.text = hardwareId
}
}
}
}
override fun onUsbError(e: Exception?) {
deviceViewModel.progressBar.postValue(false)
}
})
} catch (e: Exception) {
Firebase.crashlytics.recordException(e)
}
}
}

View File

@@ -1,25 +0,0 @@
package com.example.hpostesting.presentation.deviceinfo
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.example.hpostesting.data.dao.HemoCubeDao
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.repository.Repository
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
@HiltViewModel
class DeviceViewModel @Inject constructor(
private val hemoCubeDao: HemoCubeDao,
private val repository: Repository,
) : ViewModel() {
var isServiceConnected = false
val progressBar = MutableLiveData(false)
val messages = MutableLiveData<String>()
// private val _networkStatusLiveData = NetworkStatusLiveData(context)
// val allUserData = hemoCubeDao.getAll()
val deviceData = MutableLiveData<DeviceData?>()
// val networkStatusLiveData: LiveData<Boolean>
// get() = _networkStatusLiveData
val fireBaseUpload = MutableLiveData<String>()
}

View File

@@ -1,183 +0,0 @@
package com.example.hpostesting.presentation.deviceprovision
import android.annotation.SuppressLint
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.ServiceConnection
import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbDeviceConnection
import android.hardware.usb.UsbManager
import android.os.Bundle
import android.os.IBinder
import android.util.Log
import android.view.Menu
import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.get
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.presentation.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.ActivityAutoDacBinding
@AndroidEntryPoint
class DeviceProvisionActivity : AppCompatActivity() {
private lateinit var binding: ActivityAutoDacBinding
val viewModel: DeviceProvisionViewModel by viewModels()
private var myMenu: Menu? = null
private lateinit var mDriver: UsbSerialDriver
private var mConnection: UsbDeviceConnection? = null
lateinit var mService: UsbService
private val TAG = "HemoCube"
private val broadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
synchronized(this) {
val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
device?.apply {
connectUsb(true)
DataHolder.usbConnected.postValue(true)
}
} else {
onErrorReported("permission denied for device")
DataHolder.usbConnected.postValue(true)
}
}
}
}
private val connection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) {
val binder = service as UsbService.UsbServiceBinder
mService = binder.getService()
viewModel.isServiceConnected = true
mConnection.let { mService.connect(mDriver, mConnection!!) }
moveToNext()
}
override fun onServiceDisconnected(arg0: ComponentName) {
viewModel.isServiceConnected = false
}
}
override fun attachBaseContext(newBase: Context?) {
val languageCode = LanguageManager.getSavedLanguage(newBase!!)
LanguageManager.setLocale(newBase, languageCode)
super.attachBaseContext(newBase)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityAutoDacBinding.inflate(layoutInflater)
setContentView(binding.root)
// setSupportActionBar(binding.myToolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
setupListener()
connectUsb(false)
}
private fun setupListener() {
DataHolder.usbConnected.observe(this) {
Log.d("USB OBSERVE", "HemoCube called -> $it")
if (it) {
myMenu?.get(0)?.icon =
ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_24)
} else {
myMenu?.get(0)?.icon =
ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_off_24)
Toast.makeText(this, "Device is Disconnected", Toast.LENGTH_SHORT).show()
}
}
}
fun connectUsb(permissionGranted: Boolean) {
Log.d(TAG, "connectUsb() called, permission variable = $permissionGranted")
val manager = getSystemService(Context.USB_SERVICE) as UsbManager
val availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager)
if (availableDrivers.isEmpty()) {
onErrorReported("No Device is Connected")
} else {
mDriver = availableDrivers[0]
mConnection = manager.openDevice(mDriver.device)
if (mConnection == null) {
requestUserPermission(manager, mDriver.device)
} else {
setupService()
}
}
}
fun onErrorReported(msg: String) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
if (!isFinishing) onBackPressed()
}
private fun moveToNext() {
if (supportFragmentManager.isDestroyed) return
supportFragmentManager.beginTransaction()
.replace(binding.fgAutoDac.id, DeviceProvisionFragment()).commit()
}
@SuppressLint("MutableImplicitPendingIntent")
private fun requestUserPermission(manager: UsbManager, device: UsbDevice) {
val mPendingIntent: PendingIntent = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
PendingIntent.getBroadcast(
this, 0, Intent(Constants.HEMOCUBE_USB_PERMISSION), PendingIntent.FLAG_MUTABLE
)
} else {
PendingIntent.getBroadcast(
this,
0,
Intent(Constants.HEMOCUBE_USB_PERMISSION),
PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
)
}
val filter = IntentFilter(Constants.HEMOCUBE_USB_PERMISSION)
registerReceiver(broadcastReceiver, filter)
manager.requestPermission(device, mPendingIntent)
}
fun setupService() {
val intent = Intent(this, UsbService::class.java)
bindService(intent, connection, Context.BIND_AUTO_CREATE)
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.my_menu, menu)
return true
}
override fun onDestroy() {
super.onDestroy()
if (viewModel.isServiceConnected) {
mService.disconnect()
unbindService(connection)
viewModel.isServiceConnected = false
}
}
}

View File

@@ -1,174 +0,0 @@
package com.example.hpostesting.presentation.deviceprovision
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import com.example.hpostesting.data.Result
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionRequest
import com.example.hpostesting.presentation.UsbServiceListener
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.ktx.Firebase
import `in`.sminnovations.hpostesting.databinding.FragmentDeviceProvisionBinding
class DeviceProvisionFragment : Fragment() {
private var resultData: String = ""
private lateinit var binding: FragmentDeviceProvisionBinding
private val viewModel: DeviceProvisionViewModel by activityViewModels()
private lateinit var sharedPreferences: SharedPreferences
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
binding = FragmentDeviceProvisionBinding.inflate(inflater, container, false)
sharedPreferences = requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initViews()
observeViewModel()
}
private fun initViews() {
listenToHemoCube()
getDeviceId()
binding.btnSubmit.setOnClickListener {
viewModel.deviceProvision(
DeviceProvisionRequest(
email = Constants.deviceProvisionEmail,
password = Constants.deviceProvisionPassword,
serialNumber = sharedPreferences.getString(Constants.DEVICE_ID, "").toString(),
uid = sharedPreferences.getString(Constants.DEVICE_ID, "").toString()
)
)
}
}
private fun observeViewModel() {
viewModel.deviceProvisionResponse.observe(viewLifecycleOwner) { response ->
when (response) {
is Result.Success -> {
if (response.data.result == "Success") {
with(sharedPreferences.edit()) {
putString(
Constants.DEVICE_ID_API,
response.data.data?.credentials?.username
)
putString(
Constants.DEVICE_PASSWORD_API,
response.data.data?.credentials?.password
)
putString(
Constants.NATS_TOKEN,
response.data.data?.device?.deviceUser?.natsToken
)
response.data.data?.device?.deviceUser?.natsToken?.let {
Log.e("natstoken",
it
)
}
putString(
Constants.NATS_TOKEN_EXPIRE_DATE,
response.data.data?.device?.deviceUser?.natsTokenExpiry
)
apply()
}
startActivity(Intent(requireContext(), DashboardActivity::class.java))
Toast.makeText(
activity, "Device registered successfully", Toast.LENGTH_LONG
).show()
} else {
Toast.makeText(
activity,
"An error occurred in device provision: ${response.data.message}",
Toast.LENGTH_LONG
).show()
binding.btnSubmit.visibility = View.VISIBLE
}
}
is Result.Error -> {
response.exception.let { message ->
Toast.makeText(
activity,
"An error occurred in device provision: $message",
Toast.LENGTH_LONG
).show()
}
}
is Result.Loading -> {
binding.btnSubmit.visibility = View.GONE
}
else -> {}
}
}
}
private fun getDeviceId() {
(activity as DeviceProvisionActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.DEVICE_CONFIGURATION_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {}
override fun onUsbError(e: Exception?) {}
})
}
private fun listenToHemoCube() {
val fullReadOutput = StringBuilder()
try {
(activity as DeviceProvisionActivity).mService.listenToHemoCube(object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
data?.let {
val stringData = String(it)
fullReadOutput.append(stringData)
resultData += stringData
handleUsbData()
}
}
override fun onUsbError(e: Exception?) {}
})
} catch (e: Exception) {
Firebase.crashlytics.recordException(e)
}
}
private fun handleUsbData() {
when {
resultData.contains("SNE") -> {
val pattern = Regex("HPP1-\\d{4}")
val matchResult = pattern.find(resultData)
val hardwareId = matchResult?.value
if (hardwareId.toString().length == 9) {
with(sharedPreferences.edit()) {
putString(Constants.DEVICE_ID, hardwareId)
apply()
}
activity?.runOnUiThread {
binding.btnSubmit.visibility = View.VISIBLE
}
}
}
}
}
}

View File

@@ -1,29 +0,0 @@
package com.example.hpostesting.presentation.deviceprovision
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.hpostesting.data.Result
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionRequest
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionResponse
import com.example.hpostesting.data.repository.Repository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class DeviceProvisionViewModel @Inject constructor(
private val databaseRepository: Repository
) : ViewModel() {
var isServiceConnected = false
val deviceProvisionResponse = MutableLiveData<Result<DeviceProvisionResponse>>()
fun deviceProvision(deviceProvisionRequest: DeviceProvisionRequest) = viewModelScope.launch {
deviceProvisionResponse.postValue(Result.Loading())
databaseRepository.deviceProvision(deviceProvisionRequest).let {
deviceProvisionResponse.postValue(it)
}
}
}

View File

@@ -1,6 +1,5 @@
package com.example.hpostesting.presentation.diagnostics package com.example.hpostesting.presentation.diagnostics
import android.annotation.SuppressLint
import android.app.PendingIntent import android.app.PendingIntent
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.ComponentName import android.content.ComponentName
@@ -23,6 +22,8 @@ import androidx.core.view.get
import com.example.hpostesting.data.DataHolder import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.Constants import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.LanguageManager import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.presentation.hemocube.HemoCubeFragment
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.example.hpostesting.presentation.testRight.UsbService import com.example.hpostesting.presentation.testRight.UsbService
import com.hoho.android.usbserial.driver.UsbSerialDriver import com.hoho.android.usbserial.driver.UsbSerialDriver
import com.hoho.android.usbserial.driver.UsbSerialProber import com.hoho.android.usbserial.driver.UsbSerialProber
@@ -30,7 +31,6 @@ import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityDiagnosticsBinding import `in`.sminnovations.hpostesting.databinding.ActivityDiagnosticsBinding
@Suppress("MemberVisibilityCanBePrivate")
@AndroidEntryPoint @AndroidEntryPoint
class DiagnosticsActivity : AppCompatActivity() { class DiagnosticsActivity : AppCompatActivity() {
private lateinit var binding: ActivityDiagnosticsBinding private lateinit var binding: ActivityDiagnosticsBinding
@@ -141,23 +141,22 @@ class DiagnosticsActivity : AppCompatActivity() {
.commit() .commit()
} }
@SuppressLint("MutableImplicitPendingIntent")
private fun requestUserPermission(manager: UsbManager, device: UsbDevice) { private fun requestUserPermission(manager: UsbManager, device: UsbDevice) {
val mPendingIntent: PendingIntent val mPendingIntent: PendingIntent
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
mPendingIntent = PendingIntent.getBroadcast( mPendingIntent = PendingIntent.getBroadcast(
this, 0, Intent(Constants.HEMOCUBE_USB_PERMISSION), PendingIntent.FLAG_MUTABLE this, 0, Intent(Constants.HOMOCUBE_USB_PERMISSION), PendingIntent.FLAG_MUTABLE
) )
} else { } else {
mPendingIntent = PendingIntent.getBroadcast( mPendingIntent = PendingIntent.getBroadcast(
this, this,
0, 0,
Intent(Constants.HEMOCUBE_USB_PERMISSION), Intent(Constants.HOMOCUBE_USB_PERMISSION),
PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
) )
} }
val filter = IntentFilter(Constants.HEMOCUBE_USB_PERMISSION) val filter = IntentFilter(Constants.HOMOCUBE_USB_PERMISSION)
registerReceiver(broadcastReceiver, filter) registerReceiver(broadcastReceiver, filter)
manager.requestPermission(device, mPendingIntent) manager.requestPermission(device, mPendingIntent)
} }

View File

@@ -38,7 +38,7 @@ class DiagnosticsFragment : Fragment() {
): View { ): View {
binding = FragmentDiagnosticsBinding.inflate(inflater, container, false) binding = FragmentDiagnosticsBinding.inflate(inflater, container, false)
sharedPreferences = sharedPreferences =
requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE) requireContext().getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE)
return binding.root return binding.root
} }
@@ -86,7 +86,7 @@ class DiagnosticsFragment : Fragment() {
private fun getDeviceId() { private fun getDeviceId() {
diagnosticsViewModel.progressBar.postValue(true) diagnosticsViewModel.progressBar.postValue(true)
(activity as DiagnosticsActivity).mService.sendAndListenToHemoCube( (activity as DiagnosticsActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.DEVICE_CONFIGURATION_COMMAND, HemoCubeCommands.getDeviceId,
object : UsbServiceListener { object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) { override fun onUsbRead(data: ByteArray?) {
data?.let { data?.let {
@@ -104,7 +104,7 @@ class DiagnosticsFragment : Fragment() {
private fun runDeviceDiagnostics() { private fun runDeviceDiagnostics() {
diagnosticsViewModel.progressBar.postValue(true) diagnosticsViewModel.progressBar.postValue(true)
(activity as DiagnosticsActivity).mService.sendAndListenToHemoCube( (activity as DiagnosticsActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.DIAGNOSTICS_COMMAND, HemoCubeCommands.runDiagnostics,
object : UsbServiceListener { object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) { override fun onUsbRead(data: ByteArray?) {

View File

@@ -1,24 +1,45 @@
package com.example.hpostesting.presentation.diagnostics package com.example.hpostesting.presentation.diagnostics
import android.content.Context
import android.content.SharedPreferences
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope 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.Response
import com.example.hpostesting.data.model.diagnostics.DiagnosticsData import com.example.hpostesting.data.model.diagnostics.DiagnosticsData
import com.example.hpostesting.data.model.patient.DeviceData import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.repository.Repository import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.toHemoCubeTestData
import com.example.hpostesting.data.repository.DatabaseRepository
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
class DiagnosticsViewModel @Inject constructor( class DiagnosticsViewModel @Inject constructor(
private val repository: Repository private val hemoCubeDao: HemoCubeDao,
private val repository: DatabaseRepository,
context: Context
) : ViewModel() { ) : ViewModel() {
var isServiceConnected = false var isServiceConnected = false
val progressBar = MutableLiveData(false) val progressBar = MutableLiveData(false)
val messages = MutableLiveData<String>() val messages = MutableLiveData<String>()
private val sharedPreference: SharedPreferences =
context.getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE)
private val _networkStatusLiveData = NetworkStatusLiveData(context)
val allUserData = hemoCubeDao.getAll()
val deviceData = MutableLiveData<DeviceData?>() val deviceData = MutableLiveData<DeviceData?>()
val networkStatusLiveData: LiveData<Boolean>
get() = _networkStatusLiveData
val fireBaseUpload = MutableLiveData<String>() val fireBaseUpload = MutableLiveData<String>()
fun addDiagnosticsDataToDb(data: DiagnosticsData) { fun addDiagnosticsDataToDb(data: DiagnosticsData) {
@@ -26,19 +47,17 @@ class DiagnosticsViewModel @Inject constructor(
try { try {
when (val response = repository.addDiagnostics(data)) { when (val response = repository.addDiagnostics(data)) {
is Response.Success -> { is Response.Success -> {
// Log.i("Testdb", "Data uploaded to Firestore successfully") Log.i("Testdb", "Data uploaded to Firestore successfully")
fireBaseUpload.postValue("Success") fireBaseUpload.postValue("Success")
} }
is Response.Error -> { is Response.Error -> {
// Log.e("Testdb", "Error uploading data to Firestore: $response") Log.e("Testdb", "Error uploading data to Firestore: $response")
fireBaseUpload.postValue("Error") fireBaseUpload.postValue("Error")
} }
else -> {}
} }
} catch (e: Exception) { } catch (e: Exception) {
// Log.e("Testdb", "Exception during data upload: ${e.message}") Log.e("Testdb", "Exception during data upload: ${e.message}")
fireBaseUpload.postValue("Error") fireBaseUpload.postValue("Error")
} }
} }

View File

@@ -31,7 +31,7 @@ class DigitalCardFragment : Fragment() {
): View { ): View {
binding = FragmentDigitalCardBinding.inflate(inflater, container, false) binding = FragmentDigitalCardBinding.inflate(inflater, container, false)
sharedPreferences = sharedPreferences =
requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE) requireContext().getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE)
return binding.root return binding.root
} }

View File

@@ -3,6 +3,7 @@ package com.example.hpostesting.presentation.hemocube
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.graphics.Color
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@@ -16,8 +17,6 @@ import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.Result import com.example.hpostesting.data.Result
import com.example.hpostesting.data.constant.Constants import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.HemoCubeCommands import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.constant.TestStatus
import com.example.hpostesting.data.model.TestState
import com.example.hpostesting.data.model.patient.DeviceData import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.toHemoCubeTestData import com.example.hpostesting.data.model.patient.toHemoCubeTestData
import com.example.hpostesting.presentation.UsbServiceListener import com.example.hpostesting.presentation.UsbServiceListener
@@ -26,12 +25,11 @@ import com.example.hpostesting.presentation.utils.MyDialogListener
import com.example.hpostesting.presentation.utils.UIUtils import com.example.hpostesting.presentation.utils.UIUtils
import com.google.firebase.crashlytics.ktx.crashlytics import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.ktx.Firebase import com.google.firebase.ktx.Firebase
import com.google.firebase.perf.ktx.performance
import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentHemoCubeReferenceBinding import `in`.sminnovations.hpostesting.databinding.FragmentHemoCubeReferenceBinding
import kotlin.math.abs
import kotlin.math.log10 import kotlin.math.log10
@Suppress("MemberVisibilityCanBePrivate")
class HemoCubeFragment : Fragment() { class HemoCubeFragment : Fragment() {
private lateinit var binding: FragmentHemoCubeReferenceBinding private lateinit var binding: FragmentHemoCubeReferenceBinding
@@ -41,10 +39,10 @@ class HemoCubeFragment : Fragment() {
private var isOnline = false private var isOnline = false
private var currentDeviceData: DeviceData? = null private var currentDeviceData: DeviceData? = null
private var resultData: String = "" private var resultData: String = ""
private var currentResultData: String = ""
private var isUsingExistingBuffer = false private var isUsingExistingBuffer = false
private var isTestOngoing = false private var isTestOngoing = false
private var startListening = MutableLiveData<Boolean>(false) private var startListening = MutableLiveData<Boolean>(false)
private val testingTrace = Firebase.performance.newTrace("testing_trace")
private var led1BufferForDevice = 0.0 private var led1BufferForDevice = 0.0
private var led2BufferForDevice = 0.0 private var led2BufferForDevice = 0.0
private var led3BufferForDevice = 0.0 private var led3BufferForDevice = 0.0
@@ -57,28 +55,18 @@ class HemoCubeFragment : Fragment() {
private var fittedAbs2 = 0.0 private var fittedAbs2 = 0.0
private var fittedAbs3 = 0.0 private var fittedAbs3 = 0.0
private var fittedAbs4 = 0.0 private var fittedAbs4 = 0.0
private var calculatedPredictedDenovixRatio = 0.0 private var _predictedDenovixRatio = 0.0
private var validationError = false private var validationError = false
private var deviceHardwareId = "" private var deviceHardwareId = ""
private var allErrorMessages = "" private var allErrorMessages = ""
private var testStatusCode = 0.0 private var testStatusCode = 0.0
private var repeatReadingCount = 0
private var readingsPerSample = Constants.READINGS_PER_SAMPLE
private var uploadedToCloud = false
private var uploadedToMolbio = false
lateinit var testState: TestState
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?, inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
): View { ): View {
binding = FragmentHemoCubeReferenceBinding.inflate(inflater, container, false) binding = FragmentHemoCubeReferenceBinding.inflate(inflater, container, false)
sharedPreferences = sharedPreferences =
requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE) requireContext().getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE)
testState = TestState(
testDetails = DataHolder.selectedTest?.toHemoCubeTestData(),
)
return binding.root return binding.root
} }
@@ -94,7 +82,6 @@ class HemoCubeFragment : Fragment() {
binding.btnSubmit.setOnClickListener { binding.btnSubmit.setOnClickListener {
activity?.runOnUiThread { activity?.runOnUiThread {
binding.progressBar.visibility = View.VISIBLE binding.progressBar.visibility = View.VISIBLE
binding.btnSubmit.visibility = View.GONE
} }
hemoCubeViewModel.uploadHemoCubeResultToDatabase( hemoCubeViewModel.uploadHemoCubeResultToDatabase(
isOnline, true, sharedPreferences.getString(Constants.KIT_NUMBER, "") isOnline, true, sharedPreferences.getString(Constants.KIT_NUMBER, "")
@@ -123,7 +110,7 @@ class HemoCubeFragment : Fragment() {
} }
binding.btnPlacebuffer.setOnClickListener { binding.btnPlacebuffer.setOnClickListener {
if (isBufferValueAvailable() || !Constants.BLANK_EVERY_TEST) { if (isBufferValueAvailable()) {
showBufferAlertDialog() showBufferAlertDialog()
} else { } else {
activity?.runOnUiThread { activity?.runOnUiThread {
@@ -147,29 +134,29 @@ class HemoCubeFragment : Fragment() {
private fun observeViewModel() { private fun observeViewModel() {
hemoCubeViewModel.fireBaseUpload.observe(viewLifecycleOwner) { result -> hemoCubeViewModel.fireBaseUpload.observe(viewLifecycleOwner) { result ->
if (result == "Success") { if (result == "Success") {
uploadedToCloud = true
showToast(R.string.test_upload) showToast(R.string.test_upload)
activity?.runOnUiThread {
binding.btnSubmit.visibility = View.GONE
val i = Intent(
requireContext().applicationContext,
DashboardActivity::class.java
)
startActivity(i)
}
hemoCubeViewModel.resultUpload.observe(viewLifecycleOwner) { hemoCubeViewModel.resultUpload.observe(viewLifecycleOwner) {
when (it) { when (it) {
is Result.Success -> { is Result.Success -> {
uploadedToMolbio = true it.data.data?.get(0)?.rawData?.let { it1 ->
if (Constants.MOLBIO_INTERGATION) { hemoCubeViewModel.updateMolbioFlag(
it.data.data?.get(0)?.rawData?.let { it1 -> it1._id)
hemoCubeViewModel.updateMolbioFlag(
it1._id
)
}
} }
handleReadingFinish()
} }
is Result.Error -> { is Result.Error -> {
binding.btnSubmit.visibility = View.VISIBLE
//Remove this line of code while deploying to IOCL //Remove this line of code while deploying to IOCL
it.exception.let { message -> it.exception.let { message ->
Toast.makeText(activity, "An error occurred: $message", Toast.LENGTH_LONG) Toast.makeText(activity, "An error occurred: $message", Toast.LENGTH_LONG)
.show() .show()
} }
handleReadingFinish()
} }
else -> {} else -> {}
@@ -198,9 +185,9 @@ class HemoCubeFragment : Fragment() {
apply { apply {
DataHolder.hemoCubeTestData?.let { DataHolder.hemoCubeTestData?.let {
currentDeviceData?.coefficients?.let { coefficients -> currentDeviceData?.coefficients?.let { coefficients ->
// val coefficient1 = coefficients[0] val coefficient1 = coefficients[0]
// val coefficient2 = coefficients[1] val coefficient2 = coefficients[1]
// val result = coefficient1 * coefficient2 val result = coefficient1 * coefficient2
} }
} }
isOnline = isNetworkAvailable isOnline = isNetworkAvailable
@@ -216,38 +203,6 @@ class HemoCubeFragment : Fragment() {
} }
} }
private fun handleReadingFinish() {
if (allReadingsComplete(repeatReadingCount, readingsPerSample) && uploadedToCloud) {
if (validationError) {
hemoCubeViewModel.messages.postValue("Error")
return
}
activity?.runOnUiThread {
binding.btnSubmit.visibility = View.GONE
val i = Intent(
requireContext().applicationContext, DashboardActivity::class.java
)
startActivity(i)
}
} else {
hemoCubeViewModel.messages.postValue("Reading $repeatReadingCount completed")
resetTest()
startSampleProcess()
}
}
fun allReadingsComplete(repeatReadingCount: Int, readingsPerSample: Int): Boolean {
return repeatReadingCount >= readingsPerSample
}
private fun resetTest() {
testStatusCode = 0.0
allErrorMessages = ""
validationError = false
resultData = ""
currentResultData = ""
}
private fun checkAndStartProcess() { private fun checkAndStartProcess() {
startBufferProcess() startBufferProcess()
} }
@@ -311,7 +266,10 @@ class HemoCubeFragment : Fragment() {
} }
private fun listenToHemoCube() { private fun listenToHemoCube() {
DataHolder.hemoCubeTestData = DataHolder.selectedTest?.toHemoCubeTestData() if (DataHolder.hemoCubeTestData == null) {
DataHolder.hemoCubeTestData = DataHolder.selectedTest?.toHemoCubeTestData()
}
hemoCubeViewModel.progressBar.postValue(true) hemoCubeViewModel.progressBar.postValue(true)
val fullReadOutput = StringBuilder() val fullReadOutput = StringBuilder()
@@ -323,7 +281,7 @@ class HemoCubeFragment : Fragment() {
data?.let { data?.let {
val stringData = String(it) val stringData = String(it)
fullReadOutput.append(stringData) fullReadOutput.append(stringData)
handleUsbData(stringData) handleUsbData(stringData, testStatusCode)
} }
} }
@@ -340,7 +298,7 @@ class HemoCubeFragment : Fragment() {
private fun getDeviceInfo() { private fun getDeviceInfo() {
hemoCubeViewModel.progressBar.postValue(true) hemoCubeViewModel.progressBar.postValue(true)
(activity as HemocubeActivity).mService.sendAndListenToHemoCube( (activity as HemocubeActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.DEVICE_CONFIGURATION_COMMAND, HemoCubeCommands.getDeviceId,
object : UsbServiceListener { object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) { override fun onUsbRead(data: ByteArray?) {
data?.let { data?.let {
@@ -356,360 +314,135 @@ class HemoCubeFragment : Fragment() {
}) })
} }
fun handleUsbData(stringData: String) { private fun handleUsbData(stringData: String, testStatusCode: Double) {
if (stringData.contains("#")) { if (stringData.contains("#")) {
isTestOngoing = true isTestOngoing = true
} }
resultData += stringData resultData += stringData
currentResultData += stringData hemoCubeViewModel.deviceMessages.postValue(resultData)
hemoCubeViewModel.deviceMessages.postValue(currentResultData)
when { when {
resultData.contains("SNE") && this.testStatusCode < TestStatus.CONFIG_COMPLETED.code -> { resultData.contains("SNE") && this.testStatusCode < Constants.TEST_STATUS_CODE_CONFIG_COMPLETED -> {
processV2HardwareId(resultData) val pattern = Regex("HCV-\\d{3}-\\d{4}")
val matchResult = pattern.find(resultData)
val hardwareId = matchResult?.value
if (hardwareId.toString().length == 12) {
deviceHardwareId += hardwareId
with(sharedPreferences.edit()) {
putString(Constants.DEVICE_ID, deviceHardwareId)
apply()
}
this.testStatusCode = Constants.TEST_STATUS_CODE_CONFIG_COMPLETED
} else {
hemoCubeViewModel.messages.postValue("Config error")
}
activity?.runOnUiThread {
binding.btnPlacebuffer.visibility = View.VISIBLE
}
hemoCubeViewModel.messages.postValue(getString(R.string.start))
} }
(resultData.contains("SN") && !resultData.contains("SNS") && !resultData.contains("SNE") && resultData.length >= 15) && this.testStatusCode < TestStatus.CONFIG_COMPLETED.code -> { resultData.contains("#BS") && this.testStatusCode < Constants.TEST_STATUS_CODE_BUFFER_STARTED -> {
processV1HardwareId(resultData)
}
(resultData.contains("#LS") && this.testStatusCode < TestStatus.FIRST_EMPTY_AIR_READING_STARTED.code) -> {
// air reading 1
this.testStatusCode = TestStatus.FIRST_EMPTY_AIR_READING_STARTED.code
hemoCubeViewModel.messages.postValue("Air reading started")
}
(resultData.contains("#LC") && this.testStatusCode < TestStatus.FIRST_EMPTY_AIR_READING_COMPLETED.code) -> {
// air reading 1, send command to print
this.testStatusCode = TestStatus.FIRST_EMPTY_AIR_READING_COMPLETED.code
hemoCubeViewModel.messages.postValue("Air reading completed")
fetchResult()
}
resultData.contains("#BS") && this.testStatusCode < TestStatus.BUFFER_STARTED.code -> {
hemoCubeViewModel.messages.postValue(getString(R.string.buffer_started)) hemoCubeViewModel.messages.postValue(getString(R.string.buffer_started))
this.testStatusCode = TestStatus.BUFFER_STARTED.code this.testStatusCode = Constants.TEST_STATUS_CODE_BUFFER_STARTED
} }
resultData.contains("#BC") && this.testStatusCode < TestStatus.BUFFER_COMPLETED.code -> { resultData.contains("#BC") && this.testStatusCode < Constants.TEST_STATUS_CODE_BUFFER_COMPLETED -> {
this.testStatusCode = TestStatus.BUFFER_COMPLETED.code this.testStatusCode = Constants.TEST_STATUS_CODE_BUFFER_COMPLETED
activity?.runOnUiThread { activity?.runOnUiThread {
binding.tvSubtitle4.text = getString(R.string.buffer_completed) binding.tvSubtitle4.text = getString(R.string.buffer_completed)
binding.btnSamplestart.visibility = View.VISIBLE binding.btnSamplestart.visibility = View.VISIBLE
} }
} }
(resultData.contains("#SS") || resultData.contains("#SS1")) && this.testStatusCode < TestStatus.SAMPLE_STARTED.code -> { resultData.contains("#SS") && this.testStatusCode < Constants.TEST_STATUS_CODE_SAMPLE_STARTED -> {
this.testStatusCode = TestStatus.SAMPLE_STARTED.code this.testStatusCode = Constants.TEST_STATUS_CODE_SAMPLE_STARTED
activity?.runOnUiThread { activity?.runOnUiThread {
binding.tvSubtitle4.text = getString(R.string.sample_started) binding.tvSubtitle4.text = getString(R.string.sample_started)
binding.btnSamplestart.visibility = View.GONE binding.btnSamplestart.visibility = View.GONE
} }
} }
(resultData.contains("#SC") || resultData.contains("#SC1")) && this.testStatusCode < TestStatus.SAMPLE_COMPLETED.code -> { resultData.contains("#SC") && this.testStatusCode < Constants.TEST_STATUS_CODE_SAMPLE_COMPLETED -> {
this.testStatusCode = TestStatus.SAMPLE_COMPLETED.code this.testStatusCode = Constants.TEST_STATUS_CODE_SAMPLE_COMPLETED
hemoCubeViewModel.messages.postValue( hemoCubeViewModel.messages.postValue(
getString(R.string.sample_completed) + "\n" + getString(R.string.gathering_data)) getString(R.string.sample_completed) + "\n" + getString(R.string.gathering_data))
fetchResult() fetchResult()
currentResultData = "" testingTrace.stop()
} }
resultData.contains("ovf") -> { resultData.contains("REND") && this.testStatusCode < Constants.TEST_STATUS_CODE_SAMPLE_PRINT_COMPLETED -> {
this.testStatusCode = Constants.TEST_STATUS_CODE_SAMPLE_PRINT_COMPLETED
hemoCubeViewModel.messages.postValue( hemoCubeViewModel.messages.postValue(
getString(R.string.power_bank) getString(R.string.data_collected_processing_data)
) )
} val resultLines = resultData.split("\\s+(?=LB|LS)".toRegex())
var bufferIntensity = resultLines[1].split(' ')[1].trim()
currentResultData.contains("#SS2") && this.testStatusCode < TestStatus.FIRST_GAIN_STARTED.code -> { led1BufferForDevice = if (isUsingExistingBuffer) {
this.testStatusCode = TestStatus.FIRST_GAIN_STARTED.code sharedPreferences.getString(Constants.BUFFER_VALUE_1, "")?.toDoubleOrNull()!!
hemoCubeViewModel.messages.postValue("1.3X Gain Started") } else {
} bufferIntensity.toDoubleOrNull()!!
}
currentResultData.contains("#SC2") && this.testStatusCode < TestStatus.FIRST_GAIN_COMPLETED.code -> { bufferIntensity = resultLines[2].split(' ')[1].trim()
this.testStatusCode = TestStatus.FIRST_GAIN_COMPLETED.code led2BufferForDevice = if (isUsingExistingBuffer) {
hemoCubeViewModel.messages.postValue("1.3X Gain Completed") sharedPreferences.getString(Constants.BUFFER_VALUE_2, "")?.toDoubleOrNull()!!
fetchResult() } else {
} bufferIntensity.toDoubleOrNull()!!
}
currentResultData.contains("#SS3") && this.testStatusCode < TestStatus.SECOND_GAIN_STARTED.code -> { bufferIntensity = resultLines[3].split(' ')[1].trim()
this.testStatusCode = TestStatus.SECOND_GAIN_STARTED.code led3BufferForDevice = if (isUsingExistingBuffer) {
hemoCubeViewModel.messages.postValue("2X Gain Started") sharedPreferences.getString(Constants.BUFFER_VALUE_3, "")?.toDoubleOrNull()!!
} } else {
bufferIntensity.toDoubleOrNull()!!
currentResultData.contains("#SC3") && this.testStatusCode < TestStatus.SECOND_GAIN_COMPLETED.code -> { }
this.testStatusCode = TestStatus.SECOND_GAIN_COMPLETED.code bufferIntensity = resultLines[4].split(' ')[1].trim()
hemoCubeViewModel.messages.postValue("2X Gain Completed") led4BufferForDevice = if (isUsingExistingBuffer) {
fetchResult() sharedPreferences.getString(Constants.BUFFER_VALUE_4, "")?.toDoubleOrNull()!!
} } else {
bufferIntensity.toDoubleOrNull()!!
currentResultData.contains("#SS5") && this.testStatusCode < TestStatus.FORTH_GAIN_STARTED.code -> {
this.testStatusCode = TestStatus.FORTH_GAIN_STARTED.code
hemoCubeViewModel.messages.postValue("7.6X Gain Started")
}
currentResultData.contains("#SC5") && this.testStatusCode < TestStatus.FORTH_GAIN_COMPLETED.code -> {
this.testStatusCode = TestStatus.FORTH_GAIN_COMPLETED.code
hemoCubeViewModel.messages.postValue("7.6X Gain Completed")
fetchResult()
}
(resultData.contains("#LS") && this.testStatusCode < TestStatus.SECOND_EMPTY_AIR_READING_STARTED.code) -> {
// air reading 2
this.testStatusCode = TestStatus.SECOND_EMPTY_AIR_READING_STARTED.code
hemoCubeViewModel.messages.postValue("Air reading started")
}
(resultData.contains("#LC") && this.testStatusCode < TestStatus.SECOND_EMPTY_AIR_READING_COMPLETED.code) -> {
// air reading 2, print values
this.testStatusCode = TestStatus.SECOND_EMPTY_AIR_READING_COMPLETED.code
hemoCubeViewModel.messages.postValue("Air reading completed")
fetchResult()
}
resultData.contains("REND") && this.testStatusCode < TestStatus.SAMPLE_PRINT_COMPLETED.code -> {
handleSampleCompleted()
}
currentResultData.contains("REND")
&& this.testStatusCode >= TestStatus.FIRST_EMPTY_AIR_READING_COMPLETED.code
&& this.testStatusCode < TestStatus.FIRST_EMPTY_AIR_READING_PRINT_COMPLETED.code -> {
this.testStatusCode = TestStatus.FIRST_GAIN_PRINT_COMPLETED.code
hemoCubeViewModel.messages.postValue("First air reading completed")
val resultLines = currentResultData.split("\\s+(?=LB|LS)".toRegex())
DataHolder.hemoCubeTestData?.apply {
led1Air1 = resultLines[5].split(' ')[1].trim().toDoubleOrNull()!!
led2Air1 = resultLines[6].split(' ')[1].trim().toDoubleOrNull()!!
led3Air1 = resultLines[7].split(' ')[1].trim().toDoubleOrNull()!!
led4Air1 = resultLines[8].split(' ')[1].split('\r')[0].trim().toDoubleOrNull()!!
} }
startBufferProcess() var sampleIntensity = resultLines[5].split(' ')[1].trim()
currentResultData = "" led1SampleForDevice = resultLines[5].split(' ')[1].trim().toDoubleOrNull()!!
} sampleIntensity = resultLines[6].split(' ')[1].trim()
led2SampleForDevice = resultLines[6].split(' ')[1].trim().toDoubleOrNull()!!
currentResultData.contains("REND") sampleIntensity = resultLines[7].split(' ')[1].trim()
&& this.testStatusCode >= TestStatus.SECOND_EMPTY_AIR_READING_COMPLETED.code led3SampleForDevice = resultLines[7].split(' ')[1].trim().toDoubleOrNull()!!
&& this.testStatusCode < TestStatus.SECOND_EMPTY_AIR_PRINT_COMPLETED.code -> { sampleIntensity = resultLines[8].split(' ')[1].split('\r')[0].trim()
this.testStatusCode = TestStatus.SECOND_EMPTY_AIR_PRINT_COMPLETED.code led4SampleForDevice =
hemoCubeViewModel.messages.postValue("Second air reading completed") resultLines[8].split(' ')[1].split('\r')[0].trim().toDoubleOrNull()!!
processResult()
val resultLines = currentResultData.split("\\s+(?=LB|LS)".toRegex())
DataHolder.hemoCubeTestData?.apply {
led1Air2 = resultLines[5].split(' ')[1].trim().toDoubleOrNull()!!
led2Air2 = resultLines[6].split(' ')[1].trim().toDoubleOrNull()!!
led3Air2 = resultLines[7].split(' ')[1].trim().toDoubleOrNull()!!
led4Air2 = resultLines[8].split(' ')[1].split('\r')[0].trim().toDoubleOrNull()!!
}
sendSecondGainCommand()
currentResultData = ""
}
currentResultData.contains("REND")
&& this.testStatusCode >= TestStatus.FIRST_GAIN_COMPLETED.code
&& this.testStatusCode < TestStatus.FIRST_GAIN_PRINT_COMPLETED.code -> {
this.testStatusCode = TestStatus.FIRST_GAIN_PRINT_COMPLETED.code
hemoCubeViewModel.messages.postValue("1.3X gain data gathered")
val resultLines = currentResultData.split("\\s+(?=LB|LS)".toRegex())
DataHolder.hemoCubeTestData?.apply {
led1Gain1 = resultLines[5].split(' ')[1].trim().toDoubleOrNull()!!
led2Gain1 = resultLines[6].split(' ')[1].trim().toDoubleOrNull()!!
led3Gain1 = resultLines[7].split(' ')[1].trim().toDoubleOrNull()!!
led4Gain1 = resultLines[8].split(' ')[1].split('\r')[0].trim().toDoubleOrNull()!!
}
sendSecondGainCommand()
currentResultData = ""
}
currentResultData.contains("REND")
&& this.testStatusCode >= TestStatus.FIRST_GAIN_PRINT_COMPLETED.code
&& this.testStatusCode < TestStatus.SECOND_GAIN_PRINT_COMPLETED.code -> {
this.testStatusCode = TestStatus.SECOND_GAIN_PRINT_COMPLETED.code
hemoCubeViewModel.messages.postValue("2X gain data gathered")
val resultLines = currentResultData.split("\\s+(?=LB|LS)".toRegex())
DataHolder.hemoCubeTestData?.apply {
led1Gain2 = resultLines[5].split(' ')[1].trim().toDoubleOrNull()!!
led2Gain2 = resultLines[6].split(' ')[1].trim().toDoubleOrNull()!!
led3Gain2 = resultLines[7].split(' ')[1].trim().toDoubleOrNull()!!
led4Gain2 = resultLines[8].split(' ')[1].split('\r')[0].trim().toDoubleOrNull()!!
}
sendForthGainCommand()
currentResultData = ""
}
currentResultData.contains("REND")
&& this.testStatusCode >= TestStatus.SECOND_GAIN_PRINT_COMPLETED.code
&& this.testStatusCode < TestStatus.FORTH_GAIN_PRINT_COMPLETED.code -> {
this.testStatusCode = TestStatus.FORTH_GAIN_PRINT_COMPLETED.code
hemoCubeViewModel.messages.postValue("7.6X gain data gathered")
val resultLines = currentResultData.split("\\s+(?=LB|LS)".toRegex())
DataHolder.hemoCubeTestData?.apply {
led1Gain4 = resultLines[5].split(' ')[1].trim().toDoubleOrNull()!!
led2Gain4 = resultLines[6].split(' ')[1].trim().toDoubleOrNull()!!
led3Gain4 = resultLines[7].split(' ')[1].trim().toDoubleOrNull()!!
led4Gain4 = resultLines[8].split(' ')[1].split('\r')[0].trim().toDoubleOrNull()!!
}
finishReading()
} }
} }
} }
fun finishReading() { private fun showError() {
repeatReadingCount += 1
if (readingsPerSample == 1) {
activity?.runOnUiThread {
binding.btnSubmit.visibility = View.VISIBLE
binding.btnSubmit.isEnabled = true
binding.btnSubmit.isClickable = true
// binding.clParent.setBackgroundColor(Color.parseColor("#edfffd"))
binding.ivCheck.visibility = View.VISIBLE
}
} else {
hemoCubeViewModel.uploadHemoCubeResultToDatabase(
isOnline, true, sharedPreferences.getString(Constants.KIT_NUMBER, "")
)
}
}
fun handleSampleCompleted() {
this.testStatusCode = TestStatus.SAMPLE_PRINT_COMPLETED.code
hemoCubeViewModel.messages.postValue(
getString(R.string.data_collected_processing_data)
)
val resultLines = resultData.split("\\s+(?=LB|LS)".toRegex())
var bufferIntensity = resultLines[1].split(' ')[1].trim()
led1BufferForDevice = if (isUsingExistingBuffer) {
sharedPreferences.getString(Constants.BUFFER_VALUE_1, "")?.toDoubleOrNull()!!
} else {
bufferIntensity.toDoubleOrNull()!!
}
bufferIntensity = resultLines[2].split(' ')[1].trim()
led2BufferForDevice = if (isUsingExistingBuffer) {
sharedPreferences.getString(Constants.BUFFER_VALUE_2, "")?.toDoubleOrNull()!!
} else {
bufferIntensity.toDoubleOrNull()!!
}
bufferIntensity = resultLines[3].split(' ')[1].trim()
led3BufferForDevice = if (isUsingExistingBuffer) {
sharedPreferences.getString(Constants.BUFFER_VALUE_3, "")?.toDoubleOrNull()!!
} else {
bufferIntensity.toDoubleOrNull()!!
}
bufferIntensity = resultLines[4].split(' ')[1].trim()
led4BufferForDevice = if (isUsingExistingBuffer) {
sharedPreferences.getString(Constants.BUFFER_VALUE_4, "")?.toDoubleOrNull()!!
} else {
bufferIntensity.toDoubleOrNull()!!
}
led1SampleForDevice = resultLines[5].split(' ')[1].trim().toDoubleOrNull()!!
led2SampleForDevice = resultLines[6].split(' ')[1].trim().toDoubleOrNull()!!
led3SampleForDevice = resultLines[7].split(' ')[1].trim().toDoubleOrNull()!!
led4SampleForDevice =
resultLines[8].split(' ')[1].split('\r')[0].trim().toDoubleOrNull()!!
processResult()
if (Constants.PQ_MODE) {
finishReading()
} else {
sendFirstGainCommand()
}
currentResultData = ""
}
fun processV1HardwareId(resultData: String) {
val hardwareId = extractV1HardwareId(resultData)
if (!hardwareId.isNullOrBlank()) {
updateDeviceId(hardwareId)
activity?.runOnUiThread {
binding.btnPlacebuffer.visibility = View.VISIBLE
}
hemoCubeViewModel.messages.postValue(getString(R.string.start))
} else {
hemoCubeViewModel.messages.postValue("Config error")
}
if (!Constants.DEVICE_CONFIGURATION.containsKey(deviceHardwareId)) {
assignDefaultDevice(resultData)
testState.allErrorMessages += "Calibration configuration for this device id is not found\n"
}
if (!Constants.BUFFER_INTENSITY_THRESHOLDS.containsKey(deviceHardwareId)) {
testState.allErrorMessages += "ADC thresholds for this device id are not found\n"
}
}
fun extractV1HardwareId(input: String): String? {
val regex = Regex("SN (\\S+)")
val matchResult = regex.find(input)
return matchResult?.groupValues?.get(1)
}
fun processV2HardwareId(resultData: String) {
val hardwareId = extractV2HardwareId(resultData)
if (!hardwareId.isNullOrBlank()) {
updateDeviceId(hardwareId)
activity?.runOnUiThread {
binding.btnPlacebuffer.visibility = View.VISIBLE
}
hemoCubeViewModel.messages.postValue(getString(R.string.start))
} else {
hemoCubeViewModel.messages.postValue("Config error")
}
if (!Constants.DEVICE_CONFIGURATION.containsKey(deviceHardwareId)) {
assignDefaultDevice(resultData)
testState.allErrorMessages += "Calibration configuration for this device id is not found\n"
}
if (!Constants.BUFFER_INTENSITY_THRESHOLDS.containsKey(deviceHardwareId)) {
testState.allErrorMessages += "ADC thresholds for this device id are not found\n"
}
}
fun assignDefaultDevice(configData: String) {
deviceHardwareId = "HCV-000-3001"
testStatusCode = TestStatus.CONFIG_COMPLETED.code
activity?.runOnUiThread { activity?.runOnUiThread {
binding.btnPlacebuffer.visibility = View.VISIBLE UIUtils.createAlertDialog(requireContext(),
} "Device Error",
hemoCubeViewModel.messages.postValue(getString(R.string.start)) "Something is wrong with the device, please disconnect and reconnect the device and test the user again",
} getString(R.string.noo),
"Yes",
object : MyDialogListener {
override fun onClickNegativeButton() {}
fun extractV2HardwareId(input: String): String? { override fun onClickPositiveButton() {
val pattern = Regex("SNS\\s*(.*?)\\s*SNE") startActivity(Intent(requireActivity(), DashboardActivity::class.java))
val matchResult: MatchResult? = pattern.find(input) }
})
return matchResult?.groups?.get(1)?.value
}
fun updateDeviceId(hardwareId: String?) {
hardwareId?.let {
deviceHardwareId += it
with(sharedPreferences.edit()) {
putString(Constants.DEVICE_ID, deviceHardwareId)
apply()
}
testStatusCode = TestStatus.CONFIG_COMPLETED.code
} }
} }
fun handleBackButtonPress() { fun handleBackButtonPress() {
if (isTestOngoing) { if (isTestOngoing) {
// If the test is ongoing, don't allow the back button action
// You can optionally show a message to the user indicating why the back button is disabled
// For example, show a Toast or Snackbar.
showToast(R.string.test_go_noback) showToast(R.string.test_go_noback)
} else { } else {
// If the test is not ongoing, you can trigger the back action of the hosting activity
activity?.onBackPressed() activity?.onBackPressed()
} }
} }
@@ -728,7 +461,7 @@ class HemoCubeFragment : Fragment() {
val led2Average = log10(led2BufferForDevice.div(led2SampleForDevice)) val led2Average = log10(led2BufferForDevice.div(led2SampleForDevice))
val led3Average = log10(led3BufferForDevice.div(led3SampleForDevice)) val led3Average = log10(led3BufferForDevice.div(led3SampleForDevice))
val led4Average = log10(led4BufferForDevice.div(led4SampleForDevice)) val led4Average = log10(led4BufferForDevice.div(led4SampleForDevice))
val deviceRatio = led2Average / led1Average val deviceRatio = led3Average / led1Average
if (led1BufferForDevice < Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(0) if (led1BufferForDevice < Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(0)
?.get(0)!! ?.get(0)!!
@@ -742,11 +475,11 @@ class HemoCubeFragment : Fragment() {
3 3
)?.get(0)!! )?.get(0)!!
) { ) {
// validationError = true validationError = true
testState.allErrorMessages += "Error: Invalid Test. Improper buffer reading (low)" allErrorMessages += "Error: Invalid Test. Improper buffer reading (low)"
activity?.runOnUiThread { activity?.runOnUiThread {
binding.errorMessage.text = getString(R.string.error_improper_buffer_low) binding.errorMessage.text = getString(R.string.error_improper_buffer_low)
// binding.errorMessage.visibility = View.VISIBLE binding.errorMessage.visibility = View.VISIBLE
} }
} }
@@ -762,15 +495,19 @@ class HemoCubeFragment : Fragment() {
3 3
)?.get(1)!! )?.get(1)!!
) { ) {
// validationError = true validationError = true
testState.allErrorMessages += "Error: Invalid Test. Improper buffer reading (high)" + "\n" allErrorMessages += "Error: Invalid Test. Improper buffer reading (high)" + "\n"
activity?.runOnUiThread { activity?.runOnUiThread {
binding.errorMessage.text = binding.errorMessage.text =
getString(R.string.error_improper_buffer_high) getString(R.string.error_improper_buffer_high)
binding.errorMessage.visibility = View.VISIBLE binding.errorMessage.visibility = View.VISIBLE
binding.btnSubmit.isEnabled = true
binding.btnSubmit.isClickable = true
} }
} }
var gradient = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(0)?.get(0) var gradient = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(0)?.get(0)
var constant = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(0)?.get(1) var constant = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(0)?.get(1)
fittedAbs1 = gradient?.times(led1Average)?.plus(constant!!)!! fittedAbs1 = gradient?.times(led1Average)?.plus(constant!!)!!
@@ -783,64 +520,35 @@ class HemoCubeFragment : Fragment() {
constant = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(2)?.get(1) constant = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(2)?.get(1)
fittedAbs3 = gradient?.times(led3Average)?.plus(constant!!)!! fittedAbs3 = gradient?.times(led3Average)?.plus(constant!!)!!
gradient = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(0)?.get(0) gradient = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(3)?.get(0)
constant = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(0)?.get(1) constant = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(3)?.get(1)
fittedAbs4 = gradient?.times(led4Average)?.plus(constant!!)!! fittedAbs4 = gradient?.times(led4Average)?.plus(constant!!)!!
val slope1 = Constants.DEVICE_HB_PARAMETERS[deviceHardwareId]?.get(1)?.get(0) _predictedDenovixRatio = fittedAbs3.div(fittedAbs1)
val intercept1 = Constants.DEVICE_HB_PARAMETERS[deviceHardwareId]?.get(1)?.get(1)
val calculatedHb1 = (led1Average - intercept1!!) / slope1!!
val slope2 = Constants.DEVICE_HB_PARAMETERS[deviceHardwareId]?.get(3)?.get(0)
val intercept = Constants.DEVICE_HB_PARAMETERS[deviceHardwareId]?.get(3)?.get(1)
val calculatedHb2 = (led2Average - intercept!!) / slope2!!
val slope3 = Constants.DEVICE_HB_PARAMETERS[deviceHardwareId]?.get(2)?.get(0)
val intercept3 = Constants.DEVICE_HB_PARAMETERS[deviceHardwareId]?.get(2)?.get(1)
val calculatedHb3 = (led3Average - intercept3!!) / slope3!!
val slope4 = Constants.DEVICE_HB_PARAMETERS[deviceHardwareId]?.get(3)?.get(0)
val intercept4 = Constants.DEVICE_HB_PARAMETERS[deviceHardwareId]?.get(3)?.get(1)
val calculatedHb4 = (led4Average - intercept4!!) / slope4!!
calculatedPredictedDenovixRatio = fittedAbs3.div(fittedAbs1)
val slope = (led1Average - led2Average) / (435 - 415)
val calculatedSlopeRatio = abs(led3Average / slope)
val slopeClass = slopeRatioClassification(calculatedSlopeRatio)
if (fittedAbs1 <= fittedAbs2) { if (fittedAbs1 <= fittedAbs2) {
// validationError = true validationError = true
testState.allErrorMessages += "Error: Invalid Test. Problem with de-oxygenation" + "\n" allErrorMessages += "Error: Invalid Test. Problem with de-oxygenation" + "\n"
activity?.runOnUiThread { activity?.runOnUiThread {
binding.errorMessage.text = getString(R.string.error_invalid_test) binding.errorMessage.text = getString(R.string.error_invalid_test)
// binding.errorMessage.visibility = View.VISIBLE binding.errorMessage.visibility = View.VISIBLE
} }
} }
if (fittedAbs1 < 0 || fittedAbs2 < 0 || fittedAbs3 < 0 || fittedAbs4 < 0) { if (fittedAbs1 < 0 || fittedAbs2 < 0 || fittedAbs3 < 0 || fittedAbs4 < 0) {
// validationError = true
activity?.runOnUiThread {
binding.errorMessage.text = getString(R.string.error_negative_abs)
// binding.errorMessage.visibility = View.VISIBLE
}
}
var absorbanceLowerLimit = 0.0
if (led1Average < absorbanceLowerLimit || led2Average < absorbanceLowerLimit || led3Average < absorbanceLowerLimit || led4Average < absorbanceLowerLimit) {
validationError = true validationError = true
activity?.runOnUiThread { activity?.runOnUiThread {
binding.errorMessage.text = "Invalid" binding.errorMessage.text = getString(R.string.error_negative_abs)
binding.errorMessage.visibility = View.VISIBLE binding.errorMessage.visibility = View.VISIBLE
} }
} }
if (fittedAbs3 < 0.1) { if (fittedAbs3 < 0.1) {
// validationError = true validationError = true
testState.allErrorMessages += "Error: Low Hb. Repeat test" + "\n" allErrorMessages += "Error: Low Hb. Repeat test" + "\n"
activity?.runOnUiThread { activity?.runOnUiThread {
binding.errorMessage.text = "Error: Low Hb. Repeat test" binding.errorMessage.text = "Error: Low Hb. Repeat test"
// binding.errorMessage.visibility = View.VISIBLE binding.errorMessage.visibility = View.VISIBLE
} }
} }
@@ -863,22 +571,15 @@ class HemoCubeFragment : Fragment() {
this.abs2 = fittedAbs2 this.abs2 = fittedAbs2
this.abs3 = fittedAbs3 this.abs3 = fittedAbs3
this.abs4 = fittedAbs4 this.abs4 = fittedAbs4
this.hb3 = calculatedHb3
this.hb4 = calculatedHb4
this.deviceRatio = deviceRatio this.deviceRatio = deviceRatio
this.calculatedRatio = calculateRatio(deviceRatio) this.calculatedRatio = calculateRatio(deviceRatio)
this.predictedDenovixRatio = calculatedPredictedDenovixRatio this.predictedDenovixRatio = _predictedDenovixRatio
this.slopeRatio = calculatedSlopeRatio
this.coefficients = currentDeviceData?.coefficients?.get(0) this.coefficients = currentDeviceData?.coefficients?.get(0)
.toString() + ", " + currentDeviceData?.coefficients?.get(1).toString() .toString() + ", " + currentDeviceData?.coefficients?.get(1).toString()
this.classificationResult = findResult(calculatedRatio)
this.prdClassification = absorbanceBasedClassification(predictedDenovixRatio) this.prdClassification = absorbanceBasedClassification(predictedDenovixRatio)
this.deviceRatioClass = deviceRatioClassification(deviceRatio) hemoCubeViewModel.messages.postValue(this.prdClassification)
this.slopeRatioClass = slopeClass this.errorMessages = allErrorMessages
this.classificationResult = deviceRatioClass //findResult(calculatedRatio)
hemoCubeViewModel.messages.postValue("${this.deviceRatioClass} ${if (led4Average < 0.17) " - Low Hb" else ""}\n")
if (DataHolder.hemoCubeTestData?.testType == "HB")
hemoCubeViewModel.messages.postValue("Hb: $calculatedHb4")
this.errorMessages = testState.allErrorMessages
this.resultData = deviceLog this.resultData = deviceLog
this.batteryLevel = hemoCubeViewModel.getBatteryLevel().toString() this.batteryLevel = hemoCubeViewModel.getBatteryLevel().toString()
this.batteryCapacity = this.batteryCapacity =
@@ -899,6 +600,15 @@ class HemoCubeFragment : Fragment() {
apply() apply()
} }
} }
// if (!validationError) {
activity?.runOnUiThread {
binding.btnSubmit.visibility = View.VISIBLE
binding.btnSubmit.isEnabled = true
binding.btnSubmit.isClickable = true
binding.clParent.setBackgroundColor(Color.parseColor("#edfffd"))
}
// }
} catch (e: Exception) { } catch (e: Exception) {
Toast.makeText( Toast.makeText(
requireContext(), requireContext(),
@@ -916,6 +626,14 @@ class HemoCubeFragment : Fragment() {
if (calculatedRatio < 0.05) if (calculatedRatio < 0.05)
return getString(R.string.error_repeat_test_higher_volume) return getString(R.string.error_repeat_test_higher_volume)
if (calculatedRatio in 0.05..0.155) { if (calculatedRatio in 0.05..0.155) {
activity?.runOnUiThread {
binding.tvSubtitle4.setTextColor(
ContextCompat.getColor(
requireContext(),
R.color.brightGreen
)
)
}
return getString(R.string.normal) return getString(R.string.normal)
} }
if (calculatedRatio in 0.155..0.175) if (calculatedRatio in 0.155..0.175)
@@ -939,80 +657,19 @@ class HemoCubeFragment : Fragment() {
return getString(R.string.invalid) return getString(R.string.invalid)
} }
fun deviceRatioClassification(ratio: Double?): String {
try {
if (ratio != null) {
if (ratio in 0.1..0.29) {
// setSubtitleTextColor(R.color.green_2)
return "Normal"
}
if (ratio in 0.29..0.32)
return "Negative Borderline, Repeat Test"
if (ratio in 0.32..0.35)
return "Sickle Cell Trait"
if (ratio in 0.35..0.38)
return "Positive for Sickle Cell. HPLC for Confirmation"
if (ratio in 0.38..0.5)
return "Sickle Cell Disease"
} else {
return "Invalid"
}
} catch (e: Exception) {
handleException(e)
return "Error"
}
return "Invalid"
}
fun setSubtitleTextColor(colorResId: Int) {
activity?.runOnUiThread {
binding.tvSubtitle4.setTextColor(ContextCompat.getColor(requireContext(), colorResId))
}
}
fun handleException(e: Exception) {
showToast(R.string.error_classification)
Firebase.crashlytics.recordException(e)
}
fun slopeRatioClassification(ratio: Double?): String {
try {
hemoCubeViewModel.messages.postValue("result classification")
if (ratio != null) {
if (ratio in 0.0..30.0)
return getString(R.string.normal)
if (ratio in 30.0..35.0)
return getString(R.string.negative_borderline)
if (ratio in 35.0..50.0)
return getString(R.string.sickle_cell_trait)
if (ratio in 50.0..60.0)
return getString(R.string.positive_for_sickle_cell)
if (ratio > 60.0)
return getString(R.string.sickle_cell_disease)
} else {
return getString(R.string.invalid)
}
} catch (e: Exception) {
showToast(R.string.error_classification)
Firebase.crashlytics.recordException(e)
return getString(R.string.error)
}
return getString(R.string.invalid)
}
private fun absorbanceBasedClassification(predictedDenovixRatio: Double?): String { private fun absorbanceBasedClassification(predictedDenovixRatio: Double?): String {
try { try {
hemoCubeViewModel.messages.postValue("result classification") hemoCubeViewModel.messages.postValue("result classification")
if (predictedDenovixRatio != null) { if (predictedDenovixRatio != null) {
if (predictedDenovixRatio in 0.0..0.16) { if (predictedDenovixRatio in 0.0..0.16) {
// activity?.runOnUiThread { activity?.runOnUiThread {
// binding.tvSubtitle4.setTextColor( binding.tvSubtitle4.setTextColor(
// ContextCompat.getColor( ContextCompat.getColor(
// requireContext(), requireContext(),
// R.color.brightGreen R.color.brightGreen
// ) )
// ) )
// } }
return getString(R.string.normal) return getString(R.string.normal)
} }
if (predictedDenovixRatio in 0.16..0.165) if (predictedDenovixRatio in 0.16..0.165)
@@ -1045,7 +702,7 @@ class HemoCubeFragment : Fragment() {
binding.btnPlacebuffer.visibility = View.GONE binding.btnPlacebuffer.visibility = View.GONE
} }
(activity as HemocubeActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.START_BUFFER_COMMAND, (activity as HemocubeActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.startBuffer,
object : UsbServiceListener { object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {} override fun onUsbRead(data: ByteArray?) {}
@@ -1056,61 +713,10 @@ class HemoCubeFragment : Fragment() {
} }
private fun startSampleProcess() { private fun startSampleProcess() {
testingTrace.start()
hemoCubeViewModel.progressBar.postValue(true) hemoCubeViewModel.progressBar.postValue(true)
(activity as HemocubeActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.START_SAMPLE, (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 sendFirstGainCommand() {
hemoCubeViewModel.progressBar.postValue(true)
(activity as HemocubeActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.FIRST_GAIN_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {}
override fun onUsbError(e: Exception?) {
hemoCubeViewModel.progressBar.postValue(false)
}
})
}
private fun sendSecondGainCommand() {
hemoCubeViewModel.progressBar.postValue(true)
(activity as HemocubeActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.SECOND_GAIN_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {}
override fun onUsbError(e: Exception?) {
hemoCubeViewModel.progressBar.postValue(false)
}
})
}
private fun sendThirdGainCommand() {
hemoCubeViewModel.progressBar.postValue(true)
(activity as HemocubeActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.THIRD_GAIN_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {}
override fun onUsbError(e: Exception?) {
hemoCubeViewModel.progressBar.postValue(false)
}
})
}
private fun sendForthGainCommand() {
hemoCubeViewModel.progressBar.postValue(true)
(activity as HemocubeActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.FORTH_GAIN_COMMAND,
object : UsbServiceListener { object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {} override fun onUsbRead(data: ByteArray?) {}
@@ -1123,7 +729,7 @@ class HemoCubeFragment : Fragment() {
private fun fetchResult() { private fun fetchResult() {
hemoCubeViewModel.progressBar.postValue(true) hemoCubeViewModel.progressBar.postValue(true)
(activity as HemocubeActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.PRINT_COMMAND, (activity as HemocubeActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.getSample,
object : UsbServiceListener { object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {} override fun onUsbRead(data: ByteArray?) {}
@@ -1138,4 +744,10 @@ class HemoCubeFragment : Fragment() {
val coefficient2 = currentDeviceData?.coefficients?.get(1) ?: 0.0 val coefficient2 = currentDeviceData?.coefficients?.get(1) ?: 0.0
return coefficient1 * ratio + coefficient2 return coefficient1 * ratio + coefficient2
} }
}
private fun checkDeviceIdMismatch(deviceId: String, loginId: String): Boolean {
if (!deviceId.isNullOrEmpty() && !loginId.isNullOrEmpty() && deviceId.last() != loginId.last())
return true
return false
}
}

View File

@@ -3,24 +3,21 @@ package com.example.hpostesting.presentation.hemocube
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.IntentFilter import android.content.IntentFilter
import android.content.SharedPreferences
import android.os.BatteryManager import android.os.BatteryManager
import android.util.Log import android.util.Log
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import com.example.hpostesting.data.CsvWriter
import com.example.hpostesting.data.DataHolder import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.NetworkStatusLiveData import com.example.hpostesting.data.NetworkStatusLiveData
import com.example.hpostesting.data.Result import com.example.hpostesting.data.Result
import com.example.hpostesting.data.constant.Constants import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.dao.HemoCubeBufferDao
import com.example.hpostesting.data.dao.HemoCubeDao import com.example.hpostesting.data.dao.HemoCubeDao
import com.example.hpostesting.data.datasource.LocalFileDataSource
import com.example.hpostesting.data.model.Response import com.example.hpostesting.data.model.Response
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionRequest
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionResponse
import com.example.hpostesting.data.model.log.UploadLogsResponse import com.example.hpostesting.data.model.log.UploadLogsResponse
import com.example.hpostesting.data.model.login.LoginRequest import com.example.hpostesting.data.model.login.LoginRequest
import com.example.hpostesting.data.model.login.LoginResponse import com.example.hpostesting.data.model.login.LoginResponse
@@ -34,9 +31,10 @@ import com.example.hpostesting.data.model.patient.toHemoCubeTestData
import com.example.hpostesting.data.model.updates.CheckUpdateRequest import com.example.hpostesting.data.model.updates.CheckUpdateRequest
import com.example.hpostesting.data.model.updates.CheckUpdateResponse import com.example.hpostesting.data.model.updates.CheckUpdateResponse
import com.example.hpostesting.data.model.updates.DeviceUpdateRequest import com.example.hpostesting.data.model.updates.DeviceUpdateRequest
import com.example.hpostesting.data.repository.DatabaseRepository
import com.example.hpostesting.data.repository.Repository import com.example.hpostesting.data.repository.Repository
import com.example.hpostesting.domain.CheckUpdateWorker
import com.example.hpostesting.domain.LogFileManager import com.example.hpostesting.domain.LogFileManager
import com.example.hpostesting.presentation.hemocube.HemoCubeFragmentDirections.Companion
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.MediaType.Companion.toMediaTypeOrNull
@@ -46,31 +44,24 @@ import okhttp3.ResponseBody
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Calendar import java.util.Calendar
import java.util.Locale import java.util.Locale
import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject
@Suppress("MemberVisibilityCanBePrivate")
@HiltViewModel @HiltViewModel
class HemoCubeViewModel @Inject constructor( class HemoCubeViewModel @Inject constructor(
private val hemoCubeDao: HemoCubeDao, private val hemoCubeDao: HemoCubeDao,
private val hemoCubeBufferDao: HemoCubeBufferDao,
private val repository: Repository, private val repository: Repository,
private val databaseRepository: DatabaseRepository,
private val logFileManager: LogFileManager, private val logFileManager: LogFileManager,
private val localFileDataSource: LocalFileDataSource, context: Context
context: Context,
) : ViewModel() { ) : ViewModel() {
var isServiceConnected = false var isServiceConnected = false
val progressBar = MutableLiveData(false) val progressBar = MutableLiveData(false)
private val testDetails = DataHolder.selectedTest?.toHemoCubeTestData() private val testDetails = DataHolder.selectedTest?.toHemoCubeTestData()
val messages = MutableLiveData<String>() val messages = MutableLiveData<String>()
private val sharedPreference = private val sharedPreference: SharedPreferences =
context.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE) context.getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE)
private val workManager = WorkManager.getInstance(context) val deviceProvisionResponse = MutableLiveData<Result<DeviceProvisionResponse>>()
// init {
// startPeriodicCheckUpdate()
// }
val loginResponse = MutableLiveData<Result<LoginResponse>>() val loginResponse = MutableLiveData<Result<LoginResponse>>()
@@ -79,7 +70,6 @@ class HemoCubeViewModel @Inject constructor(
val checkUpdate = MutableLiveData<Result<CheckUpdateResponse>>() val checkUpdate = MutableLiveData<Result<CheckUpdateResponse>>()
val deviceUpdate = MutableLiveData<Result<ResponseBody>>() val deviceUpdate = MutableLiveData<Result<ResponseBody>>()
val downloadcertificate = MutableLiveData<Result<ResponseBody>>()
val uploadLogs = MutableLiveData<Result<UploadLogsResponse>?>() val uploadLogs = MutableLiveData<Result<UploadLogsResponse>?>()
@@ -88,7 +78,6 @@ class HemoCubeViewModel @Inject constructor(
private val _networkStatusLiveData = NetworkStatusLiveData(context) private val _networkStatusLiveData = NetworkStatusLiveData(context)
val allUserData = hemoCubeDao.getAll() val allUserData = hemoCubeDao.getAll()
val allKitTestData = hemoCubeBufferDao.getAll()
val deviceData = MutableLiveData<DeviceData?>() val deviceData = MutableLiveData<DeviceData?>()
@@ -104,7 +93,7 @@ class HemoCubeViewModel @Inject constructor(
} }
fun uploadHemoCubeResultToDatabase( fun uploadHemoCubeResultToDatabase(
isOnline: Boolean, testStatus: Boolean, kitSerial: String?, isOnline: Boolean, testStatus: Boolean, kitSerial: String?
) = viewModelScope.launch { ) = viewModelScope.launch {
if (kitSerial != null) { if (kitSerial != null) {
testDetails?.kitSerial = kitSerial testDetails?.kitSerial = kitSerial
@@ -128,58 +117,41 @@ class HemoCubeViewModel @Inject constructor(
} }
} }
fun deviceProvision(deviceProvisionRequest: DeviceProvisionRequest) = viewModelScope.launch {
deviceProvisionResponse.postValue(Result.Loading())
databaseRepository.deviceProvision(deviceProvisionRequest).let {
deviceProvisionResponse.postValue(it)
}
}
fun login(loginRequest: LoginRequest) = viewModelScope.launch { fun login(loginRequest: LoginRequest) = viewModelScope.launch {
loginResponse.postValue(Result.Loading()) loginResponse.postValue(Result.Loading())
repository.login(loginRequest).let { databaseRepository.login(loginRequest).let {
loginResponse.postValue(it) loginResponse.postValue(it)
} }
} }
fun uploadResult(molbioV2ResultRequest: MolbioV2ResultRequest) = viewModelScope.launch { fun uploadResult(molbioV2ResultRequest: MolbioV2ResultRequest) = viewModelScope.launch {
resultUpload.postValue(Result.Loading()) resultUpload.postValue(Result.Loading())
repository.uploadResults(molbioV2ResultRequest).let { databaseRepository.uploadResults(molbioV2ResultRequest).let {
resultUpload.postValue(it) resultUpload.postValue(it)
} }
} }
fun checkUpdate(checkUpdateRequest: CheckUpdateRequest) = viewModelScope.launch { fun checkUpdate(checkUpdateRequest: CheckUpdateRequest) = viewModelScope.launch {
checkUpdate.postValue(Result.Loading()) checkUpdate.postValue(Result.Loading())
repository.checkUpdate(checkUpdateRequest).let { databaseRepository.checkUpdate(checkUpdateRequest).let {
checkUpdate.postValue(it) checkUpdate.postValue(it)
} }
} }
fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest) = viewModelScope.launch { fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest) = viewModelScope.launch {
deviceUpdate.postValue(Result.Loading()) deviceUpdate.postValue(Result.Loading())
repository.deviceUpdate(deviceUpdateRequest).let { databaseRepository.deviceUpdate(deviceUpdateRequest).let {
deviceUpdate.postValue(it) deviceUpdate.postValue(it)
} }
} }
fun downloadClientCertificate() = viewModelScope.launch {
downloadcertificate.postValue(Result.Loading())
repository.downloadClientCertificate().let {
downloadcertificate.postValue(it)
}
}
fun startPeriodicCheckUpdate() {
val periodicRequest = PeriodicWorkRequestBuilder<CheckUpdateWorker>(
repeatInterval = 1, repeatIntervalTimeUnit = TimeUnit.MINUTES
).build()
workManager.enqueueUniquePeriodicWork(
"checkUpdateWorker", ExistingPeriodicWorkPolicy.KEEP, periodicRequest
)
}
fun uploadLogs() = viewModelScope.launch { fun uploadLogs() = viewModelScope.launch {
uploadLogs.postValue(Result.Loading()) uploadLogs.postValue(Result.Loading())
val logFile = logFileManager.createLogFile().let { file -> val logFile = logFileManager.createLogFile().let { file ->
@@ -187,66 +159,13 @@ class HemoCubeViewModel @Inject constructor(
val multipartFile = val multipartFile =
requestBody?.let { MultipartBody.Part.createFormData("logFile", file?.name, it) } requestBody?.let { MultipartBody.Part.createFormData("logFile", file?.name, it) }
multipartFile?.let { partFile -> multipartFile?.let { partFile ->
repository.uploadLogs(partFile).let { result -> databaseRepository.uploadLogs(partFile).let { result ->
uploadLogs.postValue(result) uploadLogs.postValue(result)
} }
} }
} }
} }
fun uploadHemoCubeResultToDatabaseForBufferCheck(
isOnline: Boolean,
bufferCheckData: BufferCheckData,
) =
viewModelScope.launch {
if (isOnline) {
try {
when (val response =
repository.addTestToDatabaseforBufferCheck(bufferCheckData)) {
is Response.Success -> {
Log.i("Testdb", "Data uploaded to Firestore successfully")
fireBaseUpload.postValue("Success")
bufferCheckData.localFlag = true
hemoCubeBufferDao.insertAll(bufferCheckData)
}
is Response.Error -> {
Log.e("Testdb", "Error uploading data to Firestore: $response")
fireBaseUpload.postValue("Error")
bufferCheckData.localFlag = true
hemoCubeBufferDao.insertAll(bufferCheckData)
}
else -> {}
}
} catch (e: Exception) {
Log.e("Testdb", "Exception during data upload: ${e.message}")
fireBaseUpload.postValue("Error")
}
} else {
hemoCubeBufferDao.insertAll(bufferCheckData)
fireBaseUpload.postValue("Local")
}
}
fun bulkAddResultKitTestToDb(bufferCheckData: BufferCheckData) {
viewModelScope.launch {
bufferCheckData.reportUploadTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
when (repository.addTestToDatabaseforBufferCheck(bufferCheckData)) {
is Response.Success -> {
fireBaseBulkUpload.postValue("Success")
updateBufferLocalFlag(bufferCheckData._id)
}
else -> {
fireBaseBulkUpload.postValue("Error")
}
}
}
}
fun uploadHemoCubeResultToDatabaseforbuffercheckN(bufferCheckData: BufferCheckData) = fun uploadHemoCubeResultToDatabaseforbuffercheckN(bufferCheckData: BufferCheckData) =
viewModelScope.launch { viewModelScope.launch {
addResultTestToDbforbuffercheck(bufferCheckData) addResultTestToDbforbuffercheck(bufferCheckData)
@@ -256,7 +175,7 @@ class HemoCubeViewModel @Inject constructor(
deviceData.postValue(deviceId?.let { repository.getDeviceDataById(it) }) deviceData.postValue(deviceId?.let { repository.getDeviceDataById(it) })
} }
fun parseData() { private fun parseData() {
testDetails?.deviceRatio = DataHolder.hemocubeResult testDetails?.deviceRatio = DataHolder.hemocubeResult
testDetails?.resultData = DataHolder.hemoCubeTestData?.resultData.toString() testDetails?.resultData = DataHolder.hemoCubeTestData?.resultData.toString()
testDetails?.location = DataHolder.location testDetails?.location = DataHolder.location
@@ -285,28 +204,16 @@ class HemoCubeViewModel @Inject constructor(
testDetails?.abs3 = DataHolder.hemoCubeTestData?.abs3 testDetails?.abs3 = DataHolder.hemoCubeTestData?.abs3
testDetails?.abs4 = DataHolder.hemoCubeTestData?.abs4 testDetails?.abs4 = DataHolder.hemoCubeTestData?.abs4
testDetails?.deviceRatio = DataHolder.hemoCubeTestData?.deviceRatio testDetails?.deviceRatio = DataHolder.hemoCubeTestData?.deviceRatio
testDetails?.slopeRatio = DataHolder.hemoCubeTestData?.slopeRatio
testDetails?.predictedDenovixRatio = DataHolder.hemoCubeTestData?.predictedDenovixRatio testDetails?.predictedDenovixRatio = DataHolder.hemoCubeTestData?.predictedDenovixRatio
testDetails?.calculatedRatio = DataHolder.hemoCubeTestData?.calculatedRatio testDetails?.calculatedRatio = DataHolder.hemoCubeTestData?.calculatedRatio
testDetails?.coefficients = DataHolder.hemoCubeTestData?.coefficients testDetails?.coefficients = DataHolder.hemoCubeTestData?.coefficients
testDetails?.incubationTime = DataHolder.hemoCubeTestData?.incubationTime.toString()
testDetails?.name = DataHolder.hemoCubeTestData?.name.toString()
testDetails?.birthYear = DataHolder.hemoCubeTestData?.birthYear.toString()
testDetails?.userImageURL = DataHolder.hemoCubeTestData?.userImageURL.toString()
testDetails?.classificationResult = DataHolder.hemoCubeTestData?.classificationResult!! testDetails?.classificationResult = DataHolder.hemoCubeTestData?.classificationResult!!
testDetails?.prdClassification = DataHolder.hemoCubeTestData?.prdClassification.toString() testDetails?.prdClassification = DataHolder.hemoCubeTestData?.prdClassification.toString()
testDetails?.deviceRatioClass = DataHolder.hemoCubeTestData?.deviceRatioClass.toString()
testDetails?.slopeRatioClass = DataHolder.hemoCubeTestData?.slopeRatioClass.toString()
testDetails?.errorMessages = DataHolder.hemoCubeTestData?.errorMessages.toString()
testDetails?.batteryLevel = DataHolder.hemoCubeTestData?.batteryLevel.toString() testDetails?.batteryLevel = DataHolder.hemoCubeTestData?.batteryLevel.toString()
testDetails?.batteryCapacity = DataHolder.hemoCubeTestData?.batteryCapacity.toString() testDetails?.batteryCapacity = DataHolder.hemoCubeTestData?.batteryCapacity.toString()
testDetails?.batteryMaxCapacity = DataHolder.hemoCubeTestData?.batteryMaxCapacity.toString() testDetails?.batteryMaxCapacity = DataHolder.hemoCubeTestData?.batteryMaxCapacity.toString()
testDetails?.batteryTemperature = DataHolder.hemoCubeTestData?.batteryTemperature.toString() testDetails?.batteryTemperature = DataHolder.hemoCubeTestData?.batteryTemperature.toString()
testDetails?.batteryVoltage = DataHolder.hemoCubeTestData?.batteryVoltage.toString() testDetails?.batteryVoltage = DataHolder.hemoCubeTestData?.batteryVoltage.toString()
testDetails?.quickCapture = DataHolder.hemoCubeTestData?.quickCapture!!
testDetails?.solution = DataHolder.hemoCubeTestData?.solution
testDetails?.concentration = DataHolder.hemoCubeTestData?.concentration
testDetails?.volume = DataHolder.hemoCubeTestData?.volume
} }
private fun addResultTestToDb() { private fun addResultTestToDb() {
@@ -326,24 +233,7 @@ class HemoCubeViewModel @Inject constructor(
Log.i("Testdb", "Data uploaded to Firestore successfully") Log.i("Testdb", "Data uploaded to Firestore successfully")
fireBaseUpload.postValue("Success") fireBaseUpload.postValue("Success")
testDetails.localFlag = true testDetails.localFlag = true
uploadResult( uploadResult(MolbioV2ResultRequest(listOf(MolbioV2Result(rawData = testDetails))))
MolbioV2ResultRequest(
mutableListOf(
MolbioV2Result(
rawData = testDetails,
analysisId = testDetails._id,
analysisDate = testDetails.testTime,
analysisStatus = testDetails.classificationResult,
thresholds = Constants.BUFFER_INTENSITY_THRESHOLDS[testDetails.deviceId].toString(),
interpretation = testDetails.classificationResult,
testId = testDetails._id,
testTime = testDetails.testTime,
collectionTime = testDetails.testTime,
expiryTime = testDetails.testTime,
)
)
)
)
hemoCubeDao.insertAll(testDetails) hemoCubeDao.insertAll(testDetails)
} }
@@ -362,6 +252,30 @@ class HemoCubeViewModel @Inject constructor(
} }
} }
private fun addResultTestToDbforbuffercheck(bufferCheckData: BufferCheckData) {
viewModelScope.launch {
try {
when (val response = repository.addTestToDatabaseforBufferCheck(bufferCheckData)) {
is Response.Success -> {
Log.i("Testdb", "Data uploaded to Firestore successfully")
fireBaseUpload.postValue("Success")
}
is Response.Error -> {
Log.e("Testdb", "Error uploading data to Firestore: $response")
fireBaseUpload.postValue("Error")
}
else -> {}
}
} catch (e: Exception) {
Log.e("Testdb", "Exception during data upload: ${e.message}")
fireBaseUpload.postValue("Error")
}
}
}
fun bulkAddResultTestToDb(userData: HemoCubeTestData) { fun bulkAddResultTestToDb(userData: HemoCubeTestData) {
viewModelScope.launch { viewModelScope.launch {
userData.reportUploadTime = SimpleDateFormat( userData.reportUploadTime = SimpleDateFormat(
@@ -385,7 +299,7 @@ class HemoCubeViewModel @Inject constructor(
} }
fun updateMolbioFlag(userId: String) = viewModelScope.launch { fun updateMolbioFlag(userId: String) = viewModelScope.launch {
hemoCubeDao.updateMolbioFlag(id = userId, true) hemoCubeDao.updateFieldById(id = userId, true)
} }
fun addUser(userData: HemoCubeTestData) = viewModelScope.launch { fun addUser(userData: HemoCubeTestData) = viewModelScope.launch {
@@ -396,80 +310,10 @@ class HemoCubeViewModel @Inject constructor(
hemoCubeDao.deleteById(id = userId) hemoCubeDao.deleteById(id = userId)
} }
private fun addResultTestToDbforbuffercheck(bufferCheckData: BufferCheckData) {
viewModelScope.launch {
try {
when (val response =
repository.addTestToDatabaseforBufferCheck(bufferCheckData)) {
is Response.Success -> {
Log.i("Testdb", "Data uploaded to Firestore successfully")
fireBaseUpload.postValue("Success")
}
is Response.Error -> {
Log.e("Testdb", "Error uploading data to Firestore: $response")
fireBaseUpload.postValue("Error")
}
}
} catch (e: Exception) {
Log.e("Testdb", "Exception during data upload: ${e.message}")
fireBaseUpload.postValue("Error")
}
}
}
private fun updateBufferLocalFlag(bufferId: String) =
viewModelScope.launch {
hemoCubeBufferDao.updateFieldById(id = bufferId, true)
}
fun getLocalUserDataForCsv(context: Context): Boolean {
val localUserDataLiveData: LiveData<List<HemoCubeTestData>> = hemoCubeDao.getAll()
// Observe the LiveData to get the actual data when available
localUserDataLiveData.observeForever { localUserData ->
localUserData?.let {
val csvData = mutableListOf<Array<String>>()
it.forEach { userData ->
csvData.add(
arrayOf(
userData._id,
userData.name,
userData.bloodGroup,
userData.birthYear,
userData.classificationResult,
userData.testTime.toString(),
userData.userImageURL
)
)
}
val csvWriter = CsvWriter(context)
csvWriter.writeCsv("userData.csv", csvData)
// Remove the observer to avoid leaks
localUserDataLiveData.removeObserver {}
}
}
return true // Assuming success, you might want to modify this based on your actual logic
}
fun getBatteryLevel(): Float? { fun getBatteryLevel(): Float? {
val batteryPct: Float? = batteryStatus?.let { intent -> val batteryPct: Float? = batteryStatus?.let { intent ->
val level: Int = val level: Int = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
intent.getIntExtra( val scale: Int = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
BatteryManager.EXTRA_LEVEL,
-1
)
val scale: Int =
intent.getIntExtra(
BatteryManager.EXTRA_SCALE,
-1
)
level * 100 / scale.toFloat() level * 100 / scale.toFloat()
} }
@@ -478,10 +322,7 @@ class HemoCubeViewModel @Inject constructor(
fun getBatteryTemperature(): Float? { fun getBatteryTemperature(): Float? {
val batteryTemp: Float? = batteryStatus?.let { intent -> val batteryTemp: Float? = batteryStatus?.let { intent ->
val temperature = intent.getIntExtra( val temperature = intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0)
BatteryManager.EXTRA_TEMPERATURE,
0
)
temperature.toFloat() / 10 temperature.toFloat() / 10
} }
@@ -490,59 +331,27 @@ class HemoCubeViewModel @Inject constructor(
fun getBatteryVoltage(context: Context): Float { fun getBatteryVoltage(context: Context): Float {
val batteryIntent = val batteryIntent =
context.registerReceiver( context.registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
null, val voltage = batteryIntent?.getIntExtra(BatteryManager.EXTRA_VOLTAGE, 0) ?: 0
IntentFilter(Intent.ACTION_BATTERY_CHANGED)
)
val voltage = batteryIntent?.getIntExtra(
BatteryManager.EXTRA_VOLTAGE,
0
) ?: 0
// milli-volts to volts // milli-volts to volts
return voltage.toFloat() / 1000 return voltage.toFloat() / 1000
} }
fun getBatteryCapacity(context: Context): Int { fun getBatteryCapacity(context: Context): Int {
val batteryManager = val batteryManager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
val currentCapacity =
batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER)
return currentCapacity return batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER)
} }
fun getBatteryMaxCapacity(context: Context): Float { fun getBatteryMaxCapacity(context: Context): Float {
val batteryManager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager val batteryManager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
val designCapacity = val designCapacity = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
val currentCapacity = val currentCapacity =
batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER) batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER)
// Calculate the estimated maximum battery capacity in mAh // Calculate the estimated maximum battery capacity in mAh
val maxCapacity = currentCapacity.toFloat() / designCapacity.toFloat() * 100
return maxCapacity return currentCapacity.toFloat() / designCapacity.toFloat() * 100
}
fun createCSV(hemoCubeTestData: List<HemoCubeTestData>, appContext: Context) =
viewModelScope.launch {
val fileName = "HPOS${getCurrentDate()}.csv"
if (localFileDataSource.exportDataToCSV(fileName, hemoCubeTestData)) {
hemoCubeTestData.forEach { data ->
data.localFlag = true
hemoCubeDao.updateCSVFieldById(
data._id,
true
)
}
}
}
fun getCurrentDate(): String {
return SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
} }
} }

View File

@@ -1,6 +1,5 @@
package com.example.hpostesting.presentation.hemocube package com.example.hpostesting.presentation.hemocube
import android.annotation.SuppressLint
import android.app.PendingIntent import android.app.PendingIntent
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.ComponentName import android.content.ComponentName
@@ -125,23 +124,22 @@ open class HemocubeActivity : AppCompatActivity() {
} }
@SuppressLint("MutableImplicitPendingIntent")
private fun requestUserPermission(manager: UsbManager, device: UsbDevice) { private fun requestUserPermission(manager: UsbManager, device: UsbDevice) {
val mPendingIntent: PendingIntent val mPendingIntent: PendingIntent
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
mPendingIntent = PendingIntent.getBroadcast( mPendingIntent = PendingIntent.getBroadcast(
this, 0, Intent(Constants.HEMOCUBE_USB_PERMISSION), PendingIntent.FLAG_MUTABLE this, 0, Intent(Constants.HOMOCUBE_USB_PERMISSION), PendingIntent.FLAG_MUTABLE
) )
} else { } else {
mPendingIntent = PendingIntent.getBroadcast( mPendingIntent = PendingIntent.getBroadcast(
this, this,
0, 0,
Intent(Constants.HEMOCUBE_USB_PERMISSION), Intent(Constants.HOMOCUBE_USB_PERMISSION),
PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
) )
} }
val filter = IntentFilter(Constants.HEMOCUBE_USB_PERMISSION) val filter = IntentFilter(Constants.HOMOCUBE_USB_PERMISSION)
registerReceiver(broadcastReceiver, filter) registerReceiver(broadcastReceiver, filter)
manager.requestPermission(device, mPendingIntent) manager.requestPermission(device, mPendingIntent)
} }

View File

@@ -40,7 +40,7 @@ class TestRightResults : Fragment() {
): View { ): View {
binding = FragmentTestRightResultsBinding.inflate(inflater, container, false) binding = FragmentTestRightResultsBinding.inflate(inflater, container, false)
sharedPreference = sharedPreference =
requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE) requireContext().getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE)
return binding.root return binding.root
} }
@@ -135,7 +135,7 @@ class TestRightResults : Fragment() {
} }
} }
} }
viewModel.networkStatusLiveData?.observe(viewLifecycleOwner) { isNetworkAvailable -> viewModel.networkStatusLiveData.observe(viewLifecycleOwner) { isNetworkAvailable ->
val deviceStaticId = sharedPreference.getString(Constants.USER_ID, "") val deviceStaticId = sharedPreference.getString(Constants.USER_ID, "")
if (isNetworkAvailable) { if (isNetworkAvailable) {
viewModel.uploadResultToDatabase(requireContext(), true, deviceStaticId!!) viewModel.uploadResultToDatabase(requireContext(), true, deviceStaticId!!)

View File

@@ -2,6 +2,7 @@ package com.example.hpostesting.presentation.testRight
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
@@ -42,10 +43,9 @@ class TestRightViewModel @Inject constructor(
private val saveRawDataTest: SaveRawDataTest, private val saveRawDataTest: SaveRawDataTest,
private val repository: DatabaseRepository, private val repository: DatabaseRepository,
private val userDao: UserDao, private val userDao: UserDao,
context: Context? context: Context
) : ViewModel() { ) : ViewModel() {
var isServiceConnected = false var isServiceConnected = false
val progressBar = MutableLiveData(false) val progressBar = MutableLiveData(false)
@@ -54,10 +54,10 @@ class TestRightViewModel @Inject constructor(
val fireBaseUpload = MutableLiveData<String>() val fireBaseUpload = MutableLiveData<String>()
var testDetails = DataHolder.selectedTest val testDetails = DataHolder.selectedTest
private val _networkStatusLiveData = context?.let { NetworkStatusLiveData(it) } private val _networkStatusLiveData = NetworkStatusLiveData(context)
val networkStatusLiveData: NetworkStatusLiveData? val networkStatusLiveData: LiveData<Boolean>
get() = _networkStatusLiveData get() = _networkStatusLiveData
val allUserData = userDao.getAll() val allUserData = userDao.getAll()
@@ -439,7 +439,7 @@ class TestRightViewModel @Inject constructor(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault() "yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time) ).format(Calendar.getInstance().time)
when (repository.addTestToDatabase(testDetails)) { when (repository.addTestToDatabase(testDetails)) {
is Response.Success<*> -> { is Response.Success -> {
fireBaseUpload.postValue("Success") fireBaseUpload.postValue("Success")
} }
@@ -448,45 +448,43 @@ class TestRightViewModel @Inject constructor(
} }
} }
fun uploadResultToDatabase(context: Context, isOnline: Boolean, deviceSerialNumber: String) = fun uploadResultToDatabase(context: Context, isOnline: Boolean,deviceSerialNumber: String) = viewModelScope.launch {
viewModelScope.launch { val csvFilePath = MyUtils.getAppFolderPath(context) + getCSVFileName()
val csvFilePath = MyUtils.getAppFolderPath(context) + getCSVFileName() val logTxtFilePath = MyUtils.getAppFolderPath(context) + getLogFileName()
val logTxtFilePath = MyUtils.getAppFolderPath(context) + getLogFileName() testDetails?.csvPath = csvFilePath
testDetails?.csvPath = csvFilePath testDetails?.reportPath = logTxtFilePath
testDetails?.reportPath = logTxtFilePath testDetails?.deviceSerialNumber = deviceSerialNumber
testDetails?.deviceSerialNumber = deviceSerialNumber if (isOnline) {
if (isOnline) { val storageRef = FirebaseStorage.getInstance().reference
val storageRef = FirebaseStorage.getInstance().reference val storageTestDetailsRef = storageRef.child("${testDetails?._id}/")
val storageTestDetailsRef = storageRef.child("${testDetails?._id}/")
try { try {
val csvFileUri = Uri.fromFile(File(csvFilePath)) val csvFileUri = Uri.fromFile(File(csvFilePath))
val logTxtFileUri = Uri.fromFile(File(logTxtFilePath)) val logTxtFileUri = Uri.fromFile(File(logTxtFilePath))
val csvUploadTask = val csvUploadTask =
storageTestDetailsRef.child(csvFileUri.lastPathSegment!!) storageTestDetailsRef.child(csvFileUri.lastPathSegment!!).putFile(csvFileUri)
.putFile(csvFileUri) .await()
.await() val logUploadTask = storageTestDetailsRef.child(logTxtFileUri.lastPathSegment!!)
val logUploadTask = storageTestDetailsRef.child(logTxtFileUri.lastPathSegment!!) .putFile(logTxtFileUri).await()
.putFile(logTxtFileUri).await()
val csvUri = csvUploadTask.storage.downloadUrl.await().toString() val csvUri = csvUploadTask.storage.downloadUrl.await().toString()
val logUri = logUploadTask.storage.downloadUrl.await().toString() val logUri = logUploadTask.storage.downloadUrl.await().toString()
val serialNumber = Constants.STATICID.firstOrNull { it == deviceSerialNumber } val serialNumber = Constants.STATICID.firstOrNull { it == deviceSerialNumber }
testDetails?.csvPath = csvUri testDetails?.csvPath = csvUri
testDetails?.reportPath = logUri testDetails?.reportPath = logUri
addResultTestToDb() addResultTestToDb()
} catch (exception: Exception) { } catch (exception: Exception) {
// Handle the exception appropriately (e.g., log the error, display an error message) // Handle the exception appropriately (e.g., log the error, display an error message)
}
} else {
testDetails?.testTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
userDao.insertAll(testDetails!!)
} }
} else {
testDetails?.testTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
userDao.insertAll(testDetails!!)
} }
}
fun bulkUploadResultToDatabase(userData: UserData) = viewModelScope.launch { fun bulkUploadResultToDatabase(userData: UserData) = viewModelScope.launch {
val storageRef = FirebaseStorage.getInstance().reference val storageRef = FirebaseStorage.getInstance().reference
@@ -521,7 +519,7 @@ class TestRightViewModel @Inject constructor(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault() "yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time) ).format(Calendar.getInstance().time)
when (repository.addTestToDatabase(userData)) { when (repository.addTestToDatabase(userData)) {
is Response.Success<*> -> { is Response.Success -> {
fireBaseUpload.postValue("Success") fireBaseUpload.postValue("Success")
} }

View File

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

View File

@@ -1,533 +0,0 @@
package com.example.hpostesting.presentation.trueheme
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.BatteryManager
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import com.example.hpostesting.data.CsvWriter
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.NetworkStatusLiveData
import com.example.hpostesting.data.Result
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.dao.HemoCubeBufferDao
import com.example.hpostesting.data.dao.HemoCubeDao
import com.example.hpostesting.data.datasource.LocalFileDataSource
import com.example.hpostesting.data.model.Response
import com.example.hpostesting.data.model.log.UploadLogsResponse
import com.example.hpostesting.data.model.login.LoginRequest
import com.example.hpostesting.data.model.login.LoginResponse
import com.example.hpostesting.data.model.molbioresult.MolbioV2Result
import com.example.hpostesting.data.model.molbioresult.MolbioV2ResultRequest
import com.example.hpostesting.data.model.molbioresult.MolbioV2ResultResponse
import com.example.hpostesting.data.model.patient.BufferCheckData
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.toHemoCubeTestData
import com.example.hpostesting.data.model.updates.CheckUpdateRequest
import com.example.hpostesting.data.model.updates.CheckUpdateResponse
import com.example.hpostesting.data.model.updates.DeviceUpdateRequest
import com.example.hpostesting.data.repository.Repository
import com.example.hpostesting.domain.CheckUpdateWorker
import com.example.hpostesting.domain.LogFileManager
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.RequestBody.Companion.asRequestBody
import okhttp3.ResponseBody
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import java.util.concurrent.TimeUnit
import javax.inject.Inject
@Suppress("MemberVisibilityCanBePrivate")
@HiltViewModel
class TrueHemeViewModel @Inject constructor(
private val hemoCubeDao: HemoCubeDao,
private val hemoCubeBufferDao: HemoCubeBufferDao,
private val repository: Repository,
private val logFileManager: LogFileManager,
private val localFileDataSource: LocalFileDataSource,
context: Context,
) : ViewModel() {
var isServiceConnected = false
val progressBar = MutableLiveData(false)
private val testDetails = DataHolder.selectedTest?.toHemoCubeTestData()
val messages = MutableLiveData<String>()
private val sharedPreference =
context.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
private val workManager = WorkManager.getInstance(context)
// init {
// startPeriodicCheckUpdate()
// }
val loginResponse = MutableLiveData<Result<LoginResponse>>()
val resultUpload = MutableLiveData<Result<MolbioV2ResultResponse>>()
val checkUpdate = MutableLiveData<Result<CheckUpdateResponse>>()
val deviceUpdate = MutableLiveData<Result<ResponseBody>>()
val uploadLogs = MutableLiveData<Result<UploadLogsResponse>?>()
// Get the device ID of the device you want to retrieve data for (e.g., the first device in the list)
private val _networkStatusLiveData = NetworkStatusLiveData(context)
val allUserData = hemoCubeDao.getAll()
val allKitTestData = hemoCubeBufferDao.getAll()
val deviceData = MutableLiveData<DeviceData?>()
val networkStatusLiveData: LiveData<Boolean>
get() = _networkStatusLiveData
val deviceMessages = MutableLiveData<String?>()
val fireBaseUpload = MutableLiveData<String>()
val fireBaseBulkUpload = MutableLiveData<String>()
private val batteryStatus: Intent? =
IntentFilter(Intent.ACTION_BATTERY_CHANGED).let { ifilter ->
context.registerReceiver(null, ifilter)
}
fun uploadHemoCubeResultToDatabase(
isOnline: Boolean, testStatus: Boolean, kitSerial: String?,
) = viewModelScope.launch {
if (kitSerial != null) {
testDetails?.kitSerial = kitSerial
}
testDetails?.testStatus = testStatus
try {
if (isOnline) {
parseData()
addResultTestToDb()
} else {
parseData()
testDetails?.testTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
hemoCubeDao.insertAll(testDetails!!)
fireBaseUpload.postValue("Local")
}
} catch (e: Exception) {
Log.e("Testdb", "Upload failed: ${e.message}")
}
}
fun login(loginRequest: LoginRequest) = viewModelScope.launch {
loginResponse.postValue(Result.Loading())
repository.login(loginRequest).let {
loginResponse.postValue(it)
}
}
fun uploadResult(molbioV2ResultRequest: MolbioV2ResultRequest) = viewModelScope.launch {
resultUpload.postValue(Result.Loading())
repository.uploadResults(molbioV2ResultRequest).let {
resultUpload.postValue(it)
}
}
fun checkUpdate(checkUpdateRequest: CheckUpdateRequest) = viewModelScope.launch {
checkUpdate.postValue(Result.Loading())
repository.checkUpdate(checkUpdateRequest).let {
checkUpdate.postValue(it)
}
}
fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest) = viewModelScope.launch {
deviceUpdate.postValue(Result.Loading())
repository.deviceUpdate(deviceUpdateRequest).let {
deviceUpdate.postValue(it)
}
}
fun startPeriodicCheckUpdate() {
val periodicRequest = PeriodicWorkRequestBuilder<CheckUpdateWorker>(
repeatInterval = 1, repeatIntervalTimeUnit = TimeUnit.MINUTES
).build()
workManager.enqueueUniquePeriodicWork(
"checkUpdateWorker", ExistingPeriodicWorkPolicy.KEEP, periodicRequest
)
}
fun uploadLogs() = viewModelScope.launch {
uploadLogs.postValue(Result.Loading())
val logFile = logFileManager.createLogFile().let { file ->
val requestBody = file?.asRequestBody("multipart/form-data".toMediaTypeOrNull())
val multipartFile =
requestBody?.let { MultipartBody.Part.createFormData("logFile", file?.name, it) }
multipartFile?.let { partFile ->
repository.uploadLogs(partFile).let { result ->
uploadLogs.postValue(result)
}
}
}
}
fun uploadHemoCubeResultToDatabaseForBufferCheck(
isOnline: Boolean,
bufferCheckData: BufferCheckData,
) =
viewModelScope.launch {
if (isOnline) {
try {
when (val response =
repository.addTestToDatabaseforBufferCheck(bufferCheckData)) {
is Response.Success -> {
Log.i("Testdb", "Data uploaded to Firestore successfully")
fireBaseUpload.postValue("Success")
bufferCheckData.localFlag = true
hemoCubeBufferDao.insertAll(bufferCheckData)
}
is Response.Error -> {
Log.e("Testdb", "Error uploading data to Firestore: $response")
fireBaseUpload.postValue("Error")
bufferCheckData.localFlag = true
hemoCubeBufferDao.insertAll(bufferCheckData)
}
else -> {}
}
} catch (e: Exception) {
Log.e("Testdb", "Exception during data upload: ${e.message}")
fireBaseUpload.postValue("Error")
}
} else {
hemoCubeBufferDao.insertAll(bufferCheckData)
fireBaseUpload.postValue("Local")
}
}
fun bulkAddResultKitTestToDb(bufferCheckData: BufferCheckData) {
viewModelScope.launch {
bufferCheckData.reportUploadTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
when (repository.addTestToDatabaseforBufferCheck(bufferCheckData)) {
is Response.Success -> {
fireBaseBulkUpload.postValue("Success")
updateBufferLocalFlag(bufferCheckData._id)
}
else -> {
fireBaseBulkUpload.postValue("Error")
}
}
}
}
fun uploadHemoCubeResultToDatabaseforbuffercheckN(bufferCheckData: BufferCheckData) =
viewModelScope.launch {
addResultTestToDbforbuffercheck(bufferCheckData)
}
fun getDeviceData(deviceId: String?) = viewModelScope.launch {
deviceData.postValue(deviceId?.let { repository.getDeviceDataById(it) })
}
fun parseData() {
testDetails?.deviceRatio = DataHolder.hemocubeResult
testDetails?.resultData = DataHolder.hemoCubeTestData?.resultData.toString()
testDetails?.location = DataHolder.location
testDetails?.testTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
testDetails?.appVersion = DataHolder.hemoCubeTestData?.appVersion
testDetails?.deviceId = DataHolder.hemoCubeTestData?.deviceId
testDetails?.deviceSerialNumber =
sharedPreference.getString(Constants.USER_ID, "").toString()
testDetails?.kitSerial = sharedPreference.getString(Constants.KIT_NUMBER, "").toString()
testDetails?.led1Buffer = DataHolder.hemoCubeTestData?.led1Buffer
testDetails?.led2Buffer = DataHolder.hemoCubeTestData?.led2Buffer
testDetails?.led3Buffer = DataHolder.hemoCubeTestData?.led3Buffer
testDetails?.led4Buffer = DataHolder.hemoCubeTestData?.led4Buffer
testDetails?.led1Sample = DataHolder.hemoCubeTestData?.led1Sample
testDetails?.led2Sample = DataHolder.hemoCubeTestData?.led2Sample
testDetails?.led3Sample = DataHolder.hemoCubeTestData?.led3Sample
testDetails?.led4Sample = DataHolder.hemoCubeTestData?.led4Sample
testDetails?.led1Average = DataHolder.hemoCubeTestData?.led1Average
testDetails?.led2Average = DataHolder.hemoCubeTestData?.led2Average
testDetails?.led3Average = DataHolder.hemoCubeTestData?.led3Average
testDetails?.led4Average = DataHolder.hemoCubeTestData?.led4Average
testDetails?.abs1 = DataHolder.hemoCubeTestData?.abs1
testDetails?.abs2 = DataHolder.hemoCubeTestData?.abs2
testDetails?.abs3 = DataHolder.hemoCubeTestData?.abs3
testDetails?.abs4 = DataHolder.hemoCubeTestData?.abs4
testDetails?.deviceRatio = DataHolder.hemoCubeTestData?.deviceRatio
testDetails?.slopeRatio = DataHolder.hemoCubeTestData?.slopeRatio
testDetails?.predictedDenovixRatio = DataHolder.hemoCubeTestData?.predictedDenovixRatio
testDetails?.calculatedRatio = DataHolder.hemoCubeTestData?.calculatedRatio
testDetails?.coefficients = DataHolder.hemoCubeTestData?.coefficients
testDetails?.incubationTime = DataHolder.hemoCubeTestData?.incubationTime.toString()
testDetails?.name = DataHolder.hemoCubeTestData?.name.toString()
testDetails?.birthYear = DataHolder.hemoCubeTestData?.birthYear.toString()
testDetails?.userImageURL = DataHolder.hemoCubeTestData?.userImageURL.toString()
testDetails?.classificationResult = DataHolder.hemoCubeTestData?.classificationResult!!
testDetails?.prdClassification = DataHolder.hemoCubeTestData?.prdClassification.toString()
testDetails?.deviceRatioClass = DataHolder.hemoCubeTestData?.deviceRatioClass.toString()
testDetails?.slopeRatioClass = DataHolder.hemoCubeTestData?.slopeRatioClass.toString()
testDetails?.errorMessages = DataHolder.hemoCubeTestData?.errorMessages.toString()
testDetails?.batteryLevel = DataHolder.hemoCubeTestData?.batteryLevel.toString()
testDetails?.batteryCapacity = DataHolder.hemoCubeTestData?.batteryCapacity.toString()
testDetails?.batteryMaxCapacity = DataHolder.hemoCubeTestData?.batteryMaxCapacity.toString()
testDetails?.batteryTemperature = DataHolder.hemoCubeTestData?.batteryTemperature.toString()
testDetails?.batteryVoltage = DataHolder.hemoCubeTestData?.batteryVoltage.toString()
testDetails?.quickCapture = DataHolder.hemoCubeTestData?.quickCapture!!
testDetails?.solution = DataHolder.hemoCubeTestData?.solution
testDetails?.concentration = DataHolder.hemoCubeTestData?.concentration
testDetails?.volume = DataHolder.hemoCubeTestData?.volume
}
private fun addResultTestToDb() {
viewModelScope.launch {
try {
testDetails!!.reportUploadTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
when (val response = repository.addTestToDatabase(testDetails)) {
is Response.Success -> {
val kitCount = sharedPreference.getInt(Constants.KIT_COUNT, 0)
with(sharedPreference.edit()) {
putInt(Constants.KIT_COUNT, kitCount.plus(1))
apply()
}
Log.i("Testdb", "Data uploaded to Firestore successfully")
fireBaseUpload.postValue("Success")
testDetails.localFlag = true
uploadResult(
MolbioV2ResultRequest(
mutableListOf(
MolbioV2Result(
rawData = testDetails,
analysisId = testDetails._id,
analysisDate = testDetails.testTime,
analysisStatus = testDetails.classificationResult,
thresholds = Constants.BUFFER_INTENSITY_THRESHOLDS[testDetails.deviceId].toString(),
interpretation = testDetails.classificationResult,
testId = testDetails._id,
testTime = testDetails.testTime,
collectionTime = testDetails.testTime,
expiryTime = testDetails.testTime,
)
)
)
)
hemoCubeDao.insertAll(testDetails)
}
is Response.Error -> {
Log.e("Testdb", "Error uploading data to Firestore: $response")
fireBaseUpload.postValue("Error")
hemoCubeDao.insertAll(testDetails)
}
else -> {}
}
} catch (e: Exception) {
Log.e("Testdb", "Exception during data upload: ${e.message}")
fireBaseUpload.postValue("Error")
}
}
}
fun bulkAddResultTestToDb(userData: HemoCubeTestData) {
viewModelScope.launch {
userData.reportUploadTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
when (repository.addTestToDatabase(userData)) {
is Response.Success -> {
fireBaseBulkUpload.postValue("Success")
updateLocalFlag(userData._id)
}
else -> {
fireBaseBulkUpload.postValue("Error")
}
}
}
}
private fun updateLocalFlag(userId: String) = viewModelScope.launch {
hemoCubeDao.updateFieldById(id = userId, true)
}
fun updateMolbioFlag(userId: String) = viewModelScope.launch {
hemoCubeDao.updateMolbioFlag(id = userId, true)
}
fun addUser(userData: HemoCubeTestData) = viewModelScope.launch {
hemoCubeDao.insertAll(userData)
}
fun deleteById(userId: String) = viewModelScope.launch {
hemoCubeDao.deleteById(id = userId)
}
private fun addResultTestToDbforbuffercheck(bufferCheckData: BufferCheckData) {
viewModelScope.launch {
try {
when (val response =
repository.addTestToDatabaseforBufferCheck(bufferCheckData)) {
is Response.Success -> {
Log.i("Testdb", "Data uploaded to Firestore successfully")
fireBaseUpload.postValue("Success")
}
is Response.Error -> {
Log.e("Testdb", "Error uploading data to Firestore: $response")
fireBaseUpload.postValue("Error")
}
}
} catch (e: Exception) {
Log.e("Testdb", "Exception during data upload: ${e.message}")
fireBaseUpload.postValue("Error")
}
}
}
private fun updateBufferLocalFlag(bufferId: String) =
viewModelScope.launch {
hemoCubeBufferDao.updateFieldById(id = bufferId, true)
}
fun getLocalUserDataForCsv(context: Context): Boolean {
val localUserDataLiveData: LiveData<List<HemoCubeTestData>> = hemoCubeDao.getAll()
// Observe the LiveData to get the actual data when available
localUserDataLiveData.observeForever { localUserData ->
localUserData?.let {
val csvData = mutableListOf<Array<String>>()
it.forEach { userData ->
csvData.add(
arrayOf(
userData._id,
userData.name,
userData.bloodGroup,
userData.birthYear,
userData.classificationResult,
userData.testTime.toString(),
userData.userImageURL
)
)
}
val csvWriter = CsvWriter(context)
csvWriter.writeCsv("userData.csv", csvData)
// Remove the observer to avoid leaks
localUserDataLiveData.removeObserver {}
}
}
return true // Assuming success, you might want to modify this based on your actual logic
}
fun getBatteryLevel(): Float? {
val batteryPct: Float? = batteryStatus?.let { intent ->
val level: Int =
intent.getIntExtra(
BatteryManager.EXTRA_LEVEL,
-1
)
val scale: Int =
intent.getIntExtra(
BatteryManager.EXTRA_SCALE,
-1
)
level * 100 / scale.toFloat()
}
return batteryPct
}
fun getBatteryTemperature(): Float? {
val batteryTemp: Float? = batteryStatus?.let { intent ->
val temperature = intent.getIntExtra(
BatteryManager.EXTRA_TEMPERATURE,
0
)
temperature.toFloat() / 10
}
return batteryTemp
}
fun getBatteryVoltage(context: Context): Float {
val batteryIntent =
context.registerReceiver(
null,
IntentFilter(Intent.ACTION_BATTERY_CHANGED)
)
val voltage = batteryIntent?.getIntExtra(
BatteryManager.EXTRA_VOLTAGE,
0
) ?: 0
// milli-volts to volts
return voltage.toFloat() / 1000
}
fun getBatteryCapacity(context: Context): Int {
val batteryManager =
context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
val currentCapacity =
batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER)
return currentCapacity
}
fun getBatteryMaxCapacity(context: Context): Float {
val batteryManager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
val designCapacity =
batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
val currentCapacity =
batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER)
// Calculate the estimated maximum battery capacity in mAh
val maxCapacity = currentCapacity.toFloat() / designCapacity.toFloat() * 100
return maxCapacity
}
fun createCSV(hemoCubeTestData: List<HemoCubeTestData>, appContext: Context) =
viewModelScope.launch {
val fileName = "HPOS${getCurrentDate()}.csv"
if (localFileDataSource.exportDataToCSV(fileName, hemoCubeTestData)) {
hemoCubeTestData.forEach { data ->
data.localFlag = true
hemoCubeDao.updateCSVFieldById(
data._id,
true
)
}
}
}
fun getCurrentDate(): String {
return SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
}
}

View File

@@ -1,9 +0,0 @@
<!-- res/drawable/border.xml -->
<shape xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
tools:ignore="ExtraText">
<solid android:color="@android:color/transparent" />
<stroke
android:color="#000000"
android:width="2dp" />
</shape>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -1,5 +0,0 @@
<vector android:height="24dp" android:tint="@color/primary"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@color/primary" android:pathData="M19,9h-4V3H9v6H5l7,7 7,-7zM5,18v2h14v-2H5z"/>
</vector>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="@android:color/white" />
<corners android:radius="4dp" />
</shape>
</item>
<item android:drawable="@android:drawable/btn_dropdown" />
</layer-list>

View File

@@ -1,27 +0,0 @@
<?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">
<FrameLayout
android:id="@+id/fg_assurance_controls"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
tools:context=".presentation.assurance.AssuranceControlsActivity">
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

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

View File

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

View File

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

View File

@@ -1,9 +0,0 @@
<?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.KitscanJava">
</androidx.constraintlayout.widget.ConstraintLayout>

View File

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

View File

@@ -1,116 +0,0 @@
<?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.assurance.AssuranceControlsFragment">
<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:textSize="22sp"
android:text="@string/assurance_controls"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/et_readings_per_sample"
android:visibility="gone"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:layout_weight="1"
android:hint="Readings per sample"
android:importantForAutofill="no"
android:inputType="number"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle2" />
<Spinner
android:id="@+id/spinner_solutions"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:background="@drawable/spinner_border"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/et_readings_per_sample" />
<Spinner
android:id="@+id/spinner_concentration"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="48dp"
android:background="@drawable/spinner_border"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/spinner_solutions" />
<Spinner
android:id="@+id/spinner_volume"
android:layout_width="0dp"
android:visibility="gone"
android:layout_height="wrap_content"
android:layout_marginTop="52dp"
android:background="@drawable/spinner_border"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/spinner_concentration" />
<Button
android:id="@+id/btn_submit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="352dp"
android:clickable="false"
android:gravity="center"
android:text="Continue"
android:textColor="@color/white"
app:cornerRadius="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/et_readings_per_sample" />
<ImageView
android:id="@+id/iv_check"
android:visibility="gone"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginTop="40dp"
android:importantForAccessibility="no"
android:src="@drawable/check"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_submit" />
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:elevation="12dp"
android:indeterminate="true"
android:indeterminateDrawable="@drawable/progressbar_drawable"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,114 +0,0 @@
<?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.autodac.AutoDacFragment">
<!-- <TextView-->
<!-- android:id="@+id/tv_title"-->
<!-- style="@style/title1"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_marginHorizontal="24dp"-->
<!-- android:text="@string/diagnostics"-->
<!-- android:layout_marginTop="16dp"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toTopOf="parent" />-->
<TextView
android:id="@+id/tv_subtitle2"
style="@style/title2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:text="@string/auto_dac"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_subtitle3"
style="@style/title2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle2" />
<TextView
android:id="@+id/tv_subtitle4"
style="@style/title1_1"
android:layout_width="0dp"
android:layout_height="380dp"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:gravity="center"
android:text="Start"
android:textColor="@color/black"
android:textSize="22sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle3" />
<Button
android:id="@+id/btn_submit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:gravity="center"
android:text="Start"
android:textColor="@color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle4" />
<!-- <Button-->
<!-- android:id="@+id/btn_read"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:text="@string/read"-->
<!-- android:layout_margin="16dp"-->
<!-- android:clickable="false"-->
<!-- app:layout_constraintTop_toBottomOf="@id/btn_set_reference"-->
<!-- app:layout_constraintStart_toStartOf="parent" />-->
<!-- </androidx.constraintlayout.widget.ConstraintLayout>-->
<ImageView
android:id="@+id/iv_check"
android:visibility="gone"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginTop="40dp"
android:importantForAccessibility="no"
android:src="@drawable/check"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_submit" />
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:elevation="12dp"
android:indeterminate="true"
android:indeterminateDrawable="@drawable/progressbar_drawable"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,251 +0,0 @@
<?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.calibration.CalibrationFragment">
<!-- <TextView-->
<!-- android:id="@+id/tv_title"-->
<!-- style="@style/title1"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_marginHorizontal="24dp"-->
<!-- android:text="@string/diagnostics"-->
<!-- android:layout_marginTop="16dp"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toTopOf="parent" />-->
<TextView
android:id="@+id/tv_subtitle2"
style="@style/title2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:text="@string/calibration"
android:textSize="22sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="@+id/llLed1Fields"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:orientation="horizontal"
android:background="@drawable/border"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle2">
<EditText
android:id="@+id/et_led1_slope"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginTop="8dp"
android:hint="Led 1 slope"
android:importantForAutofill="no"
android:inputType="numberDecimal" />
<EditText
android:id="@+id/et_led1_intercept"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginTop="8dp"
android:hint="Led 1 intercept"
android:importantForAutofill="no"
android:inputType="numberDecimal" />
</LinearLayout>
<LinearLayout
android:id="@+id/llLed2Fields"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:orientation="horizontal"
android:background="@drawable/border"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/llLed1Fields">
<EditText
android:id="@+id/et_led2_slope"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginTop="8dp"
android:hint="Led 2 slope"
android:importantForAutofill="no"
android:inputType="numberDecimal" />
<EditText
android:id="@+id/et_led2_intercept"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginTop="8dp"
android:hint="Led 2 intercept"
android:importantForAutofill="no"
android:inputType="numberDecimal" />
</LinearLayout>
<LinearLayout
android:id="@+id/llLed3Fields"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:orientation="horizontal"
android:background="@drawable/border"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/llLed2Fields">
<EditText
android:id="@+id/et_led3_slope"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginTop="8dp"
android:hint="Led 3 slope"
android:importantForAutofill="no"
android:inputType="numberDecimal" />
<EditText
android:id="@+id/et_led3_intercept"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginTop="8dp"
android:hint="Led 3 intercept"
android:importantForAutofill="no"
android:inputType="numberDecimal" />
</LinearLayout>
<LinearLayout
android:id="@+id/llLed4Fields"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:orientation="horizontal"
android:background="@drawable/border"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/llLed3Fields">
<EditText
android:id="@+id/et_led4_slope"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginTop="8dp"
android:hint="Led 4 slope"
android:importantForAutofill="no"
android:inputType="numberDecimal" />
<EditText
android:id="@+id/et_led4_intercept"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginTop="8dp"
android:hint="Led 4 intercept"
android:importantForAutofill="no"
android:inputType="numberDecimal" />
</LinearLayout>
<TextView
android:id="@+id/tv_subtitle3"
style="@style/title2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/llLed4Fields" />
<TextView
android:id="@+id/tv_subtitle4"
style="@style/title1_1"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="8dp"
android:gravity="center"
android:text="Start"
android:textColor="@color/black"
android:textSize="16sp"
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="10dp"
android:clickable="false"
android:gravity="center"
android:text="Save"
app:cornerRadius="100dp"
android:textColor="@color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle4" />
<!-- <Button-->
<!-- android:id="@+id/btn_read"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:text="@string/read"-->
<!-- android:layout_margin="16dp"-->
<!-- android:clickable="false"-->
<!-- app:layout_constraintTop_toBottomOf="@id/btn_set_reference"-->
<!-- app:layout_constraintStart_toStartOf="parent" />-->
<!-- </androidx.constraintlayout.widget.ConstraintLayout>-->
<ImageView
android:id="@+id/iv_check"
android:visibility="gone"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginTop="40dp"
android:importantForAccessibility="no"
android:src="@drawable/check"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_submit" />
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:elevation="12dp"
android:indeterminate="true"
android:indeterminateDrawable="@drawable/progressbar_drawable"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,23 +0,0 @@
<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.deviceinfo.DeviceFragment">
<TextView
android:id="@+id/tv_subtitle4"
style="@style/title1_1"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="50dp"
android:gravity="center"
android:text="Start"
android:textColor="@color/black"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,23 +0,0 @@
<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.deviceprovision.DeviceProvisionFragment">
<Button
android:id="@+id/btn_submit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:clickable="false"
android:gravity="center"
android:visibility="gone"
android:text="Register your device"
android:textColor="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -6,106 +6,31 @@
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context="com.example.hpostesting.presentation.dashboard.GalleryFragment"> tools:context="com.example.hpostesting.presentation.dashboard.GalleryFragment">
<TextView
android:id="@+id/tv_subtitle4"
style="@style/title1_1"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="50dp"
android:gravity="center"
android:text="Login ID"
android:textColor="@color/black"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button <Button
android:id="@+id/btn_submit" android:id="@+id/btn_submit"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp" android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp" android:layout_marginTop="24dp"
android:clickable="false" android:clickable="false"
android:text="@string/check_buffer" android:text="@string/check_buffer"
android:textColor="@color/white" android:textColor="@color/white"
app:cornerRadius="16dp" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle4" /> app:layout_constraintTop_toTopOf="parent" />
<Button <Button
android:id="@+id/btn_diagnostics" android:id="@+id/btn_diagnostics"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp" android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp" android:layout_marginTop="24dp"
android:clickable="false" android:clickable="false"
android:text="@string/diagnostics" android:text="@string/diagnostics"
android:textColor="@color/white" android:textColor="@color/white"
app:cornerRadius="16dp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_submit" /> app:layout_constraintTop_toBottomOf="@id/btn_submit" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_auto_dac"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:text="@string/auto_dac"
android:textColor="@color/white"
app:cornerRadius="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_diagnostics" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_calibration"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:text="@string/calibration"
android:textColor="@color/white"
app:cornerRadius="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_auto_dac" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_deviceProvision"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:text="@string/deviceProvision"
android:textColor="@color/white"
app:cornerRadius="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_deviceInfo" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_deviceInfo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:text="@string/deviceinfo"
android:textColor="@color/white"
app:cornerRadius="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_calibration" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -31,17 +31,17 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_title" /> app:layout_constraintTop_toBottomOf="@id/tv_title" />
<!-- <TextView--> <!-- <TextView-->
<!-- android:id="@+id/tv_subtitle3"--> <!-- android:id="@+id/tv_subtitle3"-->
<!-- style="@style/title2"--> <!-- style="@style/title2"-->
<!-- android:layout_width="0dp"--> <!-- android:layout_width="0dp"-->
<!-- android:layout_height="wrap_content"--> <!-- android:layout_height="wrap_content"-->
<!-- android:layout_marginHorizontal="24dp"--> <!-- android:layout_marginHorizontal="24dp"-->
<!-- android:layout_marginTop="16dp"--> <!-- android:layout_marginTop="16dp"-->
<!-- android:text="@string/step5"--> <!-- android:text="@string/step5"-->
<!-- app:layout_constraintEnd_toEndOf="parent"--> <!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintStart_toStartOf="parent"--> <!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toBottomOf="@id/tv_subtitle2" />--> <!-- app:layout_constraintTop_toBottomOf="@id/tv_subtitle2" />-->
<TextView <TextView
android:id="@+id/tv_name" android:id="@+id/tv_name"
@@ -62,7 +62,7 @@
android:id="@+id/tv_subtitle4" android:id="@+id/tv_subtitle4"
style="@style/title1_1" style="@style/title1_1"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="80dp"
android:layout_marginHorizontal="24dp" android:layout_marginHorizontal="24dp"
android:layout_marginTop="72dp" android:layout_marginTop="72dp"
android:gravity="center" android:gravity="center"
@@ -157,7 +157,6 @@
android:clickable="false" android:clickable="false"
android:text="@string/Start_Sample" android:text="@string/Start_Sample"
android:textColor="@color/white" android:textColor="@color/white"
app:cornerRadius="16dp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_placebuffer" /> app:layout_constraintTop_toBottomOf="@id/btn_placebuffer" />
@@ -173,22 +172,20 @@
android:clickable="false" android:clickable="false"
android:text="@string/place_buffer" android:text="@string/place_buffer"
android:textColor="@color/white" android:textColor="@color/white"
app:cornerRadius="16dp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_submit" /> app:layout_constraintTop_toBottomOf="@id/btn_submit" />
<Button <Button
android:id="@+id/btn_submit"
android:visibility="gone" android:visibility="gone"
android:layout_width="match_parent" android:id="@+id/btn_submit"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp" android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp" android:layout_marginTop="24dp"
android:clickable="false" android:clickable="false"
android:text="@string/submit" android:text="@string/submit"
android:textColor="@color/white" android:textColor="@color/white"
app:cornerRadius="16dp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle4" /> app:layout_constraintTop_toBottomOf="@id/tv_subtitle4" />
@@ -211,13 +208,16 @@
<TextView <TextView
android:id="@+id/tv_device_messages" android:id="@+id/tv_device_messages"
style="@style/title1_1" style="@style/title1_1"
android:layout_width="414dp" android:visibility="gone"
android:layout_height="201dp" android:layout_width="0dp"
android:layout_height="180dp"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="72dp"
android:gravity="center" android:gravity="center"
android:text="no device message"
android:textColor="@color/black" android:textColor="@color/black"
android:textSize="11sp" android:textSize="11sp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/error_message" /> app:layout_constraintTop_toBottomOf="@id/error_message" />
<Button <Button
@@ -233,19 +233,6 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/error_message" /> app:layout_constraintTop_toBottomOf="@id/error_message" />
<ImageView
android:id="@+id/iv_check"
android:visibility="gone"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginTop="40dp"
android:importantForAccessibility="no"
android:src="@drawable/check"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_device_messages" />
<ProgressBar <ProgressBar
android:id="@+id/progressBar" android:id="@+id/progressBar"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@@ -261,5 +248,5 @@
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</layout> </layout>

View File

@@ -18,24 +18,11 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/downloadCSV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="32dp"
android:visibility="gone"
android:backgroundTint="@color/primary"
android:contentDescription="@string/downloadcsv"
android:src="@drawable/download_csv"
app:elevation="1dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/internetNotAvailableCL" android:id="@+id/internetNotAvailableCL"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:visibility="gone" android:visibility="visible"
android:padding="24dp"> android:padding="24dp">
<TextView <TextView
@@ -44,7 +31,6 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center" android:gravity="center"
android:layout_marginTop="24dp"
android:text="@string/internet_not_available_please_enter_the_user_id_manually" android:text="@string/internet_not_available_please_enter_the_user_id_manually"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
@@ -114,24 +100,13 @@
app:layout_constraintTop_toBottomOf="@+id/btn_submit" app:layout_constraintTop_toBottomOf="@+id/btn_submit"
tools:listitem="@layout/offline_user_list_view" /> tools:listitem="@layout/offline_user_list_view" />
<ImageView
android:id="@+id/btnSaveLocal"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginEnd="10dp"
android:src="@drawable/downloads"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@+id/rv_order_offline"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/internetAvailableCL" android:id="@+id/internetAvailableCL"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:visibility="visible" android:visibility="gone"
android:padding="24dp"> android:padding="24dp">
<TextView <TextView
@@ -251,32 +226,6 @@
app:layout_constraintTop_toBottomOf="@+id/radioGroup" app:layout_constraintTop_toBottomOf="@+id/radioGroup"
tools:listitem="@layout/user_item_view"/> tools:listitem="@layout/user_item_view"/>
<TextView
android:id="@+id/labelQuickCapture"
style="@style/title1_1"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Quick Capture"
app:layout_constraintBottom_toTopOf="@+id/btnQuickCapture"
app:layout_constraintEnd_toEndOf="parent" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/btnQuickCapture"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:backgroundTint="@color/primary"
android:contentDescription="Capture measurements quickly"
android:src="@drawable/flask"
app:elevation="1dp"
app:layout_constraintBottom_toTopOf="@+id/label"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<TextView <TextView
android:id="@+id/label" android:id="@+id/label"
style="@style/title1_1" style="@style/title1_1"

View File

@@ -1,264 +0,0 @@
<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.trueheme.TrueHemeFragment">
<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"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_title" />
<!-- <TextView-->
<!-- android:id="@+id/tv_subtitle3"-->
<!-- style="@style/title2"-->
<!-- android:layout_width="0dp"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_marginHorizontal="24dp"-->
<!-- android:layout_marginTop="16dp"-->
<!-- android:text="@string/step5"-->
<!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toBottomOf="@id/tv_subtitle2" />-->
<TextView
android:id="@+id/tv_name"
style="@style/title2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:gravity="center"
android:padding="12dp"
android:layout_marginTop="26dp"
android:textFontWeight="700"
android:text="Name: SMI\n ID: 1672282828"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="MissingConstraints" />
<TextView
android:id="@+id/tv_subtitle4"
style="@style/title1_1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="72dp"
android:gravity="center"
android:textColor="@color/red"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/et_abha_id" />
<!-- <Button-->
<!-- android:visibility="gone"-->
<!-- android:id="@+id/btn_samplestart"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_marginHorizontal="16dp"-->
<!-- android:layout_marginTop="24dp"-->
<!-- android:clickable="false"-->
<!-- android:text="@string/Start_Sample"-->
<!-- android:textColor="@color/white"-->
<!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toBottomOf="@id/til_blood_group" />-->
<!-- <Button-->
<!-- android:id="@+id/btn_placebuffer"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_marginHorizontal="16dp"-->
<!-- android:layout_marginTop="24dp"-->
<!-- android:clickable="false"-->
<!-- android:text="@string/place_buffer"-->
<!-- android:textColor="@color/white"-->
<!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toBottomOf="@id/btn_submit" />-->
<TextView
android:id="@+id/tv_title2"
style="@style/title1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="48dp"
android:text="@string/enter_kit_serial_number_manually"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="MissingConstraints" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/et_abha_id"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="20dp"
app:layout_constraintEnd_toStartOf="@id/btn_go"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_title2">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/name_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLength="17"
android:inputType="text"
android:hint="@string/serial_number" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_go"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="24dp"
android:text="@string/go"
app:cornerRadius="16dp"
app:layout_constraintBottom_toBottomOf="@id/et_abha_id"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toEndOf="@id/et_abha_id"
app:layout_constraintTop_toTopOf="@id/et_abha_id" />
<Button
android:visibility="gone"
android:id="@+id/btn_samplestart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:text="@string/Start_Sample"
android:textColor="@color/white"
app:cornerRadius="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_placebuffer" />
<Button
android:id="@+id/btn_placebuffer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:text="@string/place_buffer"
android:textColor="@color/white"
app:cornerRadius="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_submit" />
<Button
android:id="@+id/btn_submit"
android:visibility="gone"
android:layout_width="match_parent"
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:cornerRadius="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle4" />
<TextView
android:id="@+id/error_message"
style="@style/title1_1"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="72dp"
android:gravity="center"
android:textColor="@color/red"
android:textSize="12sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_submit" />
<TextView
android:id="@+id/tv_device_messages"
style="@style/title1_1"
android:layout_width="414dp"
android:layout_height="201dp"
android:gravity="center"
android:text="no device message"
android:textColor="@color/black"
android:textSize="11sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/error_message" />
<Button
android:visibility="gone"
android:id="@+id/btn_digitalCard"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:text="DigitalCard View"
android:textColor="@color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/error_message" />
<ImageView
android:id="@+id/iv_check"
android:visibility="gone"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginTop="40dp"
android:importantForAccessibility="no"
android:src="@drawable/check"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_device_messages" />
<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

@@ -47,21 +47,7 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/userID" app:layout_constraintTop_toBottomOf="@id/userID"
tools:text="UserID: Mariya" /> tools:text="UserID: MohamedKaif" />
<TextView
android:id="@+id/teststatus"
android:layout_width="0dp"
android:layout_height="wrap_content"
style="@style/title1_1"
android:layout_marginTop="4dp"
android:layout_marginStart="16dp"
android:gravity="start"
android:textColor="@color/black"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/bloodGroup"
tools:text="Test Status: Completed"/>
<TextView <TextView
android:id="@+id/time" android:id="@+id/time"
@@ -75,8 +61,9 @@
android:textSize="14sp" android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/teststatus" app:layout_constraintTop_toBottomOf="@id/bloodGroup"
tools:text="startedAt: yyyy-MM-dd HH:mm:ss" /> tools:text="Test Status: Completed" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView> </androidx.cardview.widget.CardView>

View File

@@ -10,7 +10,7 @@
android:title="@string/menu_home" /> android:title="@string/menu_home" />
<item <item
android:id="@+id/nav_profile" android:id="@+id/nav_profile"
android:icon="@drawable/control_panel" android:icon="@drawable/baseline_person_24"
android:title="@string/profile" /> android:title="@string/profile" />
<item <item
android:id="@+id/nav_settings" android:id="@+id/nav_settings"

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