Compare commits

...

8 Commits

18 changed files with 579 additions and 75 deletions

View File

@@ -1,13 +1,23 @@
# Latest hpos app version # Latest hpos app version
## current version : 2.1.132 ### current version : 2.1.133
### Release key ### Release key
key0: prime24 key0: prime24
### Version 133.3
Printer not added yet
//update it when it is completed #### **Change logs :**
- [✅] Auto Sumbmit
- [✅] Auto Sumbmit Toggle
- [✅] Genegrate report
- [✅] Report Selector
- [✅] Report Printer
- [✅] Report Disclaimer Editor
#### **Completed 👌**
**version of android studio used**
`Android Studio Koala Feature Drop | 2024.1.2 Patch 1`

View File

@@ -21,8 +21,8 @@ android {
applicationId "in.sminnovations.hpostesting.server" applicationId "in.sminnovations.hpostesting.server"
minSdk 30 minSdk 30
targetSdk 34 targetSdk 34
versionCode 138 versionCode 139
versionName "2.1.133.3" versionName "2.1.133"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild { externalNativeBuild {
cmake { cmake {

View File

@@ -43,7 +43,7 @@
android:theme="@style/Theme.HPOSTesting" android:theme="@style/Theme.HPOSTesting"
tools:targetApi="31"> tools:targetApi="31">
<activity <activity
android:name="com.example.hpostesting.data.model.reportgen.ReportActivity" android:name="com.example.hpostesting.presentation.reportgen.ReportActivity"
android:exported="false" /> android:exported="false" />
<activity <activity
android:name="com.example.hpostesting.presentation.main_base.UpdateValuesActivity" android:name="com.example.hpostesting.presentation.main_base.UpdateValuesActivity"

View File

@@ -25,7 +25,7 @@ import android.view.ViewGroup
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import com.example.hpostesting.data.constant.Constants import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.model.reportgen.ReportActivity import com.example.hpostesting.presentation.reportgen.ReportActivity
import com.example.hpostesting.presentation.autodac.AutoDacActivity 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.calibration.CalibrationActivity
@@ -140,7 +140,7 @@ class PanelFragment : Fragment() {
} }
binding.btnPrintReport.setOnClickListener{ binding.btnPrintReport.setOnClickListener{
startActivity(Intent(requireContext(),ReportActivity::class.java)) startActivity(Intent(requireContext(), ReportActivity::class.java))
} }
binding.btnFirefox.setOnClickListener { binding.btnFirefox.setOnClickListener {

View File

@@ -17,6 +17,9 @@ import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Bundle import android.os.Bundle
import android.text.InputFilter
import android.text.InputType
import android.view.Gravity
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@@ -24,7 +27,9 @@ import android.widget.AdapterView
import android.widget.ArrayAdapter import android.widget.ArrayAdapter
import android.widget.Toast import android.widget.Toast
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.edit
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.preference.EditTextPreference
import androidx.preference.ListPreference import androidx.preference.ListPreference
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
@@ -41,7 +46,12 @@ import `in`.sminnovations.hpostesting.databinding.FragmentSlideshowBinding
private var isLanguageChanged = false private var isLanguageChanged = false
private val DEFAULT_DISCLAIMER = """
DISCLAIMER: This report is generated by HemoCube automated system.
Results should be interpreted by qualified medical professionals.
This report is for diagnostic purposes only and should not be used as the sole basis for medical decisions.
Please consult with your healthcare provider for proper interpretation and treatment recommendations.
""".trimIndent()
class SlideshowFragment : Fragment() { class SlideshowFragment : Fragment() {
private var selectedItem = "10mm" private var selectedItem = "10mm"
private val values = arrayOf("10mm", "2mm") private val values = arrayOf("10mm", "2mm")
@@ -58,7 +68,6 @@ class SlideshowFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
binding.nameEditText.setText(sharedPreferences.getString(Constants.LABNAME, "")) binding.nameEditText.setText(sharedPreferences.getString(Constants.LABNAME, ""))
selectedItem = sharedPreferences.getString(Constants.CUVETTE_SIZE, "10mm").toString() selectedItem = sharedPreferences.getString(Constants.CUVETTE_SIZE, "10mm").toString()
binding.btnGo.setOnClickListener { binding.btnGo.setOnClickListener {
@@ -120,6 +129,8 @@ class PrefsFragment : PreferenceFragmentCompat() {
private lateinit var serverPreference: Preference private lateinit var serverPreference: Preference
private lateinit var currentServerPreference: Preference private lateinit var currentServerPreference: Preference
lateinit var firebaseManager: FirebaseManager lateinit var firebaseManager: FirebaseManager
var autoSmbtValue = false
var reportDisclaimerText = DEFAULT_DISCLAIMER
private var topDevMode = false private var topDevMode = false
lateinit var databaseRepository: DatabaseRepository lateinit var databaseRepository: DatabaseRepository
@@ -130,10 +141,12 @@ class PrefsFragment : PreferenceFragmentCompat() {
topDevMode = firebaseManager.getDevMode() topDevMode = firebaseManager.getDevMode()
val sharedPreference = val sharedPreference =
requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE) requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
autoSmbtValue = sharedPreference.getBoolean("AutSmbt", false)
reportDisclaimerText = sharedPreference.getString("report_dis_txt", DEFAULT_DISCLAIMER).toString()
val preferenceScreen = preferenceManager.createPreferenceScreen(requireContext()) val preferenceScreen = preferenceManager.createPreferenceScreen(requireContext())
val currentServer = firebaseManager.getLastSelectedServer().serverName val currentServer = firebaseManager.getLastSelectedServer().serverName
val arWeAdmin =sharedPreference.getString(Constants.USER_ID, "").toString() == "ADMIN"
val MAX_CHARS = 10_000
// Language Preference // Language Preference
val languagePreference = ListPreference(requireContext()).apply { val languagePreference = ListPreference(requireContext()).apply {
key = "language_preference" key = "language_preference"
@@ -200,6 +213,70 @@ class PrefsFragment : PreferenceFragmentCompat() {
} }
} }
val disclaimerPreference = EditTextPreference(requireContext()).apply {
key = "Report_disclaimer"
title = "Report disclaimer Editor"
icon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_add)
summaryProvider = Preference.SummaryProvider<EditTextPreference> { preference ->
val value = preference.text
if (value.isNullOrBlank()) {
"Current disclaimer: (not set)"
} else {
"Current disclaimer: $value"
}
}
setOnBindEditTextListener { edit ->
edit.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_MULTI_LINE
edit.minLines = 4
edit.maxLines = 10
edit.gravity = Gravity.TOP or Gravity.START
edit.filters = arrayOf(InputFilter.LengthFilter(MAX_CHARS))
}
setOnPreferenceChangeListener { _, newValue ->
val text = (newValue as? String)?.trim().orEmpty()
if (text.length > MAX_CHARS) {
Toast.makeText(
requireContext(),
"Text too long (${text.length}/$MAX_CHARS).",
Toast.LENGTH_SHORT
).show()
return@setOnPreferenceChangeListener false
}else{
sharedPreference.edit().putString("report_dis_txt", text).apply()
}
true
}
}
val resetDisclaimerPreference = Preference(requireContext()).apply {
title = "Reset to default Disclaimer"
summary = "Replace the current text with the app’s default disclaimer"
icon = ContextCompat.getDrawable(requireContext(), R.drawable.baseline_restore_24)
setOnPreferenceClickListener {
sharedPreference.edit().putString("report_dis_txt", DEFAULT_DISCLAIMER).apply()
disclaimerPreference.text = DEFAULT_DISCLAIMER
Toast.makeText(requireContext(), "Disclaimer reset to default", Toast.LENGTH_SHORT).show()
true
}
}
val autosmbt = SwitchPreferenceCompat(requireContext()).apply {
title = "Auto submit"
summary = "Enable or disable Auto submit"
icon =
ContextCompat.getDrawable(requireContext(), R.drawable.baseline_motion_auto_24)
key = "auto_submit_key" // Unique key for SharedPreferences
// Load toggle state from SharedPreferences
isChecked = autoSmbtValue
setOnPreferenceChangeListener { _, newValue ->
val isEnabled = newValue as Boolean
sharedPreference.edit {
putBoolean("AutSmbt",isEnabled)
}
true
}
}
val appVersionPreference = Preference(requireContext()).apply { val appVersionPreference = Preference(requireContext()).apply {
title = "App Version" title = "App Version"
summary = summary =
@@ -208,33 +285,43 @@ class PrefsFragment : PreferenceFragmentCompat() {
setOnPreferenceClickListener { setOnPreferenceClickListener {
tapManager.registerTap { tapManager.registerTap {
if (arWeAdmin) {
firebaseManager.setDevModeOn(true) firebaseManager.setDevModeOn(true)
if (firebaseManager.getDevMode() && currentServer != "dev") { if (firebaseManager.getDevMode() && currentServer != "dev") {
Toast.makeText(requireContext(), "Now you are a Developer", Toast.LENGTH_SHORT).show() Toast.makeText(requireContext(), "Now you are a Developer", Toast.LENGTH_SHORT).show()
Toast.makeText(requireContext(), "Setting Up developer Environmnet", Toast.LENGTH_SHORT).show() Toast.makeText(requireContext(), "Setting Up developer Environment", Toast.LENGTH_SHORT).show()
} }
if (preferenceScreen.findPreference<SwitchPreferenceCompat>("developer_options") == null) { if (preferenceScreen.findPreference<SwitchPreferenceCompat>("developer_options") == null) {
preferenceScreen.addPreference(developerToggle) preferenceScreen.addPreference(developerToggle)
preferenceScreen.addPreference(autosmbt)
preferenceScreen.addPreference(disclaimerPreference)
preferenceScreen.addPreference(resetDisclaimerPreference)
} }
if (preferenceScreen.findPreference<ListPreference>("server_preference") == null) { if (preferenceScreen.findPreference<ListPreference>("server_preference") == null) {
preferenceScreen.addPreference(serverSelectorPreference) preferenceScreen.addPreference(serverSelectorPreference)
} }
developerToggle.isChecked = true developerToggle.isChecked = true
updateServerPreference(currentServer) updateServerPreference(currentServer)
}else{
Toast.makeText(requireContext(), "Works Only On Admin Mode", Toast.LENGTH_SHORT).show()
}
} }
true true
} }
} }
preferenceScreen.addPreference(appVersionPreference) preferenceScreen.addPreference(appVersionPreference)
if (firebaseManager.getDevMode()) { if (firebaseManager.getDevMode() && arWeAdmin) {
developerToggle.isChecked = true // Ensure it's checked developerToggle.isChecked = true // Ensure it's checked
preferenceScreen.addPreference(developerToggle) preferenceScreen.addPreference(developerToggle)
preferenceScreen.addPreference(serverSelectorPreference) preferenceScreen.addPreference(serverSelectorPreference)
preferenceScreen.addPreference(autosmbt)
preferenceScreen.addPreference(resetDisclaimerPreference)
preferenceScreen.addPreference(disclaimerPreference)
} }
setPreferenceScreen(preferenceScreen) setPreferenceScreen(preferenceScreen)
@@ -244,6 +331,12 @@ class PrefsFragment : PreferenceFragmentCompat() {
} }
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
listView.setPadding(0, 0, 0, 300) // Add bottom padding
listView.clipToPadding = false
}
private fun updateServerPreference(newServer: String) { private fun updateServerPreference(newServer: String) {
(findPreference<CustomDialogPreference>("server_preference"))?.let { pref -> (findPreference<CustomDialogPreference>("server_preference"))?.let { pref ->

View File

@@ -1,8 +1,8 @@
package com.example.hpostesting.data.model.reportgen package com.example.hpostesting.presentation.reportgen
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle import android.os.Bundle
import com.example.hpostesting.data.model.reportgen.ui.report.ReportFragment import com.example.hpostesting.presentation.reportgen.ui.report.ReportFragment
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.R
@AndroidEntryPoint @AndroidEntryPoint

View File

@@ -1,4 +1,4 @@
package com.example.hpostesting.data.model.reportgen.ui.report package com.example.hpostesting.presentation.reportgen.ui.report
import android.graphics.Color import android.graphics.Color
import android.view.LayoutInflater import android.view.LayoutInflater

View File

@@ -0,0 +1,326 @@
package com.example.hpostesting.presentation.reportgen.ui.report
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Typeface
import android.graphics.pdf.PdfDocument
import android.util.Log
import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import `in`.sminnovations.hpostesting.R
import java.io.File
import java.io.FileOutputStream
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
object ReportGen {
private const val PAGE_WIDTH = 595 // A4 width in points
private const val PAGE_HEIGHT = 842 // A4 height in points
private const val MARGIN_LEFT = 50f
private const val MARGIN_RIGHT = 50f
private const val MARGIN_TOP = 80f
private const val MARGIN_BOTTOM = 80f
fun generate(context: Context, dataList: List<HemoCubeTestData>,disclaimerText: String) {
if (dataList.isEmpty()) {
Toast.makeText(context, "No items selected for report generation", Toast.LENGTH_SHORT).show()
return
}
Log.d("ReportGen", "Generating report for ${dataList.size} items")
val message = if (dataList.size == 1) {
"Report for kit ${dataList.first()._id} started."
} else {
"Report for ${dataList.size} kits started."
}
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
val pdfFile = createProfessionalPdfReport(context, dataList, disclaimerText)
previewPdf(context, pdfFile)
}
private fun createProfessionalPdfReport(context: Context, dataList: List<HemoCubeTestData>,disclaimerText : String): File {
val timestamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
val file = File(context.getExternalFilesDir(null), "HemoCube_Report_$timestamp.pdf")
val pdfDocument = PdfDocument()
// Paint styles
val headerPaint = Paint().apply {
typeface = Typeface.create(Typeface.DEFAULT_BOLD, Typeface.BOLD)
textSize = 20f
color = Color.rgb(0, 102, 153) // Professional blue
}
val titlePaint = Paint().apply {
typeface = Typeface.create(Typeface.DEFAULT_BOLD, Typeface.BOLD)
textSize = 18f
color = Color.BLACK
}
val sectionHeaderPaint = Paint().apply {
typeface = Typeface.create(Typeface.DEFAULT_BOLD, Typeface.BOLD)
textSize = 14f
color = Color.rgb(0, 102, 153)
}
val contentPaint = Paint().apply {
textSize = 11f
color = Color.DKGRAY
}
val boldContentPaint = Paint().apply {
typeface = Typeface.create(Typeface.DEFAULT_BOLD, Typeface.BOLD)
textSize = 11f
color = Color.BLACK
}
val disclaimerPaint = Paint().apply {
textSize = 9f
color = Color.GRAY
typeface = Typeface.create(Typeface.DEFAULT, Typeface.ITALIC)
}
// Create one page per test data
dataList.forEachIndexed { index, testData ->
val pageInfo = PdfDocument.PageInfo.Builder(PAGE_WIDTH, PAGE_HEIGHT, index + 1).create()
val page = pdfDocument.startPage(pageInfo)
val canvas = page.canvas
drawPage(canvas, testData, index + 1, dataList.size,
headerPaint, titlePaint, sectionHeaderPaint,
contentPaint, boldContentPaint, disclaimerPaint,disclaimerText,context)
pdfDocument.finishPage(page)
}
pdfDocument.writeTo(FileOutputStream(file))
pdfDocument.close()
return file
}
private fun drawPage(
canvas: Canvas,
testData: HemoCubeTestData,
pageNumber: Int,
totalPages: Int,
headerPaint: Paint,
titlePaint: Paint,
sectionHeaderPaint: Paint,
contentPaint: Paint,
boldContentPaint: Paint,
disclaimerPaint: Paint,
disclaimerText: String,
context: Context
) {
var currentY = MARGIN_TOP
// Header with logo placeholder and title
drawHeader(canvas, headerPaint, titlePaint, currentY, context)
currentY += 100f
// Sample Information Section
currentY = drawSection(canvas, "SAMPLE INFORMATION", sectionHeaderPaint, currentY)
currentY = drawKeyValuePair(canvas, "Sample ID:", testData.sampleid.toString(), boldContentPaint, contentPaint, currentY)
currentY = drawKeyValuePair(canvas, "Blood Group:", testData.bloodGroup, boldContentPaint, contentPaint, currentY)
currentY += 15f
// Test Information Section
currentY = drawSection(canvas, "TEST INFORMATION", sectionHeaderPaint, currentY)
currentY = drawKeyValuePair(canvas, "Test ID:", testData._id, boldContentPaint, contentPaint, currentY)
currentY = drawKeyValuePair(canvas, "Test Type:", testData.testType ?: "TrueHeme", boldContentPaint, contentPaint, currentY)
currentY = drawKeyValuePair(canvas, "Test Time:", testData.testTime ?: "N/A", boldContentPaint, contentPaint, currentY)
currentY = drawKeyValuePair(canvas, "Incubation Time:", testData.incubationTime, boldContentPaint, contentPaint, currentY)
currentY = drawKeyValuePair(canvas, "Kit Serial:", testData.kitSerial, boldContentPaint, contentPaint, currentY)
currentY = drawKeyValuePair(canvas, "Device Serial:", testData.deviceSerialNumber, boldContentPaint, contentPaint, currentY)
currentY += 15f
// Test Results Section
currentY = drawSection(canvas, "TEST RESULTS", sectionHeaderPaint, currentY)
currentY = drawKeyValuePair(canvas, "Classification Result:", testData.classificationResult, boldContentPaint, contentPaint, currentY)
currentY = drawKeyValuePair(canvas, "Device Ratio:", testData.deviceRatio?.toString() ?: "N/A", boldContentPaint, contentPaint, currentY)
currentY = drawKeyValuePair(canvas, "Calculated Ratio:", testData.calculatedRatio?.toString() ?: "N/A", boldContentPaint, contentPaint, currentY)
currentY = drawKeyValuePair(canvas, "Slope Ratio:", testData.slopeRatio?.toString() ?: "N/A", boldContentPaint, contentPaint, currentY)
currentY += 15f
// LED Measurements Section
currentY = drawSection(canvas, "LED MEASUREMENTS", sectionHeaderPaint, currentY)
currentY = drawLEDData(canvas, testData, boldContentPaint, contentPaint, currentY)
currentY += 15f
// Laboratory Information Section
currentY = drawSection(canvas, "LABORATORY INFORMATION", sectionHeaderPaint, currentY)
currentY = drawKeyValuePair(canvas, "Lab Name:", testData.labName ?: "N/A", boldContentPaint, contentPaint, currentY)
currentY = drawKeyValuePair(canvas, "Center Name:", testData.centerName ?: "N/A", boldContentPaint, contentPaint, currentY)
currentY = drawKeyValuePair(canvas, "District:", testData.district ?: "N/A", boldContentPaint, contentPaint, currentY)
currentY += 15f
// Footer with page number and disclaimer
drawFooter(canvas, pageNumber, totalPages, contentPaint, disclaimerPaint,disclaimerText)
}
private fun drawHeader(canvas: Canvas, headerPaint: Paint, titlePaint: Paint, startY: Float, context: Context) {
// Load and draw actual logo
try {
// Method 1: Load from drawable resources
val logoDrawable = ContextCompat.getDrawable(context, R.mipmap.hpos_icon) // Replace with your logo resource
logoDrawable?.let { drawable ->
val logoWidth = 70
val logoHeight = 60
drawable.setBounds(
MARGIN_LEFT.toInt(),
(startY - 20f).toInt(),
(MARGIN_LEFT + logoWidth).toInt(),
(startY + logoHeight - 20f).toInt()
)
drawable.draw(canvas)
}
} catch (e: Exception) {
// Fallback to placeholder if logo loading fails
val logoPaint = Paint().apply {
color = Color.rgb(0, 102, 153)
style = Paint.Style.FILL
}
canvas.drawRect(MARGIN_LEFT, startY - 20f, MARGIN_LEFT + 60f, startY + 20f, logoPaint)
// Draw "LOGO" text as placeholder
val placeholderPaint = Paint().apply {
color = Color.WHITE
textSize = 12f
typeface = Typeface.create(Typeface.DEFAULT_BOLD, Typeface.BOLD)
textAlign = Paint.Align.CENTER
}
canvas.drawText("LOGO", MARGIN_LEFT + 30f, startY, placeholderPaint)
}
// Company name and title
canvas.drawText("HemoCube", MARGIN_LEFT + 80f, startY + 10f, headerPaint)
canvas.drawText("Medical Test Report", MARGIN_LEFT, startY + 40f, titlePaint)
// Report generation date
val currentDate = SimpleDateFormat("dd MMM yyyy, HH:mm", Locale.getDefault()).format(Date())
canvas.drawText("Generated: $currentDate", PAGE_WIDTH - MARGIN_RIGHT - 150f, startY + 10f, Paint().apply {
textSize = 10f
color = Color.GRAY
})
// Line under header
val linePaint = Paint().apply {
color = Color.rgb(0, 102, 153)
strokeWidth = 2f
}
canvas.drawLine(MARGIN_LEFT, startY + 60f, PAGE_WIDTH - MARGIN_RIGHT, startY + 60f, linePaint)
}
private fun drawSection(canvas: Canvas, title: String, paint: Paint, y: Float): Float {
canvas.drawText(title, MARGIN_LEFT, y, paint)
// Underline for section
val linePaint = Paint().apply {
color = Color.rgb(0, 102, 153)
strokeWidth = 1f
}
canvas.drawLine(MARGIN_LEFT, y + 5f, MARGIN_LEFT + paint.measureText(title), y + 5f, linePaint)
return y + 25f
}
private fun drawKeyValuePair(canvas: Canvas, key: String, value: String, keyPaint: Paint, valuePaint: Paint, y: Float): Float {
canvas.drawText(key, MARGIN_LEFT + 10f, y, keyPaint)
canvas.drawText(value, MARGIN_LEFT + 150f, y, valuePaint)
return y + 18f
}
private fun drawLEDData(canvas: Canvas, testData: HemoCubeTestData, keyPaint: Paint, valuePaint: Paint, startY: Float): Float {
var currentY = startY
currentY = drawKeyValuePair(canvas, "LED1 Sample:", testData.led1Sample?.toString() ?: "N/A", keyPaint, valuePaint, currentY)
currentY = drawKeyValuePair(canvas, "LED2 Sample:", testData.led2Sample?.toString() ?: "N/A", keyPaint, valuePaint, currentY)
currentY = drawKeyValuePair(canvas, "LED3 Sample:", testData.led3Sample?.toString() ?: "N/A", keyPaint, valuePaint, currentY)
currentY = drawKeyValuePair(canvas, "LED4 Sample:", testData.led4Sample?.toString() ?: "N/A", keyPaint, valuePaint, currentY)
currentY = drawKeyValuePair(canvas, "ABS1:", testData.abs1?.toString() ?: "N/A", keyPaint, valuePaint, currentY)
currentY = drawKeyValuePair(canvas, "ABS2:", testData.abs2?.toString() ?: "N/A", keyPaint, valuePaint, currentY)
currentY = drawKeyValuePair(canvas, "ABS3:", testData.abs3?.toString() ?: "N/A", keyPaint, valuePaint, currentY)
currentY = drawKeyValuePair(canvas, "ABS4:", testData.abs4?.toString() ?: "N/A", keyPaint, valuePaint, currentY)
return currentY
}
private fun drawFooter(canvas: Canvas, pageNumber: Int, totalPages: Int, contentPaint: Paint, disclaimerPaint: Paint,disclaimerText: String) {
val footerY = PAGE_HEIGHT - MARGIN_BOTTOM + 20f
// Page number
canvas.drawText("Page $pageNumber of $totalPages", PAGE_WIDTH - MARGIN_RIGHT - 80f, footerY, contentPaint)
// Disclaimer
val disclaimerLines = wrapText(disclaimerText, disclaimerPaint, PAGE_WIDTH - MARGIN_LEFT - MARGIN_RIGHT)
var disclaimerY = footerY + 20f
disclaimerLines.forEach { line ->
canvas.drawText(line, MARGIN_LEFT, disclaimerY, disclaimerPaint)
disclaimerY += 12f
}
// Footer line
val linePaint = Paint().apply {
color = Color.rgb(0, 102, 153)
strokeWidth = 1f
}
canvas.drawLine(MARGIN_LEFT, footerY - 10f, PAGE_WIDTH - MARGIN_RIGHT, footerY - 10f, linePaint)
}
private fun wrapText(text: String, paint: Paint, maxWidth: Float): List<String> {
val words = text.split(" ")
val lines = mutableListOf<String>()
var currentLine = ""
for (word in words) {
val testLine = if (currentLine.isEmpty()) word else "$currentLine $word"
if (paint.measureText(testLine) <= maxWidth) {
currentLine = testLine
} else {
if (currentLine.isNotEmpty()) {
lines.add(currentLine)
}
currentLine = word
}
}
if (currentLine.isNotEmpty()) {
lines.add(currentLine)
}
return lines
}
private fun previewPdf(context: Context, file: File) {
val uri = FileProvider.getUriForFile(
context,
"${context.packageName}.fileprovider",
file
)
val intent = Intent(Intent.ACTION_VIEW).apply {
setDataAndType(uri, "application/pdf")
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_ACTIVITY_NO_HISTORY
}
try {
context.startActivity(intent)
} catch (e: ActivityNotFoundException) {
Toast.makeText(context, "No PDF viewer found", Toast.LENGTH_SHORT).show()
}
}
}

View File

@@ -1,7 +1,8 @@
package com.example.hpostesting.data.model.reportgen.ui.report package com.example.hpostesting.presentation.reportgen.ui.report
import android.app.DatePickerDialog import android.app.DatePickerDialog
import android.content.Context import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
@@ -26,12 +27,21 @@ 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
private val DEFAULT_DISCLAIMER = """
DISCLAIMER: This report is generated by HemoCube automated system.
Results should be interpreted by qualified medical professionals.
This report is for diagnostic purposes only and should not be used as the sole basis for medical decisions.
Please consult with your healthcare provider for proper interpretation and treatment recommendations.
""".trimIndent()
@AndroidEntryPoint @AndroidEntryPoint
class ReportFragment : Fragment() { class ReportFragment : Fragment() {
companion object { companion object {
fun newInstance() = ReportFragment() fun newInstance() = ReportFragment()
} }
private lateinit var sharedPreferences: SharedPreferences
private val viewModel: ReportViewModel by viewModels() private val viewModel: ReportViewModel by viewModels()
@@ -47,12 +57,14 @@ class ReportFragment : Fragment() {
private var allData: List<HemoCubeTestData> = emptyList() private var allData: List<HemoCubeTestData> = emptyList()
private var currentFilter = "Today" private var currentFilter = "Today"
private var customDate: String? = null private var customDate: String? = null
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View = inflater.inflate(R.layout.fragment_report, container, false) ): View = inflater.inflate(R.layout.fragment_report, container, false)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
sharedPreferences = requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
initViews(view) initViews(view)
setupRecyclerView() setupRecyclerView()
setupFilterSpinner() setupFilterSpinner()
@@ -133,7 +145,8 @@ class ReportFragment : Fragment() {
generateBtn.setOnClickListener { generateBtn.setOnClickListener {
if (selectedItems.isNotEmpty()) { if (selectedItems.isNotEmpty()) {
ReportGen.generate(requireContext(), selectedItems) ReportGen.generate(requireContext(), selectedItems, disclaimerText = sharedPreferences.getString("report_dis_txt",
DEFAULT_DISCLAIMER).toString())
} }
} }
} }
@@ -204,31 +217,3 @@ class ReportFragment : Fragment() {
updateUI() updateUI()
} }
} }
object ReportGen {
fun generate(context: Context, dataList: List<HemoCubeTestData>) {
if (dataList.isEmpty()) {
Toast.makeText(context, "No items selected for report generation", Toast.LENGTH_SHORT).show()
return
}
Log.d("ReportGen", "Generating report for ${dataList.size} items")
val kitNumbers = dataList.map { it._id }
val message = if (dataList.size == 1) {
"Report for kit ${kitNumbers.first()} started."
} else {
"Report for ${dataList.size} kits started."
}
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
// TODO: Add PDF generation, email, or preview logic here
// You can iterate through dataList to include all selected items in the report
dataList.forEach { item->
Log.d("ReportGen", "Processing kit: ${item._id}, Result: ${item.classificationResult}, Time: ${item.testTime}")
}
}
}

View File

@@ -1,4 +1,4 @@
package com.example.hpostesting.data.model.reportgen.ui.report package com.example.hpostesting.presentation.reportgen.ui.report
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel

View File

@@ -55,8 +55,11 @@ import kotlin.math.log10
import kotlin.random.Random import kotlin.random.Random
//This is TrueHemeTestFragment, where actual tests are done first buffer check and then sample check //This is TrueHemeTestFragment, where actual tests are done first buffer check and then sample check
//and finally on submit test data to database if online or store in offline database //and finally on submit test data to database if online or store in offline database
@Suppress("MemberVisibilityCanBePrivate") @Suppress("MemberVisibilityCanBePrivate")
class TrueHemeTestFragment : Fragment() { class TrueHemeTestFragment : Fragment() {
private var doWeNeedAutoSmbt = false
private var positiveBoderLine10mm1=Constants.positiveBoderLineMetricCheck10mmMin private var positiveBoderLine10mm1=Constants.positiveBoderLineMetricCheck10mmMin
private var positiveBoderLine10mm2=Constants.positiveBoderLineMetricCheck10mmMax private var positiveBoderLine10mm2=Constants.positiveBoderLineMetricCheck10mmMax
private var negativeBoderLine10mm1=Constants.negativeBoderLineMetricCheck10mmMin private var negativeBoderLine10mm1=Constants.negativeBoderLineMetricCheck10mmMin
@@ -90,6 +93,7 @@ class TrueHemeTestFragment : Fragment() {
private var temperature="" private var temperature=""
private var cuvetteSizeSP = "10mm" private var cuvetteSizeSP = "10mm"
private var checkCuvette = false private var checkCuvette = false
private var checkCuvettePresent = false
private var checkRefreshCuvette = false private var checkRefreshCuvette = false
private var checkCuvetteSam = false private var checkCuvetteSam = false
private var checkSubmit = false private var checkSubmit = false
@@ -137,7 +141,7 @@ class TrueHemeTestFragment : Fragment() {
binding = FragmentHemoCubeReferenceBinding.inflate(inflater, container, false) binding = FragmentHemoCubeReferenceBinding.inflate(inflater, container, false)
sharedPreferences = sharedPreferences =
requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE) requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
doWeNeedAutoSmbt = sharedPreferences.getBoolean("AutSmbt", false)
cuvetteSizeSP = sharedPreferences.getString(Constants.CUVETTE_SIZE,"10mm").toString() cuvetteSizeSP = sharedPreferences.getString(Constants.CUVETTE_SIZE,"10mm").toString()
testState = TestState( testState = TestState(
@@ -163,9 +167,11 @@ class TrueHemeTestFragment : Fragment() {
lifecycleScope.launch { lifecycleScope.launch {
delay(100) delay(100)
} }
checkCuvettePresence()
lifecycleScope.launch {
delay(3000)
}
activity?.runOnUiThread { activity?.runOnUiThread {
if (checkSubmit) {
with(sharedPreferences.edit()) { with(sharedPreferences.edit()) {
putBoolean(Constants.QUICK_CAPTURE, false) putBoolean(Constants.QUICK_CAPTURE, false)
apply() apply()
@@ -186,22 +192,18 @@ class TrueHemeTestFragment : Fragment() {
sharedPreferences.getString(Constants.KIT_NUMBER, ""), sharedPreferences.getString(Constants.KIT_NUMBER, ""),
quickCapture quickCapture
) )
Toast.makeText(requireContext(), "Auto Sumbitted", Toast.LENGTH_SHORT).show() Toast.makeText(requireContext(), "Auto Submitted", Toast.LENGTH_SHORT).show()
} else {
checkCuvettePresence()
binding.btnSubmit.isEnabled = true
binding.btnSubmit.isClickable = true
Toast.makeText(requireContext(), "Auto Sumbit Failed ", Toast.LENGTH_SHORT).show()
binding.btnSubmit.visibility = View.VISIBLE
}
} }
} }
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
private fun initViews() { private fun initViews() {
binding.tvSubtitle4.movementMethod = ScrollingMovementMethod() binding.tvSubtitle4.movementMethod = ScrollingMovementMethod()
binding.tvDeviceMessages.movementMethod = ScrollingMovementMethod() binding.tvDeviceMessages.movementMethod = ScrollingMovementMethod()
binding.btnGoback.setOnClickListener{
goback()
}
binding.btnSubmit.setOnClickListener { binding.btnSubmit.setOnClickListener {
// with(sharedPreferences.edit()) { // with(sharedPreferences.edit()) {
// putBoolean(Constants.QUICK_CAPTURE, false) // putBoolean(Constants.QUICK_CAPTURE, false)
@@ -248,6 +250,7 @@ class TrueHemeTestFragment : Fragment() {
binding.nameEditText.visibility = View.GONE binding.nameEditText.visibility = View.GONE
binding.tvTitle.visibility = View.GONE binding.tvTitle.visibility = View.GONE
binding.btnGo.visibility = View.GONE binding.btnGo.visibility = View.GONE
binding.btnGoback.visibility = View.GONE
// binding.btnPlacebuffer.visibility = View.GONE // binding.btnPlacebuffer.visibility = View.GONE
val cuvetteSize = sharedPreferences.getString(Constants.CUVETTE_SIZE,"10mm") val cuvetteSize = sharedPreferences.getString(Constants.CUVETTE_SIZE,"10mm")
val cuvetteText = "Cuvette Size: $cuvetteSize" val cuvetteText = "Cuvette Size: $cuvetteSize"
@@ -394,11 +397,34 @@ class TrueHemeTestFragment : Fragment() {
} }
if (result == "Local") { if (result == "Local") {
showToast(R.string.internt_not_local) showToast(R.string.internt_not_local)
//got it
if (doWeNeedAutoSmbt) {
if (!checkCuvettePresent) {
Toast.makeText(context, "Gooing back 2", Toast.LENGTH_SHORT).show()
startActivity(Intent(requireActivity(), DashboardActivity::class.java)) startActivity(Intent(requireActivity(), DashboardActivity::class.java))
}else{
makeRetryButtonVisible()
Toast.makeText(context, "Remove Cuvette", Toast.LENGTH_SHORT).show()
}
}else{
startActivity(Intent(requireActivity(), DashboardActivity::class.java))
}
} }
if (result == "Error") { if (result == "Error") {
showToast(R.string.error_local) showToast(R.string.error_local)
//got it
if (doWeNeedAutoSmbt) {
if (!checkCuvettePresent) {
Toast.makeText(context, "Gooing back", Toast.LENGTH_SHORT).show()
startActivity(Intent(requireActivity(), DashboardActivity::class.java)) startActivity(Intent(requireActivity(), DashboardActivity::class.java))
}else{
makeRetryButtonVisible()
Toast.makeText(context, "Remove Cuvette", Toast.LENGTH_SHORT).show()
}
}else{
startActivity(Intent(requireActivity(), DashboardActivity::class.java))
}
} }
binding.progressBar.visibility = View.GONE binding.progressBar.visibility = View.GONE
@@ -443,7 +469,18 @@ class TrueHemeTestFragment : Fragment() {
val i = Intent( val i = Intent(
requireContext().applicationContext, DashboardActivity::class.java requireContext().applicationContext, DashboardActivity::class.java
) )
//got it
if (doWeNeedAutoSmbt){
if (!checkCuvettePresent){
Toast.makeText(context, "Gooing back 3", Toast.LENGTH_SHORT).show()
startActivity(i) startActivity(i)
}else{
makeRetryButtonVisible()
Toast.makeText(context, "Remove Cuvette", Toast.LENGTH_SHORT).show()
}
}else {
startActivity(i)
}
} }
} else { } else {
trueHemeTestViewModel.messages.postValue("Reading $repeatReadingCount completed") trueHemeTestViewModel.messages.postValue("Reading $repeatReadingCount completed")
@@ -652,6 +689,7 @@ class TrueHemeTestFragment : Fragment() {
} }
} }
resultData.contains("#AIN") && sampleClick && this.testStatusCode <= TestStatus.CUVETTE_ABSENTS.code -> { resultData.contains("#AIN") && sampleClick && this.testStatusCode <= TestStatus.CUVETTE_ABSENTS.code -> {
checkCuvettePresent = false
trueHemeTestViewModel.messages.postValue(getString(R.string.cuvette_absent)) trueHemeTestViewModel.messages.postValue(getString(R.string.cuvette_absent))
this.testStatusCode = TestStatus.CUVETTE_ABSENTS.code this.testStatusCode = TestStatus.CUVETTE_ABSENTS.code
activity?.runOnUiThread { activity?.runOnUiThread {
@@ -664,6 +702,7 @@ class TrueHemeTestFragment : Fragment() {
this.testStatusCode = TestStatus.CUVETTE_PRESENTR.code this.testStatusCode = TestStatus.CUVETTE_PRESENTR.code
activity?.runOnUiThread { activity?.runOnUiThread {
checkRefreshCuvette = true checkRefreshCuvette = true
checkCuvettePresent =true
binding.testing.visibility = View.GONE binding.testing.visibility = View.GONE
binding.btnRetryCheckCuvette.visibility = View.GONE binding.btnRetryCheckCuvette.visibility = View.GONE
binding.btnPlaceRefreshbuffer.visibility = View.VISIBLE binding.btnPlaceRefreshbuffer.visibility = View.VISIBLE
@@ -674,6 +713,7 @@ class TrueHemeTestFragment : Fragment() {
} }
} }
resultData.contains("#AIN") && refreshClick && this.testStatusCode <= TestStatus.CUVETTE_ABSENTR.code -> { resultData.contains("#AIN") && refreshClick && this.testStatusCode <= TestStatus.CUVETTE_ABSENTR.code -> {
checkCuvettePresent = false
trueHemeTestViewModel.messages.postValue(getString(R.string.cuvette_absent)) trueHemeTestViewModel.messages.postValue(getString(R.string.cuvette_absent))
this.testStatusCode = TestStatus.CUVETTE_ABSENTR.code this.testStatusCode = TestStatus.CUVETTE_ABSENTR.code
activity?.runOnUiThread { activity?.runOnUiThread {
@@ -684,6 +724,7 @@ class TrueHemeTestFragment : Fragment() {
showRetryButtonForCuvette() showRetryButtonForCuvette()
} }
resultData.contains("#CIN") && this.testStatusCode < TestStatus.CUVETTE_PRESENT.code -> { resultData.contains("#CIN") && this.testStatusCode < TestStatus.CUVETTE_PRESENT.code -> {
checkCuvettePresent = true
trueHemeTestViewModel.messages.postValue(getString(R.string.cuvette_present)) trueHemeTestViewModel.messages.postValue(getString(R.string.cuvette_present))
this.testStatusCode = TestStatus.CUVETTE_PRESENT.code this.testStatusCode = TestStatus.CUVETTE_PRESENT.code
activity?.runOnUiThread { activity?.runOnUiThread {
@@ -697,6 +738,7 @@ class TrueHemeTestFragment : Fragment() {
} }
} }
resultData.contains("#AIN") && this.testStatusCode <= TestStatus.CUVETTE_ABSENT.code -> { resultData.contains("#AIN") && this.testStatusCode <= TestStatus.CUVETTE_ABSENT.code -> {
checkCuvettePresent = false
trueHemeTestViewModel.messages.postValue(getString(R.string.cuvette_absent)) trueHemeTestViewModel.messages.postValue(getString(R.string.cuvette_absent))
this.testStatusCode = TestStatus.CUVETTE_ABSENT.code this.testStatusCode = TestStatus.CUVETTE_ABSENT.code
activity?.runOnUiThread { activity?.runOnUiThread {
@@ -709,7 +751,12 @@ class TrueHemeTestFragment : Fragment() {
//need to change where check submit //need to change where check submit
resultData.contains("#CIN") && this.submitClick && this.testStatusCode < TestStatus.CUVETTE_PRESENTT.code -> { resultData.contains("#CIN") && this.submitClick && this.testStatusCode < TestStatus.CUVETTE_PRESENTT.code -> {
checkCuvettePresent = true
if (doWeNeedAutoSmbt){
trueHemeTestViewModel.messages.postValue(getString(R.string.cuvette_presentnt))
}else {
trueHemeTestViewModel.messages.postValue(getString(R.string.cuvette_presentt)) trueHemeTestViewModel.messages.postValue(getString(R.string.cuvette_presentt))
}
this.testStatusCode = TestStatus.CUVETTE_PRESENTT.code this.testStatusCode = TestStatus.CUVETTE_PRESENTT.code
activity?.runOnUiThread { activity?.runOnUiThread {
binding.testing.visibility = View.GONE binding.testing.visibility = View.GONE
@@ -718,6 +765,7 @@ class TrueHemeTestFragment : Fragment() {
resultData.contains("#AIN") && this.submitClick && this.testStatusCode <= TestStatus.CUVETTE_ABSENTT.code -> { resultData.contains("#AIN") && this.submitClick && this.testStatusCode <= TestStatus.CUVETTE_ABSENTT.code -> {
checkCuvettePresent = false
trueHemeTestViewModel.messages.postValue(getString(R.string.cuvette_absentt)) trueHemeTestViewModel.messages.postValue(getString(R.string.cuvette_absentt))
this.testStatusCode = TestStatus.CUVETTE_ABSENTT.code this.testStatusCode = TestStatus.CUVETTE_ABSENTT.code
activity?.runOnUiThread { activity?.runOnUiThread {
@@ -1011,11 +1059,14 @@ class TrueHemeTestFragment : Fragment() {
activity?.runOnUiThread { activity?.runOnUiThread {
//changing to invisible //changing to invisible
binding.btnSubmit.visibility = View.GONE binding.btnSubmit.visibility = View.VISIBLE
// binding.btnSubmit.isEnabled = true // binding.btnSubmit.isEnabled = true
// binding.btnSubmit.isClickable = true // binding.btnSubmit.isClickable = true
// binding.clParent.setBackgroundColor(Color.parseColor("#edfffd")) // binding.clParent.setBackgroundColor(Color.parseColor("#edfffd"))
autoSmbt(true) if (doWeNeedAutoSmbt) {
binding.btnSubmit.visibility = View.GONE
autoSmbt(doWeNeedAutoSmbt)
}
binding.ivCheck.visibility = View.VISIBLE binding.ivCheck.visibility = View.VISIBLE
} }
@@ -1703,7 +1754,6 @@ class TrueHemeTestFragment : Fragment() {
(activity as TrueHemeTestActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.CHECK_CUVETTE_COMMAND, (activity as TrueHemeTestActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.CHECK_CUVETTE_COMMAND,
object : UsbServiceListener { object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {} override fun onUsbRead(data: ByteArray?) {}
override fun onUsbError(e: Exception?) { override fun onUsbError(e: Exception?) {
trueHemeTestViewModel.progressBar.postValue(false) trueHemeTestViewModel.progressBar.postValue(false)
} }
@@ -1723,7 +1773,22 @@ class TrueHemeTestFragment : Fragment() {
} }
}) })
} }
fun goback(){
checkCuvettePresence()
lifecycleScope.launch {
delay(4000)
}
if (!checkCuvettePresent) {
startActivity(Intent(requireActivity(), DashboardActivity::class.java))
}
}
fun makeRetryButtonVisible(){
activity?.runOnUiThread {
binding.btnGoback.visibility = View.VISIBLE
}
}
private fun startSampleProcess() { private fun startSampleProcess() {
trueHemeTestViewModel.progressBar.postValue(true) trueHemeTestViewModel.progressBar.postValue(true)

View File

@@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M2.88,7.88l1.54,1.54C4.15,10.23 4,11.1 4,12c0,4.41 3.59,8 8,8s8,-3.59 8,-8s-3.59,-8 -8,-8c-0.9,0 -1.77,0.15 -2.58,0.42L7.89,2.89C9.15,2.32 10.54,2 12,2c5.52,0 10,4.48 10,10s-4.48,10 -10,10S2,17.52 2,12C2,10.53 2.32,9.14 2.88,7.88zM7,5.5C7,6.33 6.33,7 5.5,7S4,6.33 4,5.5S4.67,4 5.5,4S7,4.67 7,5.5zM12.03,8.99h-0.07l-1.16,3.31h2.39L12.03,8.99zM12,18c3.31,0 6,-2.69 6,-6s-2.69,-6 -6,-6s-6,2.69 -6,6S8.69,18 12,18zM11.29,7.5h1.43l3.01,8h-1.39l-0.72,-2.04h-3.23L9.66,15.5H8.28L11.29,7.5z"/>
</vector>

View File

@@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M13,3c-4.97,0 -9,4.03 -9,9L1,12l3.89,3.89 0.07,0.14L9,12L6,12c0,-3.87 3.13,-7 7,-7s7,3.13 7,7 -3.13,7 -7,7c-1.93,0 -3.68,-0.79 -4.94,-2.06l-1.42,1.42C8.27,19.99 10.51,21 13,21c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9zM12,8v5l4.28,2.54 0.72,-1.21 -3.5,-2.08L13.5,8L12,8z"/>
</vector>

View File

@@ -225,6 +225,19 @@
app:cornerRadius="16dp" app:cornerRadius="16dp"
/> />
<Button
android:id="@+id/btn_goback"
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="Go back"
android:textColor="@color/white"
app:cornerRadius="16dp"
/>
</LinearLayout> </LinearLayout>
<TextView <TextView

View File

@@ -10,7 +10,7 @@
android:id="@+id/searchBar" android:id="@+id/searchBar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:hint="Search by kitno or result" android:hint="Search by Sample ID or result"
android:imeOptions="actionSearch" android:imeOptions="actionSearch"
android:inputType="text" /> android:inputType="text" />

View File

@@ -307,5 +307,6 @@
<string name="calibrate_device">Calibrate the device</string> <string name="calibrate_device">Calibrate the device</string>
<string name="cuvette_presentt">Cuvette Present , Please Remove Cuvette And Try Again</string> <string name="cuvette_presentt">Cuvette Present , Please Remove Cuvette And Try Again</string>
<string name="cuvette_absentt">Cuvette Absent,Now You Can Submit</string> <string name="cuvette_absentt">Cuvette Absent,Now You Can Submit</string>
<string name="cuvette_presentnt">Test Done, Cuvette Present, Please Remove Cuvette And Goback</string>
</resources> </resources>

View File

@@ -306,7 +306,7 @@
<string name="calibrate_device">ಸಾಧನವನ್ನು ಮಾಪನಾಂಕ ಮಾಡಿ</string> <string name="calibrate_device">ಸಾಧನವನ್ನು ಮಾಪನಾಂಕ ಮಾಡಿ</string>
<string name="cuvette_presentt">Cuvette Present , Please Remove Cuvette And Try Again</string> <string name="cuvette_presentt">Cuvette Present , Please Remove Cuvette And Try Again</string>
<string name="cuvette_absentt">Cuvette Absent,Now You Can Submit</string> <string name="cuvette_absentt">Cuvette Absent,Now You Can Submit</string>
<string name="cuvette_presentnt">Test Done, Cuvette Present, Please Remove Cuvette And Goback</string>
<!-- Add translations for other strings --> <!-- Add translations for other strings -->
</resources> </resources>

View File

@@ -306,6 +306,7 @@
<string name="reset_password_for_this_device">Reset password for this device</string> <string name="reset_password_for_this_device">Reset password for this device</string>
<string name="calibrate_device">Calibrate Device</string> <string name="calibrate_device">Calibrate Device</string>
<string name="cuvette_presentt">Cuvette Present , Please Remove Cuvette And Try Again</string> <string name="cuvette_presentt">Cuvette Present , Please Remove Cuvette And Try Again</string>
<string name="cuvette_presentnt">Test Done, Cuvette Present, Please Remove Cuvette And Goback</string>
<string name="cuvette_absentt">Cuvette Absent,Now You Can Submit</string> <string name="cuvette_absentt">Cuvette Absent,Now You Can Submit</string>
</resources> </resources>