diff --git a/app/build.gradle b/app/build.gradle index 0eca9d0..35f690a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -55,12 +55,15 @@ android { } dependencies { + implementation "com.google.dagger:hilt-android:2.46" + kapt "com.google.dagger:hilt-android-compiler:2.46" implementation 'androidx.core:core-ktx:1.12.0' implementation 'androidx.appcompat:appcompat:1.6.1' - implementation 'com.google.android.material:material:1.9.0' + implementation 'com.google.android.material:material:1.10.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.2' + implementation 'androidx.fragment:fragment-ktx:1.6.2' //firebase implementation platform('com.google.firebase:firebase-bom:32.1.0') @@ -75,8 +78,10 @@ dependencies { implementation 'com.google.android.gms:play-services-location:21.0.1' implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1' implementation 'com.google.android.things:androidthings:1.0' - implementation 'com.google.firebase:firebase-appdistribution:16.0.0-beta10' - implementation("com.google.firebase:firebase-appdistribution-api-ktx:16.0.0-beta10") + implementation 'com.google.firebase:firebase-appdistribution:16.0.0-beta11' + implementation("com.google.firebase:firebase-appdistribution-api-ktx:16.0.0-beta11") + implementation 'androidx.preference:preference-ktx:1.2.1' + implementation 'androidx.preference:preference-ktx:1.2.1' // Testing @@ -88,14 +93,14 @@ dependencies { androidTestImplementation 'org.mockito:mockito-android:3.12.4' androidTestImplementation 'org.mockito:mockito-inline:3.12.4' testImplementation "androidx.arch.core:core-testing:2.2.0" - testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4' + testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.1' implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2" implementation 'com.opencsv:opencsv:4.6' implementation 'com.github.mik3y:usb-serial-for-android:3.5.1' - implementation "androidx.fragment:fragment-ktx:1.6.1" + implementation "androidx.fragment:fragment-ktx:1.6.2" // CSV read, write implementation 'com.opencsv:opencsv:4.6' @@ -107,22 +112,22 @@ dependencies { implementation 'com.google.android.gms:play-services-code-scanner:16.1.0' //Room - implementation "androidx.room:room-ktx:2.6.0-rc01" - implementation "androidx.room:room-runtime:2.6.0-rc01" - kapt ("androidx.room:room-compiler:2.6.0-rc01") + implementation "androidx.room:room-ktx:2.6.0" + implementation "androidx.room:room-runtime:2.6.0" + kapt ("androidx.room:room-compiler:2.6.0") //image implementation 'com.github.bumptech.glide:glide:4.13.2' annotationProcessor 'com.github.bumptech.glide:compiler:4.13.2' // Navigation Component - implementation "androidx.navigation:navigation-fragment-ktx:2.7.3" - implementation "androidx.navigation:navigation-ui-ktx:2.7.3" + implementation "androidx.navigation:navigation-fragment-ktx:2.7.5" + implementation "androidx.navigation:navigation-ui-ktx:2.7.5" //Dagger - Hilt implementation "com.google.dagger:hilt-android:2.46" kapt "com.google.dagger:hilt-android-compiler:2.46" - kapt "androidx.hilt:hilt-compiler:1.0.0" + kapt "androidx.hilt:hilt-compiler:1.1.0" // Retrofit + GSON implementation "com.squareup.retrofit2:retrofit:2.9.0" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c2f6365..61c85a5 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,8 +5,8 @@ - - @@ -32,6 +32,9 @@ android:supportsRtl="true" android:theme="@style/Theme.HPOSTesting" tools:targetApi="31"> + @@ -58,7 +61,8 @@ android:name="com.example.hpostesting.presentation.dashboard.DashboardActivity" android:exported="false" android:label="@string/title_activity_dashboard" - android:theme="@style/Theme.HPOS.NoActionBar" /> + android:theme="@style/Theme.HPOS.NoActionBar" + tools:ignore="MissingClass" /> if (result.contents.isNullOrEmpty()) { - Toast.makeText(this, "Cancelled: Unable to scan, Try Again!!", Toast.LENGTH_LONG).show() + Toast.makeText(this, R.string.cancelled_unable_scan, Toast.LENGTH_LONG).show() } else { Log.d(TAG, result.contents) processScannedData(result.contents) @@ -120,7 +120,7 @@ class KitScanActivity : AppCompatActivity() { } Toast.makeText( applicationContext, - "Kit number is updated, Please Select user before starting test", + R.string.kit_updated, Toast.LENGTH_SHORT ).show() @@ -138,9 +138,24 @@ class KitScanActivity : AppCompatActivity() { moveToNext() } } else { - Toast.makeText(this, "Invalid KIT Number", Toast.LENGTH_LONG).show() + Toast.makeText(this, R.string.invalid_kit_number, Toast.LENGTH_LONG).show() return@setOnClickListener } + if (serialNumber.isNotEmpty() && checkDataNotNull() && isSerialValid( + serialNumber + ) + ) { + DataHolder.kitSerial = binding.nameEditText.text.toString() + DataHolder.selectedTest?.kitSerial = binding.nameEditText.text.toString() + with(sharedPreference.edit()) { + putString(Constants.KIT_NUMBER, binding.nameEditText.text.toString()) + putInt(Constants.KIT_COUNT, 1) + apply() + } + moveToNext() + } else { + Toast.makeText(this, R.string.invalid_kit_number, Toast.LENGTH_LONG).show() + } } } @@ -195,7 +210,7 @@ class KitScanActivity : AppCompatActivity() { private fun checkDataNotNull(): Boolean { return if (DataHolder.selectedTest?._id == null) { Toast.makeText( - applicationContext, "Please Select patient before starting test", Toast.LENGTH_SHORT + applicationContext, R.string.select_patient, Toast.LENGTH_SHORT ).show() val i = Intent(applicationContext, DashboardActivity::class.java) diff --git a/app/src/main/java/com/example/hpostesting/presentation/MainActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/MainActivity.kt index dd5d0f6..1381a56 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/MainActivity.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/MainActivity.kt @@ -1,5 +1,6 @@ package com.example.hpostesting.presentation +import com.example.hpostesting.presentation.dashboard.DashboardActivity import android.Manifest import android.content.* import android.content.pm.PackageManager @@ -9,8 +10,6 @@ import android.os.Bundle import android.util.Log import android.view.Menu import android.view.View -import android.view.ViewGroup -import android.widget.Button import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat @@ -20,7 +19,6 @@ import com.example.hpostesting.data.DataHolder import com.example.hpostesting.data.constant.Constants import com.example.hpostesting.data.model.patient.UserData import com.example.hpostesting.data.model.test.TestType -import com.example.hpostesting.presentation.dashboard.DashboardActivity import com.google.android.gms.location.* import com.google.android.material.snackbar.Snackbar import com.google.firebase.crashlytics.FirebaseCrashlytics @@ -138,7 +136,7 @@ class MainActivity : AppCompatActivity() { else -> { Log.d(TAG, "Device NOT Connected") - Toast.makeText(this, "Device Not Connected", Toast.LENGTH_SHORT).show() + Toast.makeText(this, R.string.device_not, Toast.LENGTH_SHORT).show() DataHolder.usbConnected.value = false null } @@ -226,7 +224,7 @@ class MainActivity : AppCompatActivity() { ) != PackageManager.PERMISSION_GRANTED ) { // Handle location permission request if needed - Toast.makeText(this, "Please enable location services", Toast.LENGTH_SHORT).show() + Toast.makeText(this, R.string.enable_location, Toast.LENGTH_SHORT).show() requestCoarseLocationPermission() requestFineLocationPermission() return @@ -313,7 +311,7 @@ class MainActivity : AppCompatActivity() { requestFineLocationPermission() } else { // Coarse location permission denied - Toast.makeText(this, "Coarse location permission denied", Toast.LENGTH_SHORT) + Toast.makeText(this, R.string.coarse_location_denied, Toast.LENGTH_SHORT) .show() } } @@ -324,7 +322,7 @@ class MainActivity : AppCompatActivity() { getLocation() } else { // Fine location permission denied - Toast.makeText(this, "Fine location permission denied", Toast.LENGTH_SHORT) + Toast.makeText(this, R.string.location_denied, Toast.LENGTH_SHORT) .show() } } diff --git a/app/src/main/java/com/example/hpostesting/presentation/SplashActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/SplashActivity.kt index 3623888..41d77ba 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/SplashActivity.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/SplashActivity.kt @@ -1,5 +1,6 @@ package com.example.hpostesting.presentation +import com.example.hpostesting.presentation.dashboard.DashboardActivity import android.Manifest import android.content.Intent import android.content.pm.PackageManager @@ -13,11 +14,8 @@ import androidx.annotation.RequiresApi import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat import com.example.hpostesting.data.DataHolder -import com.example.hpostesting.presentation.dashboard.DashboardActivity import com.example.hpostesting.util.MyUtils -import com.google.firebase.firestore.FirebaseFirestoreSettings -import com.google.firebase.firestore.ktx.firestore -import com.google.firebase.ktx.Firebase +import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.databinding.ActivitySplashBinding class SplashActivity : AppCompatActivity() { @@ -77,7 +75,7 @@ class SplashActivity : AppCompatActivity() { } else { Toast.makeText( this, - "You must grant permission to access all files to use the app", + R.string.permission_grant, Toast.LENGTH_SHORT ).show() finish() @@ -139,7 +137,7 @@ class SplashActivity : AppCompatActivity() { if (allGranted) { moveToLandingPage() } else { - Toast.makeText(this, "All permissions are required to use the app.", Toast.LENGTH_SHORT).show() + Toast.makeText(this, R.string.permission_required, Toast.LENGTH_SHORT).show() finish() } } diff --git a/app/src/main/java/com/example/hpostesting/presentation/adapter/OfflineUserListAdapter.kt b/app/src/main/java/com/example/hpostesting/presentation/adapter/OfflineUserListAdapter.kt index 6acd933..2a77c87 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/adapter/OfflineUserListAdapter.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/adapter/OfflineUserListAdapter.kt @@ -1,5 +1,6 @@ package com.example.hpostesting.presentation.adapter +import android.content.Context import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -14,11 +15,13 @@ import com.example.hpostesting.data.model.patient.HemoCubeTestData import com.example.hpostesting.data.model.patient.UserData import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.databinding.OfflineUserListViewBinding +import org.apache.commons.collections4.MapUtils.getString import java.text.SimpleDateFormat import java.util.Calendar import java.util.Date import java.util.Locale + class OfflineUserListAdapter(private val view: View, private val batLevel: Int) : RecyclerView.Adapter() { @@ -40,7 +43,7 @@ class OfflineUserListAdapter(private val view: View, private val batLevel: Int) } val differ = AsyncListDiffer(this, differCallback) - + private val context: Context? = null override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OfflineUserListViewHolder { return OfflineUserListViewHolder( OfflineUserListViewBinding.inflate(LayoutInflater.from(parent.context), parent, false) @@ -61,7 +64,7 @@ class OfflineUserListAdapter(private val view: View, private val batLevel: Int) if (batLevel < 40) { Toast.makeText( view.context, - "Battery level is low than 40%, please charge the device to continue testing", + context?.getString(R.string.low_battery_warning), Toast.LENGTH_SHORT ).show() return@setOnClickListener @@ -70,7 +73,7 @@ class OfflineUserListAdapter(private val view: View, private val batLevel: Int) if (userList.testStatus!!) { Toast.makeText( view.context, - "Test has been already conducted for this user", + context?.getString(R.string.test_already_conducted), Toast.LENGTH_SHORT ).show() } else { @@ -78,13 +81,13 @@ class OfflineUserListAdapter(private val view: View, private val batLevel: Int) if (isBetween15And30Minutes(userList.incubationTime) < Constants.INCUBATION_TIME_MIN) { Toast.makeText( view.context, - "Incubation has not completed 15 minutes", + context?.getString(R.string.incubation_not_completed), Toast.LENGTH_SHORT ).show() } else if (isBetween15And30Minutes(userList.incubationTime) > Constants.INCUBATION_TIME_MAX) { Toast.makeText( view.context, - "Incubation crossed 30 minutes, need to repeat the incubation", + context?.getString(R.string.incubation_crossed_30_minutes), Toast.LENGTH_SHORT ).show() } else { @@ -99,7 +102,7 @@ class OfflineUserListAdapter(private val view: View, private val batLevel: Int) } else { Toast.makeText( view.context, - "Incubation not started for this user", + context?.getString(R.string.incubation_not_started), Toast.LENGTH_SHORT ).show() } diff --git a/app/src/main/java/com/example/hpostesting/presentation/adapter/UserListAdapter.kt b/app/src/main/java/com/example/hpostesting/presentation/adapter/UserListAdapter.kt index cd52b4d..af1dc97 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/adapter/UserListAdapter.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/adapter/UserListAdapter.kt @@ -70,10 +70,10 @@ class UserListAdapter( Glide.with(view).load(model.userImageURL).into(userImage) if (model.testStatus!!) { - teststatus.text = "Test concluded" + teststatus.text = view.context.getString(R.string.test_concluded) } else { - teststatus.text = "Test is Pending" + teststatus.text = view.context.getString(R.string.test_pending) } holder.binding.btnBlood.setOnClickListener { @@ -101,12 +101,12 @@ class UserListAdapter( builder.setPositiveButton("OK") { dialog, which -> val bloodGroup = etBloodGroup.text.toString() if (bloodGroup.equals("Select Blood Group") || bloodGroup.isNullOrBlank()) { - etBloodGroup.error = "Please enter your blood group" - Toast.makeText( - context, - "Please enter your blood group", - Toast.LENGTH_SHORT - ).show() + if (view != null) { + etBloodGroup.error =view.context.getString(R.string.blood_group_error) + } + if (view != null) { + Toast.makeText(context, view.context.getString(R.string.blood_group_toast), Toast.LENGTH_SHORT).show() + } } else { // Check if hemoCubeViewModel and testDetails are not null val db: FirebaseFirestore = FirebaseFirestore.getInstance() @@ -125,27 +125,33 @@ class UserListAdapter( ).format(Calendar.getInstance().time).toString() ) .addOnSuccessListener { - Toast.makeText( - context, - "Blood group updated successfully", - Toast.LENGTH_SHORT - ).show() + if (view != null) { + Toast.makeText( + view.context, + context?.getString(R.string.blood_group_updated_successfully), + Toast.LENGTH_SHORT + ).show() + } btnBlood.visibility = View.GONE } .addOnFailureListener { e -> - Toast.makeText( - context, - "Failed to update blood group: ${e.message}", - Toast.LENGTH_SHORT - ).show() + if (view != null) { + Toast.makeText( + view.context, + context?.getString(R.string.failed_to_update_blood_group), + Toast.LENGTH_SHORT + ).show() + } } } catch (e: IndexOutOfBoundsException) { // Handle the case where no documents are found for the specified ID - Toast.makeText( - context, - "No user data found for the specified ID", - Toast.LENGTH_SHORT - ).show() + if (view != null) { + Toast.makeText( + view.context, + context?.getString(R.string.no_user_data_found), + Toast.LENGTH_SHORT + ).show() + } } } @@ -193,7 +199,7 @@ class UserListAdapter( if (batLevel < 40) { Toast.makeText( view.context, - "Battery level is low than 40%, please charge the device to continue testing", + context?.getString(R.string.low_battery_warning), Toast.LENGTH_SHORT ).show() return@setOnClickListener @@ -202,7 +208,7 @@ class UserListAdapter( if (model.testStatus!!) { Toast.makeText( view.context, - "Test has been already conducted for this user", + context?.getString(R.string.test_already_conducted), Toast.LENGTH_SHORT ).show() } else { @@ -210,13 +216,13 @@ class UserListAdapter( if (isBetween15And30Minutes(model.incubationTime) < 15) { Toast.makeText( view.context, - "Incubation has not completed 15 minutes", + context?.getString(R.string.incubation_not_completed), Toast.LENGTH_SHORT ).show() } else if (isBetween15And30Minutes(model.incubationTime) > 30) { Toast.makeText( view.context, - "Incubation crossed 30 minutes, need to repeat the incubation", + context?.getString(R.string.incubation_crossed_30_minutes), Toast.LENGTH_SHORT ).show() } else { @@ -227,7 +233,7 @@ class UserListAdapter( } else { Toast.makeText( view.context, - "Incubation not started for this user", + context?.getString(R.string.incubation_not_started), Toast.LENGTH_SHORT ).show() } diff --git a/app/src/main/java/com/example/hpostesting/presentation/buffercheck/HemoCubeBufferCheckFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/buffercheck/HemoCubeBufferCheckFragment.kt index deb77e1..96ace8c 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/buffercheck/HemoCubeBufferCheckFragment.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/buffercheck/HemoCubeBufferCheckFragment.kt @@ -20,7 +20,6 @@ import com.example.hpostesting.data.model.patient.BufferCheckData 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.dashboard.DashboardActivity import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel import com.example.hpostesting.presentation.utils.MyDialogListener import com.example.hpostesting.presentation.utils.UIUtils @@ -73,7 +72,7 @@ class HemoCubeBufferCheckFragment : Fragment() { listenToHemoCube() startBufferProcess() } else { - Toast.makeText(context, "Invalid KIT Number", Toast.LENGTH_LONG).show() + Toast.makeText(context, R.string.invalid_kit_number, Toast.LENGTH_LONG).show() return@setOnClickListener } activity?.runOnUiThread { @@ -108,17 +107,17 @@ class HemoCubeBufferCheckFragment : Fragment() { hemoCubeViewModel.getDeviceData(sharedPreferences.getString(Constants.USER_ID, "")) } else { Toast.makeText( - requireContext(), "No internet connection avaiable", Toast.LENGTH_SHORT + requireContext(), R.string.internt_not, Toast.LENGTH_SHORT ).show() } isOnline = isNetworkAvailable } hemoCubeViewModel.fireBaseUpload.observe(viewLifecycleOwner) { result -> if (result == "Success") { - showToast("Kit result uploaded successfully") + showToast(R.string.kit_uploaded) } if (result == "Local") { - showToast("Kit result uploading failed, note it down manually") + showToast(R.string.kit_upload_failed) } binding.progressBar.visibility = View.GONE @@ -152,7 +151,7 @@ class HemoCubeBufferCheckFragment : Fragment() { } }) } catch (e: Exception) { - showToast("test is going on") + showToast(R.string.test_ongoing) Firebase.crashlytics.recordException(e) } } @@ -270,17 +269,18 @@ class HemoCubeBufferCheckFragment : Fragment() { return "NULL" } } catch (e: Exception) { - showToast("error while performing classification") + showToast(R.string.error_classification) Firebase.crashlytics.recordException(e) return "ERROR" } return "NULL" } - private fun showToast(message: String) { - Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show() + private fun showToast(messageResId: Int) { + Toast.makeText(requireContext(), getString(messageResId), Toast.LENGTH_SHORT).show() } + private fun startBufferProcess() { (activity as HemocubeBufferCheckActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.startBuffer, diff --git a/app/src/main/java/com/example/hpostesting/presentation/buffercheck/HemocubeBufferCheckActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/buffercheck/HemocubeBufferCheckActivity.kt index 6375d39..4f1a692 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/buffercheck/HemocubeBufferCheckActivity.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/buffercheck/HemocubeBufferCheckActivity.kt @@ -92,7 +92,7 @@ open class HemocubeBufferCheckActivity : AppCompatActivity() { } 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() + Toast.makeText(this, R.string.device_disconnected, Toast.LENGTH_SHORT).show() } } } @@ -103,7 +103,7 @@ open class HemocubeBufferCheckActivity : AppCompatActivity() { val availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager) if (availableDrivers.isEmpty()) { - Toast.makeText(this, "No device found", Toast.LENGTH_SHORT).show() + Toast.makeText(this, R.string.no_device_found, Toast.LENGTH_SHORT).show() } else { mDriver = availableDrivers[0] mConnection = manager.openDevice(mDriver.device) diff --git a/app/src/main/java/com/example/hpostesting/presentation/dashboard/DashboardActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/dashboard/DashboardActivity.kt index 02b1df6..82b5602 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/dashboard/DashboardActivity.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/dashboard/DashboardActivity.kt @@ -10,13 +10,11 @@ import androidx.navigation.ui.AppBarConfiguration import androidx.navigation.ui.navigateUp import androidx.navigation.ui.setupActionBarWithNavController import androidx.navigation.ui.setupWithNavController +import com.example.hpostesting.presentation.dashboard.SlideshowSettingsFragment import com.google.android.material.navigation.NavigationView import com.google.firebase.appdistribution.FirebaseAppDistribution import com.google.firebase.appdistribution.FirebaseAppDistributionException import com.google.firebase.crashlytics.FirebaseCrashlytics -import com.google.firebase.crashlytics.ktx.crashlytics -//import com.google.firebase.appdistribution.FirebaseAppDistribution -//import com.google.firebase.appdistribution.FirebaseAppDistributionException import dagger.hilt.android.AndroidEntryPoint import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.databinding.ActivityDashboardBinding @@ -46,10 +44,22 @@ class DashboardActivity : AppCompatActivity() { setupActionBarWithNavController(navController, appBarConfiguration) navView.setupWithNavController(navController) + // Handle navigation item clicks + navView.setNavigationItemSelectedListener { menuItem -> + when (menuItem.itemId) { + R.id.nav_settings -> { + // Open the settings fragment + openSettings() + drawerLayout.closeDrawers() // Close the drawer after selecting an item + true + } + + else -> false + } + } } override fun onCreateOptionsMenu(menu: Menu): Boolean { - // Inflate the menu; this adds items to the action bar if it is present. menuInflater.inflate(R.menu.dashboard, menu) return true } @@ -59,6 +69,13 @@ class DashboardActivity : AppCompatActivity() { return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp() } + // Add this function to open the settings fragment + private fun openSettings() { + supportFragmentManager.beginTransaction() + .replace(R.id.nav_host_fragment_content_dashboard, SlideshowSettingsFragment()) + .addToBackStack(null) + .commit() + } override fun onResume() { super.onResume() diff --git a/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt index 93f7414..d74f22d 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt @@ -108,12 +108,12 @@ class HomeFragment : Fragment() { if (result == "Success") { Toast.makeText( requireContext(), - "Test Results Uploaded Successfully", + R.string.test_upload, Toast.LENGTH_SHORT ).show() } if (result == "Error") { - Toast.makeText(requireContext(), "Test Results Upload Failed", Toast.LENGTH_SHORT) + Toast.makeText(requireContext(), R.string.test_upload_failed, Toast.LENGTH_SHORT) .show() } } @@ -162,10 +162,10 @@ class HomeFragment : Fragment() { val dateFormat = SimpleDateFormat("yyyy-MM-dd") val currentDate = Date() val formattedDate = dateFormat.format(currentDate) - val query = Firebase.firestore.collection("patientData") - .whereGreaterThanOrEqualTo("createdAt", formattedDate) - .orderBy("createdAt", Query.Direction.DESCENDING) -// val query = Firebase.firestore.collection("patientData").whereEqualTo("testStatus", false) +// val query = Firebase.firestore.collection("patientData") +// .whereGreaterThanOrEqualTo("createdAt", formattedDate) +// .orderBy("createdAt", Query.Direction.DESCENDING) + val query = Firebase.firestore.collection("patientData").whereEqualTo("testStatus", false) query.get().addOnSuccessListener { if (it.documents.isEmpty()) { binding.pendingTest.visibility = View.VISIBLE @@ -203,14 +203,14 @@ class HomeFragment : Fragment() { private fun logoutUser(context: Context) { val builder = AlertDialog.Builder(context) - builder.setTitle("Log Out") - builder.setMessage("Do you want to LogOut the Application?") - builder.setPositiveButton("Yes") { dialog, _ -> + builder.setTitle(R.string.log_out) + builder.setMessage(R.string.do_log_out) + builder.setPositiveButton(R.string.yes) { dialog, _ -> saveUserId("") findNavController().navigate(R.id.action_nav_home_to_loginFragment) dialog.dismiss() } - builder.setNegativeButton("No") { dialog, _ -> + builder.setNegativeButton(R.string.no) { dialog, _ -> dialog.dismiss() } diff --git a/app/src/main/java/com/example/hpostesting/presentation/dashboard/SlideshowFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/dashboard/SlideshowFragment.kt index d62d53b..31dce7d 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/dashboard/SlideshowFragment.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/dashboard/SlideshowFragment.kt @@ -1,44 +1,40 @@ package com.example.hpostesting.presentation.dashboard +import android.content.Context +import android.content.ContextWrapper +import android.content.SharedPreferences +import android.content.res.Configuration import android.os.Bundle +import android.preference.PreferenceManager import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.FrameLayout import androidx.fragment.app.Fragment -import androidx.lifecycle.ViewModelProvider -import com.example.hpostesting.presentation.dashboard.ui.slideshow.SlideshowViewModel +import androidx.preference.PreferenceFragmentCompat +import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.databinding.FragmentSlideshowBinding - +import java.util.Locale class SlideshowFragment : Fragment() { - private var _binding: FragmentSlideshowBinding? = null - - // This property is only valid between onCreateView and - // onDestroyView. private val binding get() = _binding!! - override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle?, + savedInstanceState: Bundle? ): View { - val slideshowViewModel = - ViewModelProvider(this).get(SlideshowViewModel::class.java) + val root = inflater.inflate(R.layout.fragment_slideshow, container, false) - _binding = FragmentSlideshowBinding.inflate(inflater, container, false) - val root: View = binding.root + // Find the FrameLayout and add the PreferenceFragmentCompat dynamically + val fragmentContainer = root.findViewById(R.id.fragment_container) + val settingsFragment = SlideshowSettingsFragment() + childFragmentManager.beginTransaction() + .replace(fragmentContainer.id, settingsFragment) + .commit() - val pInfo = requireActivity().packageManager.getPackageInfo( - requireActivity().packageName, 0 - ) - val version = pInfo.versionName - binding.textSlideshow.text = version + // Handle language selection logic if needed -// val textView: TextView = binding.textSlideshow -// slideshowViewModel.text.observe(viewLifecycleOwner) { -// textView.text = it -// } return root } @@ -46,4 +42,92 @@ class SlideshowFragment : Fragment() { super.onDestroyView() _binding = null } +} + +class SlideshowSettingsFragment : PreferenceFragmentCompat() { + + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + setPreferencesFromResource(R.xml.settings, rootKey) + + val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext()) + sharedPreferences.registerOnSharedPreferenceChangeListener { _, key -> + if (key == "language_preference") { + val selectedLanguage = sharedPreferences.getString(key, "en") + if (selectedLanguage != null) { + setLocale(selectedLanguage) + } + restartActivity() + } + } + } + + private fun setLocale(languageCode: String) { + val newContext = LanguageHelper.wrap(requireContext(), languageCode) + LanguagePreference.setLanguage(newContext, languageCode) + + // Set the locale for the entire app, not just the context + val resources = newContext.resources + val configuration = resources.configuration + configuration.setLocale(Locale(languageCode)) + resources.updateConfiguration(configuration, resources.displayMetrics) + + requireActivity().recreate() // Restart the activity to apply language changes + } + + private fun restartActivity() { + requireActivity().recreate() + } + + override fun onDestroy() { + super.onDestroy() + val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext()) + sharedPreferences.unregisterOnSharedPreferenceChangeListener { _, _ -> } + } +} + +class LanguageHelper(base: Context) : ContextWrapper(base) { + + companion object { + fun wrap(context: Context, language: String): ContextWrapper { + var newContext = context + + val config = Configuration(context.resources.configuration) + val locale = Locale(language) + Locale.setDefault(locale) + config.setLocale(locale) + + newContext = context.createConfigurationContext(config) + + return LanguageHelper(newContext) + } + + fun updateBaseContextLocale(context: Context, language: String): Context { + val config = Configuration(context.resources.configuration) + val locale = Locale(language) + Locale.setDefault(locale) + config.setLocale(locale) + + return context.createConfigurationContext(config) + } + } +} + +class LanguagePreference(context: Context) { + + private val preferences: SharedPreferences = context.getSharedPreferences("LanguagePrefs", Context.MODE_PRIVATE) + + companion object { + private const val SELECTED_LANGUAGE = "selectedLanguage" + + fun getLanguage(context: Context): String? { + val preferences = context.getSharedPreferences("LanguagePrefs", Context.MODE_PRIVATE) + return preferences.getString(SELECTED_LANGUAGE, null) + } + + fun setLanguage(context: Context, language: String) { + val editor = context.getSharedPreferences("LanguagePrefs", Context.MODE_PRIVATE).edit() + editor.putString(SELECTED_LANGUAGE, language) + editor.apply() + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/presentation/dashboard/ui/LoginFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/dashboard/ui/LoginFragment.kt index 39fecbe..cb74fd0 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/dashboard/ui/LoginFragment.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/dashboard/ui/LoginFragment.kt @@ -47,10 +47,10 @@ class LoginFragment : Fragment() { performLogin(loginId, password) } else { if (loginId.isBlank()) { - binding.loginId.error = "Please enter a proper Login ID" + binding.loginId.error = R.string.enter_proper_login_id.toString() } if (password.isBlank()) { - binding.password.error = "Please enter a proper password" + binding.password.error = R.string.enter_proper_password.toString() } } } @@ -72,10 +72,10 @@ class LoginFragment : Fragment() { navigateToHomeFragment() return } else { - Toast.makeText(requireContext(), "Wrong Password", Toast.LENGTH_SHORT).show() + Toast.makeText(requireContext(), R.string.wrong_password, Toast.LENGTH_SHORT).show() } } - Toast.makeText(requireContext(), "Wrong UserID", Toast.LENGTH_SHORT).show() + Toast.makeText(requireContext(), R.string.wrong_user_id, Toast.LENGTH_SHORT).show() } private fun saveUserId(userId: String) { diff --git a/app/src/main/java/com/example/hpostesting/presentation/hemocube/DigitalCardActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/hemocube/DigitalCardActivity.kt new file mode 100644 index 0000000..95c08d1 --- /dev/null +++ b/app/src/main/java/com/example/hpostesting/presentation/hemocube/DigitalCardActivity.kt @@ -0,0 +1,39 @@ +package com.example.hpostesting.presentation.hemocube + +import android.content.BroadcastReceiver +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.ServiceConnection +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.view.Menu +import androidx.activity.viewModels +import com.example.hpostesting.data.DataHolder +import com.example.hpostesting.presentation.testRight.UsbService +import com.hoho.android.usbserial.driver.UsbSerialDriver +import `in`.sminnovations.hpostesting.R +import `in`.sminnovations.hpostesting.databinding.ActivityDigitalCardBinding +import `in`.sminnovations.hpostesting.databinding.ActivityHemocubeBinding + +class DigitalCardActivity : AppCompatActivity() { + private lateinit var binding: ActivityDigitalCardBinding + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityDigitalCardBinding.inflate(layoutInflater) + setContentView(binding.root) + moveToNext() + } + + + private fun moveToNext() { + if (supportFragmentManager.isDestroyed) return + supportFragmentManager.beginTransaction().replace(binding.fghemocube.id, DigitalCardFragment()) + .commit() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/presentation/hemocube/DigitalCardFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/hemocube/DigitalCardFragment.kt new file mode 100644 index 0000000..f72c826 --- /dev/null +++ b/app/src/main/java/com/example/hpostesting/presentation/hemocube/DigitalCardFragment.kt @@ -0,0 +1,83 @@ +package com.example.hpostesting.presentation.hemocube + +import android.annotation.SuppressLint +import android.content.Context +import android.content.SharedPreferences +import android.os.Bundle +import android.util.Log +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.activityViewModels +import com.example.hpostesting.data.DataHolder +import com.example.hpostesting.data.model.patient.toHemoCubeTestData +import `in`.sminnovations.hpostesting.R +import `in`.sminnovations.hpostesting.databinding.FragmentDigitalCardBinding +import `in`.sminnovations.hpostesting.databinding.FragmentHemoCubeReferenceBinding +import java.text.SimpleDateFormat +import java.util.Calendar +import java.util.Date +import java.util.Locale + +class DigitalCardFragment : Fragment() { + private lateinit var binding: FragmentDigitalCardBinding + private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels() + private lateinit var sharedPreferences: SharedPreferences + private val testDetails = DataHolder.selectedTest?.toHemoCubeTestData() + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?, + ): View { + binding = FragmentDigitalCardBinding.inflate(inflater, container, false) + sharedPreferences = + requireContext().getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + initViews() + } + + @SuppressLint("SetTextI18n") + private fun initViews() { + activity?.runOnUiThread { + binding.progressBar.visibility = View.VISIBLE + } + Log.d("DigitalCardFragment", "Name: ${DataHolder.hemoCubeTestData?.name}") + Log.d("DigitalCardFragment", "DOB: ${testDetails?.birthYear}") + Log.d("DigitalCardFragment", "Gender: ${testDetails?.gender}") + Log.d("DigitalCardFragment", "State: ${testDetails?.state}") + Log.d("DigitalCardFragment", "ABHA ID: ${testDetails?.abhaId}") + Log.d("DigitalCardFragment", "Blood Group: ${testDetails?.bloodGroup}") + Log.d("DigitalCardFragment", "Sickle-Cell: ${testDetails?.classificationResult}") +// Log.d("DigitalCardFragment", "Issue Date: $formattedDate") + activity?.runOnUiThread { + binding.progressBar.visibility = View.GONE + binding.name.text = "Name: ${DataHolder.hemoCubeTestData?.name}" + binding.dob.text = "DOB: ${testDetails?.birthYear}" + binding.gender.text = "Gender: ${testDetails?.gender}" + binding.State.text = "State: ${testDetails?.state}" + binding.abhaid.text = "ABHA ID: ${testDetails?.abhaId}" + binding.blood.text = "Blood Group: ${testDetails?.bloodGroup}" + binding.sicklecell.text = "Sickle-Cell: ${DataHolder.hemoCubeTestData?.prdClassification.toString()}" + + } + // Update the UI with the fetched details + val originalDateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()) + val originalDate: Date? = originalDateFormat.parse(SimpleDateFormat( + "yyyy-MM-dd HH:mm:ss", Locale.getDefault() + ).format(Calendar.getInstance().time)) + +// Format the parsed date to "mm date, year" + val desiredDateFormat = SimpleDateFormat("MMM dd, yyyy", Locale.getDefault()) + val formattedDate: String = originalDate?.let { desiredDateFormat.format(it) } ?: "N/A" + activity?.runOnUiThread { + binding.issueDate.text = "Issue Date: ${formattedDate}" + } + + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt index 5f0ab39..9bc21ea 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt @@ -1,5 +1,6 @@ package com.example.hpostesting.presentation.hemocube +import com.example.hpostesting.presentation.dashboard.DashboardActivity import android.content.Context import android.content.Intent import android.content.SharedPreferences @@ -18,7 +19,7 @@ import com.example.hpostesting.data.constant.HemoCubeCommands import com.example.hpostesting.data.model.patient.DeviceData import com.example.hpostesting.data.model.patient.toHemoCubeTestData import com.example.hpostesting.presentation.UsbServiceListener -import com.example.hpostesting.presentation.dashboard.DashboardActivity + import com.example.hpostesting.presentation.utils.MyDialogListener import com.example.hpostesting.presentation.utils.UIUtils import com.google.firebase.crashlytics.ktx.crashlytics @@ -90,8 +91,8 @@ class HemoCubeFragment : Fragment() { binding.nameEditText.visibility = View.GONE binding.tvTitle.visibility = View.GONE binding.btnGo.visibility = View.GONE - binding.btnSubmit.isEnabled = false - binding.btnSubmit.isClickable = false +// binding.btnSubmit.isEnabled = false +// binding.btnSubmit.isClickable = false binding.btnPlacebuffer.visibility = View.GONE binding.tvName.text = "Name: ${testDetails?.name}\n ID: ${testDetails?._id}" @@ -126,19 +127,25 @@ class HemoCubeFragment : Fragment() { private fun observeViewModel() { hemoCubeViewModel.fireBaseUpload.observe(viewLifecycleOwner) { result -> if (result == "Success") { - showToast("Test Results Uploaded Successfully") - val i = Intent( - requireContext().applicationContext, DashboardActivity::class.java - ) - startActivity(i) - (activity as HemocubeActivity).finish() + showToast(R.string.test_upload) + + activity?.runOnUiThread { + binding.btnSubmit.visibility = View.GONE + binding.btnDigitalCard.visibility = View.VISIBLE + binding.btnDigitalCard.setOnClickListener { + val i = Intent( + requireContext().applicationContext, DigitalCardActivity::class.java + ) + startActivity(i) + } + } } if (result == "Local") { - showToast("Internet not available, test details stored locally") + showToast(R.string.internt_not_local) startActivity(Intent(requireActivity(), DashboardActivity::class.java)) } if (result == "Error") { - showToast("Error uploading data, test details stored locally") + showToast(R.string.error_local) startActivity(Intent(requireActivity(), DashboardActivity::class.java)) } @@ -199,16 +206,16 @@ class HemoCubeFragment : Fragment() { false } } catch (e: Exception) { - showToast("error while getting existing buffer") + showToast(R.string.error_exist) false } } private fun showBufferAlertDialog() { val title = "WARNING" - val message = "Do you want to continue with existing buffer?" + val message = getString(R.string.do_exist) val negativeText = getString(R.string.no) - val positiveText = "Yes" + val positiveText = getString(R.string.yes) UIUtils.createAlertDialog(requireContext(), title, @@ -224,7 +231,7 @@ class HemoCubeFragment : Fragment() { activity?.runOnUiThread { binding.btnPlacebuffer.visibility = View.GONE binding.btnSamplestart.visibility = View.VISIBLE - binding.tvSubtitle4.text = "Place Sample" + binding.tvSubtitle4.text = R.string.place_sample.toString() } isUsingExistingBuffer = true } @@ -256,7 +263,7 @@ class HemoCubeFragment : Fragment() { } }) } catch (e: Exception) { - showToast("test is going on") + showToast(R.string.test_ongoing) Firebase.crashlytics.recordException(e) } } @@ -301,37 +308,36 @@ class HemoCubeFragment : Fragment() { activity?.runOnUiThread { binding.btnPlacebuffer.visibility = View.VISIBLE } - hemoCubeViewModel.messages.postValue("Start") + hemoCubeViewModel.messages.postValue(R.string.start.toString()) } stringData.contains("#BS") -> { - hemoCubeViewModel.messages.postValue("Buffer Started") + hemoCubeViewModel.messages.postValue(R.string.buffer_started.toString()) } stringData.contains("#BC") -> { activity?.runOnUiThread { - binding.tvSubtitle4.text = "Buffer Completed" + binding.tvSubtitle4.text = R.string.buffer_completed.toString() binding.btnSamplestart.visibility = View.VISIBLE } } stringData.contains("#SS") -> { activity?.runOnUiThread { - binding.tvSubtitle4.text = "Sample Started" + binding.tvSubtitle4.text = R.string.sample_started.toString() binding.btnSamplestart.visibility = View.GONE } } stringData.contains("#SC") -> { - hemoCubeViewModel.messages.postValue("Sample Completed \nGathering data") + hemoCubeViewModel.messages.postValue(R.string.sample_completed.toString() +"\n" + R.string.gathering_data.toString()) fetchResult() testingTrace.stop() } resultData.contains("REND") -> { hemoCubeViewModel.messages.postValue( - "Data collected \n" + - " Processing data" + R.string.data_collected_processing_data.toString() ) val resultLines = resultData.split("\\s+(?=LB|LS)".toRegex()) var bufferIntensity = resultLines[1].split(' ')[1].trim() @@ -395,7 +401,7 @@ class HemoCubeFragment : Fragment() { // 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("Test is ongoing. Cannot go back.") + showToast(R.string.test_go_noback) } else { // If the test is not ongoing, you can trigger the back action of the hosting activity activity?.onBackPressed() @@ -404,7 +410,7 @@ class HemoCubeFragment : Fragment() { private fun processResult() { try { - hemoCubeViewModel.messages.postValue("processing result") + hemoCubeViewModel.messages.postValue(R.string.processing_result.toString()) val deviceLog = resultData val pInfo = requireActivity().packageManager.getPackageInfo( @@ -426,7 +432,7 @@ class HemoCubeFragment : Fragment() { 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.text = R.string.error_improper_buffer_low.toString() binding.errorMessage.visibility = View.VISIBLE } } @@ -440,8 +446,10 @@ class HemoCubeFragment : Fragment() { allErrorMessages += "Error: Invalid Test. Improper buffer reading (high)" + "\n" activity?.runOnUiThread { binding.errorMessage.text = - "Error: Invalid Test. Improper buffer reading (high)" + R.string.error_improper_buffer_high.toString() binding.errorMessage.visibility = View.VISIBLE + binding.btnSubmit.isEnabled = true + binding.btnSubmit.isClickable = true } } @@ -467,7 +475,7 @@ class HemoCubeFragment : Fragment() { 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.text = R.string.error_invalid_test.toString() binding.errorMessage.visibility = View.VISIBLE } } @@ -475,7 +483,7 @@ class HemoCubeFragment : Fragment() { if (fittedAbs1 < 0 || fittedAbs2 < 0 || fittedAbs3 < 0 || fittedAbs4 < 0) { validationError = true activity?.runOnUiThread { - binding.errorMessage.text = "Error: Negative Abs. Retake Blank Reading" + binding.errorMessage.text = R.string.error_negative_abs.toString() binding.errorMessage.visibility = View.VISIBLE } } @@ -546,7 +554,7 @@ class HemoCubeFragment : Fragment() { } catch (e: Exception) { Toast.makeText( requireContext(), - "Error while processing device data", + R.string.error_processing_device_data, Toast.LENGTH_SHORT ).show() Firebase.crashlytics.recordException(e) @@ -558,28 +566,28 @@ class HemoCubeFragment : Fragment() { hemoCubeViewModel.messages.postValue("result classification") if (calculatedRatio != null) { if (calculatedRatio < 0.05) - return "Inconclusive. Very low Absorbance - Repeat test with Higher Blood Volume" + return R.string.error_repeat_test_higher_volume.toString() if (calculatedRatio in 0.05..0.155) - return "Normal" + return R.string.normal.toString() if (calculatedRatio in 0.155..0.175) - return "Negative Borderline. Repeat Test" + return R.string.negative_borderline.toString() if (calculatedRatio in 0.175..0.22) - return "Sickle Cell Trait" + return R.string.sickle_cell_trait.toString() if (calculatedRatio in 0.22..0.25) - return "Positive for Sickle Cell. HPLC for Confirmation" + return R.string.positive_for_sickle_cell.toString() if (calculatedRatio in 0.25..0.35) - return "Sickle Cell Disease" + return R.string.sickle_cell_disease.toString() if (calculatedRatio > 0.35) - return "Inconclusive. Repeat with test with lower volume of blood" + return R.string.error_repeat_test_lower_volume.toString() } else { - return "INVALID" + return R.string.invalid.toString() } } catch (e: Exception) { - showToast("error while performing classification") + showToast(R.string.error_classification) Firebase.crashlytics.recordException(e) - return "ERROR" + return R.string.error.toString() } - return "INVALID" + return R.string.invalid.toString() } private fun absorbanceBasedClassification(predictedDenovixRatio: Double?): String { @@ -587,28 +595,28 @@ class HemoCubeFragment : Fragment() { hemoCubeViewModel.messages.postValue("result classification") if (predictedDenovixRatio != null) { if (predictedDenovixRatio in 0.0..0.16) - return "Normal" + return R.string.normal.toString() if (predictedDenovixRatio in 0.16..0.165) - return "Negative Borderline" + return R.string.negative_borderline.toString() if (predictedDenovixRatio in 0.165..0.235) - return "Sickle Cell Trait" + return R.string.sickle_cell_trait.toString() if (predictedDenovixRatio in 0.235..0.24) - return "Positive Borderline" + return R.string.positive_borderline.toString() if (predictedDenovixRatio in 0.24..1.0) - return "Sickle Cell Disease" + return R.string.sickle_cell_disease.toString() } else { - return "INVALID" + return R.string.invalid.toString() } } catch (e: Exception) { - showToast("error while performing classification") + showToast(R.string.error_classification) Firebase.crashlytics.recordException(e) - return "ERROR" + return R.string.error.toString() } - return "INVALID" + return R.string.invalid.toString() } - private fun showToast(message: String) { - Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show() + private fun showToast(messageResId: Int) { + Toast.makeText(requireContext(), getString(messageResId), Toast.LENGTH_SHORT).show() } private fun startBufferProcess() { diff --git a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt index 4987d1e..b9af079 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt @@ -1,11 +1,13 @@ package com.example.hpostesting.presentation.hemocube +import android.app.Application import android.content.Context import android.content.Intent import android.content.IntentFilter import android.content.SharedPreferences import android.os.BatteryManager import android.util.Log +import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel @@ -37,230 +39,241 @@ class HemoCubeViewModel @Inject constructor( ) : ViewModel() { var isServiceConnected = false val progressBar = MutableLiveData(false) - val testDetails = DataHolder.selectedTest?.toHemoCubeTestData() - val messages = MutableLiveData() - private val sharedPreference: SharedPreferences = - context.getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE) + val testDetails = DataHolder.selectedTest?.toHemoCubeTestData() + val messages = MutableLiveData() + private val sharedPreference: SharedPreferences = + context.getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE) - // Get the device ID of the device you want to retrieve data for (e.g., the first device in the list) + // Get the device ID of the device you want to retrieve data for (e.g., the first device in the list) - private val _networkStatusLiveData = NetworkStatusLiveData(context) - val allUserData = hemoCubeDao.getAll() - val deviceData = MutableLiveData() - val networkStatusLiveData: LiveData - get() = _networkStatusLiveData - val fireBaseUpload = MutableLiveData() - val fireBaseBulkUpload = MutableLiveData() + private val _networkStatusLiveData = NetworkStatusLiveData(context) + val allUserData = hemoCubeDao.getAll() + val deviceData = MutableLiveData() + val networkStatusLiveData: LiveData + get() = _networkStatusLiveData + val fireBaseUpload = MutableLiveData() + val fireBaseBulkUpload = MutableLiveData() - 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 + private val batteryStatus: Intent? = + IntentFilter(Intent.ACTION_BATTERY_CHANGED).let { ifilter -> + context.registerReceiver(null, ifilter) } - 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") + 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}") } - } catch (e: Exception) { - Log.e("Testdb", "Upload failed: ${e.message}") } + + + fun uploadHemoCubeResultToDatabaseforbuffercheckN(bufferCheckData: BufferCheckData) = + viewModelScope.launch { + addResultTestToDbforbuffercheck(bufferCheckData) + } + + fun getDeviceData(deviceId: String?) = viewModelScope.launch { + deviceData.postValue(deviceId?.let { repository.getDeviceDataById(it) }) } - - - fun uploadHemoCubeResultToDatabaseforbuffercheckN(bufferCheckData: BufferCheckData) = - viewModelScope.launch { - addResultTestToDbforbuffercheck(bufferCheckData) - } - - fun getDeviceData(deviceId: String?) = viewModelScope.launch { - deviceData.postValue(deviceId?.let { repository.getDeviceDataById(it) }) - } - - private 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?.predictedDenovixRatio = DataHolder.hemoCubeTestData?.predictedDenovixRatio - testDetails?.calculatedRatio = DataHolder.hemoCubeTestData?.calculatedRatio - testDetails?.coefficients = DataHolder.hemoCubeTestData?.coefficients - testDetails?.classificationResult = DataHolder.hemoCubeTestData?.classificationResult!! - testDetails?.prdClassification = DataHolder.hemoCubeTestData?.prdClassification.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() - } - - 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 - hemoCubeDao.insertAll(testDetails) - } - - is Response.Error -> { - Log.e("Testdb", "Error uploading data to Firestore: $response") - fireBaseUpload.postValue("Error") - hemoCubeDao.insertAll(testDetails) - } - } - } catch (e: Exception) { - Log.e("Testdb", "Exception during data upload: ${e.message}") - fireBaseUpload.postValue("Error") - } - } - } - - - 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") - } - } - } - - fun bulkAddResultTestToDb(userData: HemoCubeTestData) { - viewModelScope.launch { - userData.reportUploadTime = SimpleDateFormat( + private 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) - when (repository.addTestToDatabase(userData)) { - is Response.Success -> { - fireBaseBulkUpload.postValue("Success") - updateLocalFlag(userData._id) - } + 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?.predictedDenovixRatio = DataHolder.hemoCubeTestData?.predictedDenovixRatio + testDetails?.calculatedRatio = DataHolder.hemoCubeTestData?.calculatedRatio + testDetails?.coefficients = DataHolder.hemoCubeTestData?.coefficients + testDetails?.classificationResult = DataHolder.hemoCubeTestData?.classificationResult!! + testDetails?.prdClassification = + DataHolder.hemoCubeTestData?.prdClassification.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() + } - else -> { - fireBaseBulkUpload.postValue("Error") + 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 + hemoCubeDao.insertAll(testDetails) + } + + is Response.Error -> { + Log.e("Testdb", "Error uploading data to Firestore: $response") + fireBaseUpload.postValue("Error") + hemoCubeDao.insertAll(testDetails) + } + } + } catch (e: Exception) { + Log.e("Testdb", "Exception during data upload: ${e.message}") + fireBaseUpload.postValue("Error") } } } - } - private fun updateLocalFlag(userId: String) = viewModelScope.launch { - hemoCubeDao.updateFieldById(id = userId, true) - } - fun addUser(userData: HemoCubeTestData) = viewModelScope.launch { - hemoCubeDao.insertAll(userData) - } + private fun addResultTestToDbforbuffercheck(bufferCheckData: BufferCheckData) { + viewModelScope.launch { + try { - fun deleteById(userId: String) = viewModelScope.launch { - hemoCubeDao.deleteById(id = userId) - } + when (val response = + repository.addTestToDatabaseforBufferCheck(bufferCheckData)) { + is Response.Success -> { + Log.i("Testdb", "Data uploaded to Firestore successfully") + fireBaseUpload.postValue("Success") + } - 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() + 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") + } + } } - return batteryPct - } + 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) + } - fun getBatteryTemperature(): Float? { - val batteryTemp: Float? = batteryStatus?.let { intent -> - val temperature = intent?.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0) ?: 0 - temperature.toFloat() / 10 + else -> { + fireBaseBulkUpload.postValue("Error") + } + } + } } - return batteryTemp + private fun updateLocalFlag(userId: String) = viewModelScope.launch { + hemoCubeDao.updateFieldById(id = userId, true) + } + + fun addUser(userData: HemoCubeTestData) = viewModelScope.launch { + hemoCubeDao.insertAll(userData) + } + + fun deleteById(userId: String) = viewModelScope.launch { + hemoCubeDao.deleteById(id = userId) + } + + 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) ?: 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 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 - } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightResults.kt b/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightResults.kt index a225428..f6bed53 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightResults.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightResults.kt @@ -1,5 +1,6 @@ package com.example.hpostesting.presentation.testRight +import com.example.hpostesting.presentation.dashboard.DashboardActivity import android.content.Context import android.content.Intent import android.content.SharedPreferences @@ -14,7 +15,6 @@ import com.example.hpostesting.data.DataHolder import com.example.hpostesting.data.constant.Constants import com.example.hpostesting.data.model.test.TestRightResultType import com.example.hpostesting.data.model.test.TestType -import com.example.hpostesting.presentation.dashboard.DashboardActivity import com.example.hpostesting.util.MyUtils.calculateAgeFromYOB import com.google.firebase.firestore.FirebaseFirestore import com.google.firebase.firestore.ktx.firestore diff --git a/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightViewModel.kt b/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightViewModel.kt index 636f8b3..baf2b05 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightViewModel.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightViewModel.kt @@ -2,7 +2,6 @@ package com.example.hpostesting.presentation.testRight import android.content.Context import android.net.Uri -import android.util.Log import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel diff --git a/app/src/main/res/drawable/indianoil.jpg b/app/src/main/res/drawable/indianoil.jpg new file mode 100644 index 0000000..3f6e528 Binary files /dev/null and b/app/src/main/res/drawable/indianoil.jpg differ diff --git a/app/src/main/res/drawable/karnataka.png b/app/src/main/res/drawable/karnataka.png new file mode 100644 index 0000000..4d12e96 Binary files /dev/null and b/app/src/main/res/drawable/karnataka.png differ diff --git a/app/src/main/res/drawable/person.xml b/app/src/main/res/drawable/person.xml new file mode 100644 index 0000000..98730cd --- /dev/null +++ b/app/src/main/res/drawable/person.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/user.png b/app/src/main/res/drawable/user.png new file mode 100644 index 0000000..68711d0 Binary files /dev/null and b/app/src/main/res/drawable/user.png differ diff --git a/app/src/main/res/layout/activity_digital_card.xml b/app/src/main/res/layout/activity_digital_card.xml new file mode 100644 index 0000000..3e8cf38 --- /dev/null +++ b/app/src/main/res/layout/activity_digital_card.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_hemocube.xml b/app/src/main/res/layout/activity_hemocube.xml index a91259a..2d0b501 100644 --- a/app/src/main/res/layout/activity_hemocube.xml +++ b/app/src/main/res/layout/activity_hemocube.xml @@ -1,10 +1,8 @@ - - + app:layout_constraintTop_toTopOf="parent" /> - - - - - - \ No newline at end of file + + diff --git a/app/src/main/res/layout/content_dashboard.xml b/app/src/main/res/layout/content_dashboard.xml index 02c00de..27f66f1 100644 --- a/app/src/main/res/layout/content_dashboard.xml +++ b/app/src/main/res/layout/content_dashboard.xml @@ -18,4 +18,6 @@ app:layout_constraintTop_toTopOf="parent" app:navGraph="@navigation/dashboard_navigation" /> + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_digital_card.xml b/app/src/main/res/layout/fragment_digital_card.xml new file mode 100644 index 0000000..7259d46 --- /dev/null +++ b/app/src/main/res/layout/fragment_digital_card.xml @@ -0,0 +1,242 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +