updated settings, and report gen

This commit is contained in:
Sathwik
2025-08-06 17:04:08 +05:30
parent 92f426d7be
commit dd887802bc
5 changed files with 100 additions and 17 deletions

View File

@@ -21,7 +21,7 @@ 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" versionName "2.1.133"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild { externalNativeBuild {

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
@@ -26,6 +29,7 @@ import android.widget.Toast
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.edit 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
@@ -42,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")
@@ -121,6 +130,7 @@ class PrefsFragment : PreferenceFragmentCompat() {
private lateinit var currentServerPreference: Preference private lateinit var currentServerPreference: Preference
lateinit var firebaseManager: FirebaseManager lateinit var firebaseManager: FirebaseManager
var autoSmbtValue = false var autoSmbtValue = false
var reportDisclaimerText = DEFAULT_DISCLAIMER
private var topDevMode = false private var topDevMode = false
lateinit var databaseRepository: DatabaseRepository lateinit var databaseRepository: DatabaseRepository
@@ -132,10 +142,11 @@ class PrefsFragment : PreferenceFragmentCompat() {
val sharedPreference = val sharedPreference =
requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE) requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
autoSmbtValue = sharedPreference.getBoolean("AutSmbt", false) 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 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"
@@ -202,6 +213,52 @@ 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 apps 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 { val autosmbt = SwitchPreferenceCompat(requireContext()).apply {
title = "Auto submit" title = "Auto submit"
summary = "Enable or disable Auto submit" summary = "Enable or disable Auto submit"
@@ -238,7 +295,9 @@ class PrefsFragment : PreferenceFragmentCompat() {
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(autosmbt)
preferenceScreen.addPreference(disclaimerPreference)
preferenceScreen.addPreference(resetDisclaimerPreference)
} }
if (preferenceScreen.findPreference<ListPreference>("server_preference") == null) { if (preferenceScreen.findPreference<ListPreference>("server_preference") == null) {
@@ -258,8 +317,11 @@ class PrefsFragment : PreferenceFragmentCompat() {
if (firebaseManager.getDevMode() && arWeAdmin) { 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(autosmbt)
preferenceScreen.addPreference(serverSelectorPreference) preferenceScreen.addPreference(serverSelectorPreference)
preferenceScreen.addPreference(autosmbt)
preferenceScreen.addPreference(resetDisclaimerPreference)
preferenceScreen.addPreference(disclaimerPreference)
} }
setPreferenceScreen(preferenceScreen) setPreferenceScreen(preferenceScreen)
@@ -269,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

@@ -30,7 +30,7 @@ object ReportGen {
private const val MARGIN_TOP = 80f private const val MARGIN_TOP = 80f
private const val MARGIN_BOTTOM = 80f private const val MARGIN_BOTTOM = 80f
fun generate(context: Context, dataList: List<HemoCubeTestData>) { fun generate(context: Context, dataList: List<HemoCubeTestData>,disclaimerText: String) {
if (dataList.isEmpty()) { if (dataList.isEmpty()) {
Toast.makeText(context, "No items selected for report generation", Toast.LENGTH_SHORT).show() Toast.makeText(context, "No items selected for report generation", Toast.LENGTH_SHORT).show()
return return
@@ -45,11 +45,11 @@ object ReportGen {
} }
Toast.makeText(context, message, Toast.LENGTH_SHORT).show() Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
val pdfFile = createProfessionalPdfReport(context, dataList) val pdfFile = createProfessionalPdfReport(context, dataList, disclaimerText)
previewPdf(context, pdfFile) previewPdf(context, pdfFile)
} }
private fun createProfessionalPdfReport(context: Context, dataList: List<HemoCubeTestData>): File { private fun createProfessionalPdfReport(context: Context, dataList: List<HemoCubeTestData>,disclaimerText : String): File {
val timestamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date()) val timestamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
val file = File(context.getExternalFilesDir(null), "HemoCube_Report_$timestamp.pdf") val file = File(context.getExternalFilesDir(null), "HemoCube_Report_$timestamp.pdf")
@@ -99,7 +99,7 @@ object ReportGen {
drawPage(canvas, testData, index + 1, dataList.size, drawPage(canvas, testData, index + 1, dataList.size,
headerPaint, titlePaint, sectionHeaderPaint, headerPaint, titlePaint, sectionHeaderPaint,
contentPaint, boldContentPaint, disclaimerPaint,context) contentPaint, boldContentPaint, disclaimerPaint,disclaimerText,context)
pdfDocument.finishPage(page) pdfDocument.finishPage(page)
} }
@@ -120,6 +120,7 @@ object ReportGen {
contentPaint: Paint, contentPaint: Paint,
boldContentPaint: Paint, boldContentPaint: Paint,
disclaimerPaint: Paint, disclaimerPaint: Paint,
disclaimerText: String,
context: Context context: Context
) { ) {
var currentY = MARGIN_TOP var currentY = MARGIN_TOP
@@ -165,7 +166,7 @@ object ReportGen {
currentY += 15f currentY += 15f
// Footer with page number and disclaimer // Footer with page number and disclaimer
drawFooter(canvas, pageNumber, totalPages, contentPaint, disclaimerPaint) drawFooter(canvas, pageNumber, totalPages, contentPaint, disclaimerPaint,disclaimerText)
} }
private fun drawHeader(canvas: Canvas, headerPaint: Paint, titlePaint: Paint, startY: Float, context: Context) { private fun drawHeader(canvas: Canvas, headerPaint: Paint, titlePaint: Paint, startY: Float, context: Context) {
@@ -256,17 +257,13 @@ object ReportGen {
return currentY return currentY
} }
private fun drawFooter(canvas: Canvas, pageNumber: Int, totalPages: Int, contentPaint: Paint, disclaimerPaint: Paint) { private fun drawFooter(canvas: Canvas, pageNumber: Int, totalPages: Int, contentPaint: Paint, disclaimerPaint: Paint,disclaimerText: String) {
val footerY = PAGE_HEIGHT - MARGIN_BOTTOM + 20f val footerY = PAGE_HEIGHT - MARGIN_BOTTOM + 20f
// Page number // Page number
canvas.drawText("Page $pageNumber of $totalPages", PAGE_WIDTH - MARGIN_RIGHT - 80f, footerY, contentPaint) canvas.drawText("Page $pageNumber of $totalPages", PAGE_WIDTH - MARGIN_RIGHT - 80f, footerY, contentPaint)
// Disclaimer // Disclaimer
val disclaimerText = "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."
val disclaimerLines = wrapText(disclaimerText, disclaimerPaint, PAGE_WIDTH - MARGIN_LEFT - MARGIN_RIGHT) val disclaimerLines = wrapText(disclaimerText, disclaimerPaint, PAGE_WIDTH - MARGIN_LEFT - MARGIN_RIGHT)
var disclaimerY = footerY + 20f var disclaimerY = footerY + 20f

View File

@@ -2,6 +2,7 @@ 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())
} }
} }
} }

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>