UI changes

This commit is contained in:
SaiD 2025-11-26 07:22:07 +05:30
parent 6de6ef8bf8
commit 7f24f1cae1
26 changed files with 1656 additions and 332 deletions

8
.idea/markdown.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MarkdownSettings">
<option name="previewPanelProviderInfo">
<ProviderInfo name="Compose (experimental)" className="com.intellij.markdown.compose.preview.ComposePanelProvider" />
</option>
</component>
</project>

View File

@ -45,6 +45,7 @@ dependencies {
val cameraxVersion = "1.5.1"
implementation("androidx.appcompat:appcompat:1.7.0")
implementation("androidx.cardview:cardview:1.0.0")
implementation("com.google.android.material:material:1.12.0")
implementation("androidx.camera:camera-core:$cameraxVersion")
implementation("androidx.camera:camera-camera2:$cameraxVersion")
implementation("androidx.camera:camera-lifecycle:$cameraxVersion")

View File

@ -4,6 +4,9 @@
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage" />
<application
android:allowBackup="true"
@ -13,7 +16,8 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AnimalRating">
android:theme="@style/Theme.AnimalRating"
android:requestLegacyExternalStorage="true">
<activity
android:name=".HomeActivity"

View File

@ -25,6 +25,7 @@ import androidx.camera.view.PreviewView
import androidx.core.content.ContextCompat
import com.example.animalrating.ml.CowAnalyzer
import com.example.animalrating.ui.SilhouetteOverlay
import com.google.android.material.button.MaterialButton
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
@ -73,6 +74,10 @@ class CameraProcessor : AppCompatActivity(), CowAnalyzer.CowListener {
segmentationOverlay = findViewById(R.id.segmentationOverlay)
savedMaskOverlay = findViewById(R.id.savedMaskOverlay)
findViewById<MaterialButton>(R.id.btnExit).setOnClickListener {
finish()
}
frameProcessor = FrameProcessor()
val silhouetteId = intent.getIntExtra("SILHOUETTE_ID", 0)

View File

@ -1,18 +1,30 @@
package com.example.animalrating
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Color
import android.os.Bundle
import android.view.View
import android.widget.ArrayAdapter
import android.widget.AutoCompleteTextView
import android.widget.Button
import android.widget.GridLayout
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.RadioButton
import android.widget.RadioGroup
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.google.android.material.textfield.TextInputEditText
import com.google.android.material.textfield.TextInputLayout
import java.io.File
import java.io.FileOutputStream
import java.io.FileWriter
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
@ -21,12 +33,57 @@ class CowSelectionActivity : AppCompatActivity() {
private var currentCowName: String? = null
private lateinit var imagesContainer: LinearLayout
private val storagePermissionCode = 101
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_cow_selection)
// Initialize StringProvider
StringProvider.initialize(this)
// Set UI text from StringProvider
findViewById<TextView>(R.id.tvToolbarTitle)?.text = StringProvider.getString("title_cow_selection")
findViewById<TextView>(R.id.tvAddCowDetails)?.text = StringProvider.getString("title_add_cow_details")
findViewById<TextInputLayout>(R.id.tilSpecies)?.hint = StringProvider.getString("hint_species")
findViewById<TextInputLayout>(R.id.tilBreed)?.hint = StringProvider.getString("hint_breed")
findViewById<TextInputLayout>(R.id.tilAge)?.hint = StringProvider.getString("hint_age")
findViewById<TextInputLayout>(R.id.tilMilk)?.hint = StringProvider.getString("hint_milk_yield")
findViewById<TextInputLayout>(R.id.tilCalving)?.hint = StringProvider.getString("hint_calving_number")
findViewById<TextInputLayout>(R.id.tilDescription)?.hint = StringProvider.getString("hint_description")
findViewById<TextView>(R.id.tvReproductiveStatus)?.text = StringProvider.getString("label_reproductive_status")
findViewById<RadioButton>(R.id.rbPregnant)?.text = StringProvider.getString("radio_pregnant")
findViewById<RadioButton>(R.id.rbCalved)?.text = StringProvider.getString("radio_calved")
findViewById<RadioButton>(R.id.rbNone)?.text = StringProvider.getString("radio_none")
findViewById<TextView>(R.id.tvUploadPhotos)?.text = StringProvider.getString("label_upload_photos")
findViewById<Button>(R.id.btnNewCow)?.text = StringProvider.getString("btn_save_profile")
findViewById<Button>(R.id.btnCancel)?.text = StringProvider.getString("btn_cancel")
findViewById<TextView>(R.id.tvFrontView)?.text = StringProvider.getString("text_front_view")
findViewById<TextView>(R.id.tvRearView)?.text = StringProvider.getString("text_rear_view")
findViewById<TextView>(R.id.tvLeftSide)?.text = StringProvider.getString("text_left_side")
findViewById<TextView>(R.id.tvRightSide)?.text = StringProvider.getString("text_right_side")
findViewById<TextView>(R.id.tvAngleView)?.text = StringProvider.getString("text_angle_view")
// Setup Toolbar Navigation Click (Exit instead of Back)
val toolbar = findViewById<androidx.appcompat.widget.Toolbar>(R.id.toolbar)
setSupportActionBar(toolbar)
supportActionBar?.setDisplayShowTitleEnabled(false)
// NOTE: The navigation icon is set in XML (@drawable/ic_back_arrow).
// We handle the click here.
toolbar.setNavigationOnClickListener {
// Exit behavior: Finish this activity.
// If "Exit" means close app, use finishAffinity() but user likely means exit this screen.
// Given "except home activity", finish() goes back to home or previous screen.
finish()
}
initializeDefaultMasks()
setupDropdowns()
imagesContainer = findViewById(R.id.currentCowImagesContainer)
@ -37,26 +94,38 @@ class CowSelectionActivity : AppCompatActivity() {
generateNewCowName()
}
// Try to load existing data if we are editing an existing cow
if (intent.hasExtra("COW_NAME")) {
loadCowDetails(currentCowName!!)
}
updateCowNameDisplay()
refreshCowImages()
findViewById<Button>(R.id.btnNewCow).setOnClickListener {
generateNewCowName()
updateCowNameDisplay()
refreshCowImages()
if (checkStoragePermissions()) {
saveProfile()
} else {
requestStoragePermissions()
}
}
findViewById<Button>(R.id.btnCancel).setOnClickListener {
finish()
}
val buttons = mapOf(
R.id.btnLeft to Pair(R.drawable.left, "left"),
R.id.btnRight to Pair(R.drawable.right, "right"),
R.id.btnTop to Pair(R.drawable.angle, "angle"), // Placeholder if no image yet
R.id.btnTop to Pair(R.drawable.angle, "angle"),
R.id.btnFront to Pair(R.drawable.front, "front"),
R.id.btnBack to Pair(R.drawable.back, "back")
)
buttons.forEach { (btnId, pair) ->
val (drawableId, orientation) = pair
findViewById<Button>(btnId).setOnClickListener {
// Cast to View generic, as it is now a LinearLayout (clickable) in XML
findViewById<View>(btnId).setOnClickListener {
val intent = Intent(this, CameraProcessor::class.java)
intent.putExtra("SILHOUETTE_ID", drawableId)
intent.putExtra("COW_NAME", currentCowName)
@ -66,6 +135,208 @@ class CowSelectionActivity : AppCompatActivity() {
}
}
private fun checkStoragePermissions(): Boolean {
return if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
android.os.Environment.isExternalStorageManager()
} else {
val write = ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
val read = ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE)
write == PackageManager.PERMISSION_GRANTED && read == PackageManager.PERMISSION_GRANTED
}
}
private fun requestStoragePermissions() {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
try {
val intent = Intent(android.provider.Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
val uri = android.net.Uri.fromParts("package", packageName, null)
intent.data = uri
startActivity(intent)
} catch (_: Exception) {
val intent = Intent(android.provider.Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)
startActivity(intent)
}
} else {
ActivityCompat.requestPermissions(
this,
arrayOf(android.Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.READ_EXTERNAL_STORAGE),
storagePermissionCode
)
}
}
private fun saveProfile() {
// Get displayed values
val speciesDisplay = findViewById<AutoCompleteTextView>(R.id.spinnerSpecies).text.toString()
val breedDisplay = findViewById<AutoCompleteTextView>(R.id.spinnerBreed).text.toString()
// Convert to English for storage if needed (using reverse lookup or StringProvider helper)
// Assuming keys like "species_cow" map to "Cow" in English and something else in Hindi
// We try to find the key for the displayed value, then get the English value for that key.
// If not found (e.g. custom input), fallback to displayed value.
val speciesKey = StringProvider.getKeyForValue(speciesDisplay)
val species = if (speciesKey != null) StringProvider.getStringEnglish(speciesKey) else speciesDisplay
val breedKey = StringProvider.getKeyForValue(breedDisplay)
val breed = if (breedKey != null) StringProvider.getStringEnglish(breedKey) else breedDisplay
val ageInput = findViewById<TextInputEditText>(R.id.etAge).text.toString()
val milkInput = findViewById<TextInputLayout>(R.id.tilMilk).editText?.text.toString()
val calvingInput = findViewById<TextInputLayout>(R.id.tilCalving).editText?.text.toString()
val descriptionInput = findViewById<TextInputLayout>(R.id.tilDescription).editText?.text.toString()
val rgReproductive = findViewById<RadioGroup>(R.id.rgReproductiveStatus)
val reproductiveStatusKey = when(rgReproductive?.checkedRadioButtonId) {
R.id.rbPregnant -> "radio_pregnant"
R.id.rbCalved -> "radio_calved"
R.id.rbNone -> "radio_none"
else -> null
}
val reproductiveStatus = if (reproductiveStatusKey != null) StringProvider.getStringEnglish(reproductiveStatusKey) else ""
val csvHeader = "CowID,Species,Breed,Age,MilkYield,CalvingNumber,ReproductiveStatus,Description\n"
val csvRow = "$currentCowName,$species,$breed,$ageInput,$milkInput,$calvingInput,$reproductiveStatus,$descriptionInput\n"
val csvFile = File(filesDir, "cow_profiles.csv")
try {
val fileExists = csvFile.exists()
val lines = if (fileExists) csvFile.readLines().toMutableList() else mutableListOf()
if (!fileExists) {
lines.add(csvHeader.trim())
}
// Check if we are updating
val existingIndex = lines.indexOfFirst { it.startsWith("$currentCowName,") }
if (existingIndex != -1) {
lines[existingIndex] = csvRow.trim()
} else {
lines.add(csvRow.trim())
}
FileWriter(csvFile).use { writer ->
lines.forEach { line ->
writer.write(line + "\n")
}
}
// Also export to public storage if needed
saveCsvToPublicStorage(lines)
Toast.makeText(this, StringProvider.getString("toast_profile_saved"), Toast.LENGTH_SHORT).show()
finish()
} catch (e: Exception) {
e.printStackTrace()
Toast.makeText(this, StringProvider.getString("toast_error_saving_profile") + " ${e.message}", Toast.LENGTH_SHORT).show()
}
}
private fun saveCsvToPublicStorage(lines: List<String>) {
// Saving to public Documents folder
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
if (android.os.Environment.isExternalStorageManager()) {
val publicFile = File(android.os.Environment.getExternalStoragePublicDirectory(android.os.Environment.DIRECTORY_DOCUMENTS), "AnimalRating_Profiles.csv")
FileWriter(publicFile).use { writer ->
lines.forEach { line ->
writer.write(line + "\n")
}
}
}
} else {
val publicFile = File(android.os.Environment.getExternalStoragePublicDirectory(android.os.Environment.DIRECTORY_DOCUMENTS), "AnimalRating_Profiles.csv")
FileWriter(publicFile).use { writer ->
lines.forEach { line ->
writer.write(line + "\n")
}
}
}
}
private fun loadCowDetails(cowId: String) {
val csvFile = File(filesDir, "cow_profiles.csv")
if (!csvFile.exists()) return
try {
val lines = csvFile.readLines()
// Removed unused header variable
val record = lines.find { it.startsWith("$cowId,") }?.split(",") ?: return
// Simple mapping based on known order
// CowID,Species,Breed,Age,MilkYield,CalvingNumber,ReproductiveStatus,Description
if (record.size >= 8) {
// Data is stored in English. Find key for English value, then get display string for that key.
val storedSpecies = record[1]
val speciesKey = StringProvider.getKeyForEnglishValue(storedSpecies)
val displaySpecies = if (speciesKey != null) StringProvider.getString(speciesKey) else storedSpecies
findViewById<AutoCompleteTextView>(R.id.spinnerSpecies).setText(displaySpecies, false)
val storedBreed = record[2]
val breedKey = StringProvider.getKeyForEnglishValue(storedBreed)
val displayBreed = if (breedKey != null) StringProvider.getString(breedKey) else storedBreed
findViewById<AutoCompleteTextView>(R.id.spinnerBreed).setText(displayBreed, false)
findViewById<TextInputEditText>(R.id.etAge).setText(record[3])
findViewById<TextInputLayout>(R.id.tilMilk).editText?.setText(record[4])
findViewById<TextInputLayout>(R.id.tilCalving).editText?.setText(record[5])
val storedStatus = record[6]
// Find which key matches this English value
val statusKey = StringProvider.getKeyForEnglishValue(storedStatus)
// We need to check radio buttons.
// Radio buttons text is set from StringProvider in onCreate.
// So we need to find which RadioButton corresponds to 'statusKey'.
// "radio_pregnant" -> R.id.rbPregnant
// "radio_calved" -> R.id.rbCalved
// "radio_none" -> R.id.rbNone
when(statusKey) {
"radio_pregnant" -> findViewById<RadioButton>(R.id.rbPregnant).isChecked = true
"radio_calved" -> findViewById<RadioButton>(R.id.rbCalved).isChecked = true
"radio_none" -> findViewById<RadioButton>(R.id.rbNone).isChecked = true
// Fallback if stored directly as text or unknown key
else -> {
// If stored directly as English "Pregnant" etc.
when (storedStatus) {
"Pregnant" -> findViewById<RadioButton>(R.id.rbPregnant).isChecked = true
"Calved" -> findViewById<RadioButton>(R.id.rbCalved).isChecked = true
"None" -> findViewById<RadioButton>(R.id.rbNone).isChecked = true
}
}
}
findViewById<TextInputLayout>(R.id.tilDescription).editText?.setText(record[7])
}
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun setupDropdowns() {
val species = listOf(
StringProvider.getString("species_cow"),
StringProvider.getString("species_buffalo")
)
val speciesAdapter = ArrayAdapter(this, android.R.layout.simple_dropdown_item_1line, species)
findViewById<AutoCompleteTextView>(R.id.spinnerSpecies).setAdapter(speciesAdapter)
val breeds = listOf(
StringProvider.getString("breed_holstein"),
StringProvider.getString("breed_jersey"),
StringProvider.getString("breed_sahiwal"),
StringProvider.getString("breed_gir"),
StringProvider.getString("breed_red_sindhi"),
StringProvider.getString("breed_murrah"),
StringProvider.getString("breed_surti")
)
val breedAdapter = ArrayAdapter(this, android.R.layout.simple_dropdown_item_1line, breeds)
findViewById<AutoCompleteTextView>(R.id.spinnerBreed).setAdapter(breedAdapter)
}
override fun onResume() {
super.onResume()
refreshCowImages()
@ -124,7 +395,8 @@ class CowSelectionActivity : AppCompatActivity() {
}
private fun updateCowNameDisplay() {
findViewById<TextView>(R.id.tvCowName).text = "Current Cow: $currentCowName"
// Cow Name is now in Toolbar title if needed, but we hide title.
// findViewById<TextView>(R.id.tvCowName).text = "Current Cow: $currentCowName"
}
private fun refreshCowImages() {
@ -148,63 +420,61 @@ class CowSelectionActivity : AppCompatActivity() {
private fun addOrientationSection(orientationStr: String, files: List<File>) {
// Orientation Header
val orientationHeader = TextView(this).apply {
text = orientationStr.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }
val key = when(orientationStr.lowercase(Locale.getDefault())) {
"front" -> "text_front_view"
"back" -> "text_rear_view"
"left" -> "text_left_side"
"right" -> "text_right_side"
"angle" -> "text_angle_view"
else -> ""
}
val label = if (key.isNotEmpty()) StringProvider.getString(key) else orientationStr.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }
text = label
textSize = 16f
setTypeface(null, android.graphics.Typeface.BOLD)
setPadding(16, 8, 0, 8)
}
imagesContainer.addView(orientationHeader)
// Grid for thumbnails
val gridLayout = GridLayout(this).apply {
columnCount = 3
layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
).apply {
setMargins(16, 0, 16, 16)
}
}
// Images for this orientation
files.forEach { file ->
val imageRow = LinearLayout(this).apply {
orientation = LinearLayout.HORIZONTAL
layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
200 // Smaller height for images
).apply {
setMargins(16, 0, 0, 16)
val thumbnailView = layoutInflater.inflate(R.layout.item_image_thumbnail, gridLayout, false)
val imageView = thumbnailView.findViewById<ImageView>(R.id.ivThumbnail)
val deleteButton = thumbnailView.findViewById<View>(R.id.btnDelete)
imageView.setImageBitmap(BitmapFactory.decodeFile(file.absolutePath))
imageView.setOnClickListener {
val intent = Intent(this@CowSelectionActivity, FullScreenImageActivity::class.java)
intent.putExtra("IMAGE_PATH", file.absolutePath)
startActivity(intent)
}
deleteButton.setOnClickListener {
if (file.delete()) {
Toast.makeText(this@CowSelectionActivity, StringProvider.getString("toast_image_deleted"), Toast.LENGTH_SHORT).show()
refreshCowImages()
} else {
Toast.makeText(this@CowSelectionActivity, StringProvider.getString("toast_error_deleting_image"), Toast.LENGTH_SHORT).show()
}
}
val imageView = ImageView(this).apply {
layoutParams = LinearLayout.LayoutParams(
0,
LinearLayout.LayoutParams.MATCH_PARENT,
1f
)
scaleType = ImageView.ScaleType.CENTER_CROP
setImageBitmap(BitmapFactory.decodeFile(file.absolutePath))
setOnClickListener {
val intent = Intent(context, FullScreenImageActivity::class.java)
intent.putExtra("IMAGE_PATH", file.absolutePath)
startActivity(intent)
}
}
val deleteButton = Button(this).apply {
text = "Delete"
textSize = 12f
layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
).apply {
setMargins(16,0,0,0)
}
setOnClickListener {
if (file.delete()) {
Toast.makeText(context, "Image deleted", Toast.LENGTH_SHORT).show()
refreshCowImages()
} else {
Toast.makeText(context, "Error deleting image", Toast.LENGTH_SHORT).show()
}
}
}
imageRow.addView(imageView)
imageRow.addView(deleteButton)
imagesContainer.addView(imageRow)
gridLayout.addView(thumbnailView)
}
imagesContainer.addView(gridLayout)
}
override fun onSaveInstanceState(outState: Bundle) {

View File

@ -1,14 +1,16 @@
package com.example.animalrating
import android.content.Intent
import android.content.res.ColorStateList
import android.graphics.BitmapFactory
import android.os.Bundle
import android.widget.Button
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.button.MaterialButton
import com.google.android.material.floatingactionbutton.FloatingActionButton
import java.io.File
import java.util.Locale
@ -20,7 +22,30 @@ class GalleryActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_gallery)
// Initialize StringProvider
StringProvider.initialize(this)
// Setup Back Button
val toolbar = findViewById<androidx.appcompat.widget.Toolbar>(R.id.toolbar)
setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowHomeEnabled(true)
supportActionBar?.setDisplayShowTitleEnabled(false)
// Set Toolbar title
findViewById<TextView>(R.id.tvToolbarTitle)?.text = StringProvider.getString("title_gallery")
toolbar.setNavigationOnClickListener {
finish()
}
container = findViewById(R.id.galleryContainer)
findViewById<FloatingActionButton>(R.id.fabAddCow).setOnClickListener {
val intent = Intent(this, CowSelectionActivity::class.java)
startActivity(intent)
}
refreshGallery()
}
@ -35,12 +60,23 @@ class GalleryActivity : AppCompatActivity() {
if (parts.size >= 2) "${parts[0]}_${parts[1]}" else "unknown"
} ?: emptyMap()
val csvFile = File(filesDir, "cow_profiles.csv")
val cowDetails = if (csvFile.exists()) {
csvFile.readLines().associate { line ->
val parts = line.split(",")
if (parts.isNotEmpty()) parts[0] to parts else "" to emptyList()
}
} else {
emptyMap()
}
groupedFiles.forEach { (cowName, cowFiles) ->
addCowSection(cowName, cowFiles)
val details = cowDetails[cowName] ?: emptyList()
addCowSection(cowName, cowFiles, details)
}
}
private fun addCowSection(cowName: String, cowFiles: List<File>) {
private fun addCowSection(cowName: String, cowFiles: List<File>, details: List<String>) {
// Cow Name Header and Retake Button
val headerLayout = LinearLayout(this).apply {
orientation = LinearLayout.HORIZONTAL
@ -53,8 +89,10 @@ class GalleryActivity : AppCompatActivity() {
}
val nameView = TextView(this).apply {
text = cowName
text = if (details.isNotEmpty()) "${StringProvider.getString("text_cow_id")} $cowName" else cowName
textSize = 20f
setTypeface(null, android.graphics.Typeface.BOLD)
setTextColor(android.graphics.Color.parseColor("#3E2723"))
layoutParams = LinearLayout.LayoutParams(
0,
LinearLayout.LayoutParams.WRAP_CONTENT,
@ -62,10 +100,21 @@ class GalleryActivity : AppCompatActivity() {
)
}
val retakeButton = Button(this).apply {
text = "Retake"
val retakeButton = MaterialButton(this).apply {
text = StringProvider.getString("btn_edit")
textSize = 12f
setTypeface(null, android.graphics.Typeface.BOLD)
setTextColor(android.graphics.Color.parseColor("#5D4037"))
cornerRadius = (12 * resources.displayMetrics.density).toInt()
backgroundTintList = ColorStateList.valueOf(android.graphics.Color.parseColor("#EFEBE9"))
strokeWidth = (1 * resources.displayMetrics.density).toInt()
strokeColor = ColorStateList.valueOf(android.graphics.Color.parseColor("#5D4037"))
minHeight = 0
minimumHeight = 0
setPadding(24, 20, 24, 20)
setOnClickListener {
val intent = Intent(context, CowSelectionActivity::class.java)
val intent = Intent(this@GalleryActivity, CowSelectionActivity::class.java)
intent.putExtra("COW_NAME", cowName)
startActivity(intent)
}
@ -75,6 +124,48 @@ class GalleryActivity : AppCompatActivity() {
headerLayout.addView(retakeButton)
container.addView(headerLayout)
// Display details if available
// Header: CowID,Species,Breed,Age,MilkYield,CalvingNumber,ReproductiveStatus,Description
if (details.size >= 7) {
val detailsLayout = LinearLayout(this).apply {
orientation = LinearLayout.VERTICAL
layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
).apply {
setMargins(0, 0, 0, 16)
}
setPadding(24, 24, 24, 24)
background = android.graphics.drawable.GradientDrawable().apply {
setColor(android.graphics.Color.parseColor("#FAFAFA"))
cornerRadius = 16f
setStroke(2, android.graphics.Color.parseColor("#EEEEEE"))
}
}
val infoText = StringBuilder()
// Note: Values like "Cow", "Holstein" stored in CSV are currently displayed as is.
// To translate stored values, we'd need a reverse lookup map or similar logic if the CSV stores English keys.
// For now, we translate the labels.
infoText.append("${StringProvider.getString("label_species")} ${details.getOrElse(1) { "-" }} ")
infoText.append("${StringProvider.getString("label_breed")} ${details.getOrElse(2) { "-" }}\n")
infoText.append("${StringProvider.getString("label_age")} ${details.getOrElse(3) { "-" }} ${StringProvider.getString("unit_years")} ")
infoText.append("${StringProvider.getString("label_milk_yield")} ${details.getOrElse(4) { "-" }} ${StringProvider.getString("unit_liters")}\n")
infoText.append("${StringProvider.getString("label_calving_no")} ${details.getOrElse(5) { "-" }} ")
infoText.append("${StringProvider.getString("label_status")} ${details.getOrElse(6) { "-" }}")
val detailsView = TextView(this).apply {
text = infoText.toString()
textSize = 14f
setTextColor(android.graphics.Color.parseColor("#5D4037"))
setLineSpacing(10f, 1f)
}
detailsLayout.addView(detailsView)
container.addView(detailsLayout)
}
// Group files by orientation (e.g., left, right, etc.)
val filesByOrientation = cowFiles.groupBy { file ->
val parts = file.name.split("_")
@ -101,63 +192,60 @@ class GalleryActivity : AppCompatActivity() {
private fun addOrientationSection(orientationStr: String, files: List<File>) {
// Orientation Header
val orientationHeader = TextView(this).apply {
text = orientationStr.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }
val key = when(orientationStr.lowercase(Locale.getDefault())) {
"front" -> "text_front_view"
"back" -> "text_rear_view"
"left" -> "text_left_side"
"right" -> "text_right_side"
"angle" -> "text_angle_view"
else -> ""
}
val label = if (key.isNotEmpty()) StringProvider.getString(key) else orientationStr.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }
text = label
textSize = 16f
setTypeface(null, android.graphics.Typeface.BOLD)
setPadding(16, 8, 0, 8)
}
container.addView(orientationHeader)
// Grid for thumbnails
val gridLayout = android.widget.GridLayout(this).apply {
columnCount = 3
layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
).apply {
setMargins(16, 0, 16, 16)
}
}
// Images for this orientation
files.forEach { file ->
val imageRow = LinearLayout(this).apply {
orientation = LinearLayout.HORIZONTAL
layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
200
).apply {
setMargins(32, 0, 0, 16)
val thumbnailView = layoutInflater.inflate(R.layout.item_image_thumbnail, gridLayout, false)
val imageView = thumbnailView.findViewById<ImageView>(R.id.ivThumbnail)
val deleteButton = thumbnailView.findViewById<android.view.View>(R.id.btnDelete)
imageView.setImageBitmap(BitmapFactory.decodeFile(file.absolutePath))
imageView.setOnClickListener {
val intent = Intent(this@GalleryActivity, FullScreenImageActivity::class.java)
intent.putExtra("IMAGE_PATH", file.absolutePath)
startActivity(intent)
}
deleteButton.setOnClickListener {
if (file.delete()) {
Toast.makeText(this@GalleryActivity, StringProvider.getString("toast_image_deleted"), Toast.LENGTH_SHORT).show()
refreshGallery()
} else {
Toast.makeText(this@GalleryActivity, StringProvider.getString("toast_error_deleting_image"), Toast.LENGTH_SHORT).show()
}
}
val imageView = ImageView(this).apply {
layoutParams = LinearLayout.LayoutParams(
0,
LinearLayout.LayoutParams.MATCH_PARENT,
1f
)
scaleType = ImageView.ScaleType.CENTER_CROP
setImageBitmap(BitmapFactory.decodeFile(file.absolutePath))
setOnClickListener {
val intent = Intent(context, FullScreenImageActivity::class.java)
intent.putExtra("IMAGE_PATH", file.absolutePath)
startActivity(intent)
}
}
val deleteButton = Button(this).apply {
text = "Delete"
textSize = 12f
layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
).apply {
setMargins(16,0,0,0)
}
setOnClickListener {
if (file.delete()) {
Toast.makeText(context, "Image deleted", Toast.LENGTH_SHORT).show()
refreshGallery()
} else {
Toast.makeText(context, "Error deleting image", Toast.LENGTH_SHORT).show()
}
}
}
imageRow.addView(imageView)
imageRow.addView(deleteButton)
container.addView(imageRow)
gridLayout.addView(thumbnailView)
}
container.addView(gridLayout)
}
override fun onResume() {

View File

@ -1,13 +1,21 @@
package com.example.animalrating
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.view.View
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.Button
import android.widget.ImageView
import android.widget.PopupMenu
import android.widget.SeekBar
import android.widget.Spinner
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.google.android.material.button.MaterialButton
class HomeActivity : AppCompatActivity() {
@ -15,22 +23,103 @@ class HomeActivity : AppCompatActivity() {
const val ALGORITHM_HAMMING = "Hamming Distance"
const val ALGORITHM_EUCLIDEAN = "Euclidean Distance"
const val ALGORITHM_JACCARD = "Jaccard Similarity"
private const val PERMISSION_REQUEST_CODE = 101
private const val PREF_COW_ILLUSTRATION_INDEX = "COW_ILLUSTRATION_INDEX"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_home)
StringProvider.initialize(this)
setupUI()
checkAndRequestPermissions()
}
private fun checkAndRequestPermissions() {
val permissions = mutableListOf<String>()
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
permissions.add(android.Manifest.permission.CAMERA)
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
permissions.add(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
}
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
permissions.add(android.Manifest.permission.READ_EXTERNAL_STORAGE)
}
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_MEDIA_IMAGES) != PackageManager.PERMISSION_GRANTED) {
permissions.add(android.Manifest.permission.READ_MEDIA_IMAGES)
}
} else {
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
permissions.add(android.Manifest.permission.READ_EXTERNAL_STORAGE)
}
}
}
if (permissions.isNotEmpty()) {
ActivityCompat.requestPermissions(this, permissions.toTypedArray(), PERMISSION_REQUEST_CODE)
}
}
private fun setupUI() {
// Language Spinner
val languageSpinner = findViewById<Spinner>(R.id.spinnerLanguage)
val languages = StringProvider.getLanguages()
val languageAdapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, languages)
languageAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
languageSpinner.adapter = languageAdapter
val prefs = getSharedPreferences("AnimalRatingPrefs", MODE_PRIVATE)
val savedLang = prefs.getString("LANGUAGE", "English")
languageSpinner.setSelection(languages.indexOf(savedLang))
languageSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
val selectedLanguage = languages[position]
val currentLang = prefs.getString("LANGUAGE", "English")
// Only update and recreate if language actually changed
if (selectedLanguage != currentLang) {
saveSettings() // Save UI state so it's not lost
StringProvider.setLanguage(selectedLanguage, this@HomeActivity)
// Post recreate to avoid WindowLeaked (allows spinner popup to close)
android.os.Handler(android.os.Looper.getMainLooper()).post {
recreate()
}
}
}
override fun onNothingSelected(parent: AdapterView<*>?) {}
}
// Set text from StringProvider
findViewById<TextView>(R.id.tvTitle).text = StringProvider.getString("title_home")
findViewById<MaterialButton>(R.id.btnViewGallery).text = StringProvider.getString("btn_view_gallery")
findViewById<MaterialButton>(R.id.btnSelectCow).text = StringProvider.getString("btn_select_cow")
findViewById<TextView>(R.id.tvAlgorithmLabel).text = StringProvider.getString("label_algorithm")
findViewById<TextView>(R.id.tvThresholdLabel).text = StringProvider.getString("label_match_threshold")
// Cow Illustration and Logic
val ivCowIllustration = findViewById<ImageView>(R.id.ivCowIllustration)
val savedIndex = prefs.getInt(PREF_COW_ILLUSTRATION_INDEX, 0)
setCowIllustration(ivCowIllustration, savedIndex)
ivCowIllustration.setOnClickListener { view ->
showIllustrationPopup(view, ivCowIllustration)
}
// Navigation buttons
findViewById<Button>(R.id.btnViewGallery).setOnClickListener {
findViewById<MaterialButton>(R.id.btnViewGallery).setOnClickListener {
startActivity(Intent(this, GalleryActivity::class.java))
}
findViewById<Button>(R.id.btnSelectCow).setOnClickListener {
findViewById<MaterialButton>(R.id.btnSelectCow).setOnClickListener {
saveSettingsAndStart()
}
@ -42,7 +131,6 @@ class HomeActivity : AppCompatActivity() {
spinner.adapter = adapter
// Set default selection from preferences or intent
val prefs = getSharedPreferences("AnimalRatingPrefs", MODE_PRIVATE)
val savedAlg = prefs.getString("ALGORITHM", ALGORITHM_HAMMING)
spinner.setSelection(algorithms.indexOf(savedAlg))
@ -63,21 +151,68 @@ class HomeActivity : AppCompatActivity() {
})
}
private fun saveSettingsAndStart() {
private fun showIllustrationPopup(anchor: View, imageView: ImageView) {
val popup = PopupMenu(this, anchor)
for (i in 0..4) {
popup.menu.add(0, i, i, "Illustration $i")
}
popup.setOnMenuItemClickListener { item ->
val index = item.itemId
setCowIllustration(imageView, index)
// Save preference
getSharedPreferences("AnimalRatingPrefs", MODE_PRIVATE).edit()
.putInt(PREF_COW_ILLUSTRATION_INDEX, index)
.apply()
true
}
popup.show()
}
private fun setCowIllustration(imageView: ImageView, index: Int) {
// Map index to drawable resource
// We assume resources are named cow_illustration (for index 0 or default) or similar logic if strictly named
// But user said "cow_illustration_{n}, where n=0,1,2,3,4"
// However, currently we likely only have 'cow_illustration' in drawable from previous step, or user implies they exist.
// We will try to find resources dynamically.
val resName = "cow_illustration_$index"
val resId = resources.getIdentifier(resName, "drawable", packageName)
if (resId != 0) {
imageView.setImageResource(resId)
} else {
// Fallback to default if specific one not found
if (index == 0) {
// Maybe it's just "cow_illustration" without suffix if n=0 is base?
// Or user provided 5 distinct files. We try 'cow_illustration' as fallback.
val defaultId = resources.getIdentifier("cow_illustration", "drawable", packageName)
if (defaultId != 0) imageView.setImageResource(defaultId)
}
}
}
private fun saveSettings() {
val spinner = findViewById<Spinner>(R.id.spinnerAlgorithm)
val seekBar = findViewById<SeekBar>(R.id.seekBarThreshold)
val selectedAlgorithm = spinner.selectedItem.toString()
val threshold = seekBar.progress
if (spinner != null && seekBar != null) {
val selectedAlgorithm = spinner.selectedItem?.toString() ?: ALGORITHM_HAMMING
val threshold = seekBar.progress
// Save to preferences
val prefs = getSharedPreferences("AnimalRatingPrefs", MODE_PRIVATE)
prefs.edit().apply {
putString("ALGORITHM", selectedAlgorithm)
putInt("THRESHOLD", threshold)
apply()
// Save to preferences
val prefs = getSharedPreferences("AnimalRatingPrefs", MODE_PRIVATE)
prefs.edit().apply {
putString("ALGORITHM", selectedAlgorithm)
putInt("THRESHOLD", threshold)
apply()
}
}
}
private fun saveSettingsAndStart() {
saveSettings()
startActivity(Intent(this, CowSelectionActivity::class.java))
}
}

View File

@ -0,0 +1,101 @@
package com.example.animalrating
import android.content.Context
import org.json.JSONObject
import java.io.InputStream
object StringProvider {
private var stringData: JSONObject? = null
private var currentLanguage = "English"
private const val DEFAULT_LANGUAGE = "English"
fun initialize(context: Context) {
if (stringData == null) {
try {
val inputStream: InputStream = context.resources.openRawResource(R.raw.strings)
val jsonString = inputStream.bufferedReader().use { it.readText() }
stringData = JSONObject(jsonString)
// Load saved language
val prefs = context.getSharedPreferences("AnimalRatingPrefs", Context.MODE_PRIVATE)
currentLanguage = prefs.getString("LANGUAGE", DEFAULT_LANGUAGE) ?: DEFAULT_LANGUAGE
} catch (e: Exception) {
e.printStackTrace()
// Handle error, maybe load default strings or log
}
}
}
fun setLanguage(language: String, context: Context) {
currentLanguage = language
// Save selected language
val prefs = context.getSharedPreferences("AnimalRatingPrefs", Context.MODE_PRIVATE)
prefs.edit().putString("LANGUAGE", language).apply()
}
fun getLanguages(): List<String> {
return stringData?.keys()?.asSequence()?.toList() ?: listOf(DEFAULT_LANGUAGE)
}
fun getString(key: String): String {
return getStringForLanguage(key, currentLanguage)
}
fun getStringEnglish(key: String): String {
return getStringForLanguage(key, DEFAULT_LANGUAGE)
}
private fun getStringForLanguage(key: String, language: String): String {
return try {
stringData?.getJSONObject(language)?.getString(key) ?: ""
} catch (e: Exception) {
// Fallback to English if key not found in current language
try {
if (language != DEFAULT_LANGUAGE) {
stringData?.getJSONObject(DEFAULT_LANGUAGE)?.getString(key) ?: ""
} else {
""
}
} catch (e2: Exception) {
"" // Return empty if not found anywhere
}
}
}
fun getKeyForValue(value: String): String? {
// Helper to find the key for a given localized value in current language
// This is expensive, but useful if we need to reverse lookup
val langData = stringData?.optJSONObject(currentLanguage) ?: return null
val keys = langData.keys()
while (keys.hasNext()) {
val key = keys.next()
if (langData.getString(key) == value) {
return key
}
}
// Also check English just in case it was stored as English
val englishData = stringData?.optJSONObject(DEFAULT_LANGUAGE) ?: return null
val engKeys = englishData.keys()
while (engKeys.hasNext()) {
val key = engKeys.next()
if (englishData.getString(key) == value) {
return key
}
}
return null
}
fun getKeyForEnglishValue(value: String): String? {
val englishData = stringData?.optJSONObject(DEFAULT_LANGUAGE) ?: return null
val engKeys = englishData.keys()
while (engKeys.hasNext()) {
val key = engKeys.next()
if (englishData.getString(key) == value) {
return key
}
}
return null
}
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#EFEBE9" />
<corners android:radius="16dp" />
</shape>

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 616 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#FFFFFF">
<path
android:fillColor="#FFFFFF"
android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8l8,8l1.41,-1.41L7.83,13H20v-2z"/>
</vector>

View File

@ -0,0 +1,22 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="40dp"
android:height="40dp"
android:viewportWidth="40"
android:viewportHeight="40">
<!-- Circle Background -->
<path
android:fillColor="#EFEBE9"
android:pathData="M20,20m-20,0a20,20 0,1 1,40 0a20,20 0,1 1,-40 0"/>
<!-- Arrow Icon (Centered and Scaled) -->
<group
android:scaleX="1.0"
android:scaleY="1.0"
android:translateX="8.0"
android:translateY="8.0">
<path
android:fillColor="#5D4037"
android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8l8,8l1.41,-1.41L7.83,13H20v-2z"/>
</group>
</vector>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#EFEBE9" />
<corners android:radius="16dp" />
</shape>

View File

@ -1,133 +1,451 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#F5F5F5">
android:orientation="vertical"
android:background="#FFFFFF">
<LinearLayout
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center"
android:padding="16dp">
android:layout_height="?attr/actionBarSize"
android:background="#FFFFFF"
app:navigationIcon="@drawable/ic_round_back_button">
<androidx.cardview.widget.CardView
<TextView
android:id="@+id/tvToolbarTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Cow Selection"
android:textSize="20sp"
android:textStyle="bold"
android:textColor="#3E2723"/>
</androidx.appcompat.widget.Toolbar>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
app:cardCornerRadius="12dp"
app:cardElevation="4dp"
app:contentPadding="16dp">
android:orientation="vertical"
android:padding="24dp">
<TextView
android:id="@+id/tvAddCowDetails"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Add Cow Details"
android:textSize="24sp"
android:textStyle="bold"
android:textColor="#3E2723"
android:layout_marginBottom="24dp"/>
<!-- Form Fields -->
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilSpecies"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
app:boxCornerRadiusTopStart="12dp"
app:boxCornerRadiusTopEnd="12dp"
app:boxCornerRadiusBottomStart="12dp"
app:boxCornerRadiusBottomEnd="12dp"
app:boxStrokeColor="#6D4C41"
android:hint="Species">
<AutoCompleteTextView
android:id="@+id/spinnerSpecies"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="none"/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilBreed"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
app:boxCornerRadiusTopStart="12dp"
app:boxCornerRadiusTopEnd="12dp"
app:boxCornerRadiusBottomStart="12dp"
app:boxCornerRadiusBottomEnd="12dp"
app:boxStrokeColor="#6D4C41"
android:hint="Breed">
<AutoCompleteTextView
android:id="@+id/spinnerBreed"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="none"/>
</com.google.android.material.textfield.TextInputLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center">
android:orientation="horizontal"
android:baselineAligned="false"
android:layout_marginBottom="16dp">
<TextView
android:id="@+id/tvCowName"
android:layout_width="wrap_content"
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilAge"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textStyle="bold"
android:textColor="#333333"
android:layout_marginBottom="16dp"/>
android:layout_weight="1"
android:layout_marginEnd="8dp"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
app:boxCornerRadiusTopStart="12dp"
app:boxCornerRadiusTopEnd="12dp"
app:boxCornerRadiusBottomStart="12dp"
app:boxCornerRadiusBottomEnd="12dp"
app:boxStrokeColor="#6D4C41"
android:hint="Age (Years)">
<Button
android:id="@+id/btnNewCow"
android:layout_width="wrap_content"
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etAge"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number"/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilMilk"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Capture New Cow"
android:backgroundTint="#2196F3"
android:textColor="#FFFFFF"/>
android:layout_weight="1"
android:layout_marginStart="8dp"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
app:boxCornerRadiusTopStart="12dp"
app:boxCornerRadiusTopEnd="12dp"
app:boxCornerRadiusBottomStart="12dp"
app:boxCornerRadiusBottomEnd="12dp"
app:boxStrokeColor="#6D4C41"
android:hint="Milk Yield (L)">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="numberDecimal"/>
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Select Orientation"
android:textSize="20sp"
android:textStyle="bold"
android:layout_marginBottom="16dp"/>
<GridLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:columnCount="2"
android:rowCount="3"
android:alignmentMode="alignMargins"
android:columnOrderPreserved="false"
android:layout_marginBottom="32dp">
<!-- Left -->
<Button
android:id="@+id/btnLeft"
android:layout_width="0dp"
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilCalving"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
android:text="Left"
android:layout_margin="8dp"
android:backgroundTint="#FF5722"
android:textColor="#FFFFFF"/>
android:layout_marginBottom="16dp"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
app:boxCornerRadiusTopStart="12dp"
app:boxCornerRadiusTopEnd="12dp"
app:boxCornerRadiusBottomStart="12dp"
app:boxCornerRadiusBottomEnd="12dp"
app:boxStrokeColor="#6D4C41"
android:hint="Calving Number">
<!-- Right -->
<Button
android:id="@+id/btnRight"
android:layout_width="0dp"
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number"/>
</com.google.android.material.textfield.TextInputLayout>
<TextView
android:id="@+id/tvReproductiveStatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
android:text="Right"
android:layout_margin="8dp"
android:backgroundTint="#FF5722"
android:textColor="#FFFFFF"/>
android:text="Reproductive Status"
android:textColor="#5D4037"
android:layout_marginBottom="8dp"/>
<!-- Front -->
<Button
android:id="@+id/btnFront"
android:layout_width="0dp"
<RadioGroup
android:id="@+id/rgReproductiveStatus"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
android:text="Front"
android:layout_margin="8dp"
android:backgroundTint="#FF5722"
android:textColor="#FFFFFF"/>
android:orientation="horizontal"
android:layout_marginBottom="16dp">
<!-- Back -->
<Button
android:id="@+id/btnBack"
android:layout_width="0dp"
<RadioButton
android:id="@+id/rbPregnant"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Pregnant"
android:layout_marginEnd="16dp"/>
<RadioButton
android:id="@+id/rbCalved"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Calved"
android:layout_marginEnd="16dp"/>
<RadioButton
android:id="@+id/rbNone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="None"/>
</RadioGroup>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilDescription"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
android:text="Back"
android:layout_margin="8dp"
android:backgroundTint="#FF5722"
android:textColor="#FFFFFF"/>
android:layout_marginBottom="24dp"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
app:boxCornerRadiusTopStart="12dp"
app:boxCornerRadiusTopEnd="12dp"
app:boxCornerRadiusBottomStart="12dp"
app:boxCornerRadiusBottomEnd="12dp"
app:boxStrokeColor="#6D4C41"
android:hint="Description">
<!-- Top (Centered in last row) -->
<Button
android:id="@+id/btnTop"
android:layout_width="0dp"
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textMultiLine"
android:minLines="3"/>
</com.google.android.material.textfield.TextInputLayout>
<!-- Upload Photos -->
<TextView
android:id="@+id/tvUploadPhotos"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
android:layout_gravity="fill_horizontal"
android:layout_columnSpan="2"
android:text="Angle"
android:layout_margin="8dp"
android:backgroundTint="#FF5722"
android:textColor="#FFFFFF"/>
android:text="Upload Photos"
android:textSize="18sp"
android:textStyle="bold"
android:textColor="#3E2723"
android:layout_marginBottom="16dp"/>
</GridLayout>
<GridLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:columnCount="2"
android:rowCount="3"
android:alignmentMode="alignMargins"
android:columnOrderPreserved="false"
android:layout_marginBottom="24dp">
<!-- Container for displaying current cow's images -->
<LinearLayout
android:id="@+id/currentCowImagesContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="8dp"/>
<!-- Front View -->
<androidx.cardview.widget.CardView
android:layout_width="0dp"
android:layout_height="100dp"
android:layout_columnWeight="1"
android:layout_margin="8dp"
app:cardCornerRadius="8dp"
app:cardElevation="2dp">
<LinearLayout
android:id="@+id/btnFront"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:background="#F5F5F5"
android:clickable="true"
android:focusable="true">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@android:drawable/ic_menu_camera"
app:tint="#5D4037"/>
<TextView
android:id="@+id/tvFrontView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Front View"
android:textSize="12sp"
android:textColor="#5D4037"
android:layout_marginTop="4dp"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
</ScrollView>
<!-- Rear View (Back) -->
<androidx.cardview.widget.CardView
android:layout_width="0dp"
android:layout_height="100dp"
android:layout_columnWeight="1"
android:layout_margin="8dp"
app:cardCornerRadius="8dp"
app:cardElevation="2dp">
<LinearLayout
android:id="@+id/btnBack"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:background="#F5F5F5"
android:clickable="true"
android:focusable="true">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@android:drawable/ic_menu_camera"
app:tint="#5D4037"/>
<TextView
android:id="@+id/tvRearView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Rear View"
android:textSize="12sp"
android:textColor="#5D4037"
android:layout_marginTop="4dp"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
<!-- Left Side -->
<androidx.cardview.widget.CardView
android:layout_width="0dp"
android:layout_height="100dp"
android:layout_columnWeight="1"
android:layout_margin="8dp"
app:cardCornerRadius="8dp"
app:cardElevation="2dp">
<LinearLayout
android:id="@+id/btnLeft"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:background="#F5F5F5"
android:clickable="true"
android:focusable="true">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@android:drawable/ic_menu_camera"
app:tint="#5D4037"/>
<TextView
android:id="@+id/tvLeftSide"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Left Side"
android:textSize="12sp"
android:textColor="#5D4037"
android:layout_marginTop="4dp"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
<!-- Right Side -->
<androidx.cardview.widget.CardView
android:layout_width="0dp"
android:layout_height="100dp"
android:layout_columnWeight="1"
android:layout_margin="8dp"
app:cardCornerRadius="8dp"
app:cardElevation="2dp">
<LinearLayout
android:id="@+id/btnRight"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:background="#F5F5F5"
android:clickable="true"
android:focusable="true">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@android:drawable/ic_menu_camera"
app:tint="#5D4037"/>
<TextView
android:id="@+id/tvRightSide"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Right Side"
android:textSize="12sp"
android:textColor="#5D4037"
android:layout_marginTop="4dp"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
<!-- Angle View -->
<androidx.cardview.widget.CardView
android:layout_width="0dp"
android:layout_height="100dp"
android:layout_columnWeight="1"
android:layout_columnSpan="2"
android:layout_margin="8dp"
app:cardCornerRadius="8dp"
app:cardElevation="2dp">
<LinearLayout
android:id="@+id/btnTop"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:background="#F5F5F5"
android:clickable="true"
android:focusable="true">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@android:drawable/ic_menu_camera"
app:tint="#5D4037"/>
<TextView
android:id="@+id/tvAngleView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Angle View"
android:textSize="12sp"
android:textColor="#5D4037"
android:layout_marginTop="4dp"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
</GridLayout>
<!-- Container for showing captured thumbnails -->
<LinearLayout
android:id="@+id/currentCowImagesContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginBottom="24dp"/>
<!-- Bottom Buttons -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/btnNewCow"
android:layout_width="0dp"
android:layout_height="56dp"
android:layout_weight="1"
android:text="Save Profile"
android:textSize="16sp"
android:textStyle="bold"
app:cornerRadius="12dp"
app:backgroundTint="#6D4C41"
android:layout_marginEnd="8dp"/>
<com.google.android.material.button.MaterialButton
android:id="@+id/btnCancel"
android:layout_width="0dp"
android:layout_height="56dp"
android:layout_weight="1"
android:text="Cancel"
android:textSize="16sp"
android:textStyle="bold"
android:textColor="#5D4037"
app:cornerRadius="12dp"
app:backgroundTint="#EFEBE9"
app:strokeColor="#5D4037"
app:strokeWidth="1dp"
android:layout_marginStart="8dp"/>
</LinearLayout>
<!-- Hidden TextView for Cow Name logic compatibility -->
<TextView
android:id="@+id/tvCowName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"/>
</LinearLayout>
</ScrollView>
</LinearLayout>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000">
@ -12,13 +13,16 @@
android:scaleType="fitCenter"
android:contentDescription="Full Screen Image" />
<Button
<ImageButton
android:id="@+id/btnBack"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="32dp"
android:text="Back" />
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_margin="16dp"
android:src="@drawable/ic_round_back_button"
android:background="@android:color/transparent"
android:scaleType="centerInside"
android:contentDescription="Back" />
</RelativeLayout>

View File

@ -1,26 +1,101 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#F5F5F5">
<LinearLayout
android:id="@+id/galleryContainer"
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
android:background="#FFFFFF"
app:elevation="0dp">
<TextView
android:layout_width="wrap_content"
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#FFFFFF"
app:navigationIcon="@drawable/ic_round_back_button">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Saved Cow Profiles"
android:textSize="20sp"
android:textStyle="bold"
android:textColor="#3E2723"/>
</androidx.appcompat.widget.Toolbar>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Captured Images"
android:textSize="28sp"
android:textStyle="bold"
android:textColor="#333333"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="24dp"/>
android:orientation="horizontal"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:paddingBottom="16dp">
</LinearLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
app:boxBackgroundColor="#F5F5F5"
app:boxCornerRadiusTopStart="24dp"
app:boxCornerRadiusTopEnd="24dp"
app:boxCornerRadiusBottomStart="24dp"
app:boxCornerRadiusBottomEnd="24dp"
app:boxStrokeWidth="0dp"
app:startIconDrawable="@android:drawable/ic_menu_search"
app:startIconTint="#8D6E63"
android:hint="Search profiles...">
</ScrollView>
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="12dp"
android:paddingBottom="12dp"/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.button.MaterialButton
android:layout_width="52dp"
android:layout_height="52dp"
android:layout_marginStart="12dp"
app:icon="@android:drawable/ic_menu_sort_by_size"
app:iconTint="#5D4037"
app:backgroundTint="#EFEBE9"
app:cornerRadius="12dp"
app:iconGravity="textStart"
app:iconPadding="0dp"
android:insetTop="0dp"
android:insetBottom="0dp"/>
</LinearLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:id="@+id/galleryContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp"/>
</androidx.core.widget.NestedScrollView>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fabAddCow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="24dp"
app:srcCompat="@android:drawable/ic_input_add"
app:tint="#FFFFFF"
app:backgroundTint="#6D4C41"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -1,84 +1,187 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="16dp"
android:background="#F5F5F5">
android:background="#F7F7F7"
android:fillViewport="true">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Animal Rating"
android:textSize="32sp"
android:textStyle="bold"
android:textColor="#333333"
android:layout_marginBottom="32dp"/>
<androidx.cardview.widget.CardView
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
app:cardCornerRadius="12dp"
app:cardElevation="4dp"
app:contentPadding="16dp">
android:orientation="vertical"
android:padding="24dp"
android:gravity="center_horizontal">
<!-- Language Selection (Top Right) -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="end"
android:layout_marginBottom="16dp">
<Spinner
android:id="@+id/spinnerLanguage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="8dp"
android:background="@drawable/bg_spinner_rounded"/>
</LinearLayout>
<!-- Cow Illustration - Circular Logo -->
<androidx.cardview.widget.CardView
android:layout_width="180dp"
android:layout_height="180dp"
app:cardCornerRadius="90dp"
app:cardElevation="8dp"
app:cardBackgroundColor="#FFFFFF"
android:layout_marginBottom="24dp">
<ImageView
android:id="@+id/ivCowIllustration"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/cow_illustration_0"
android:scaleType="centerCrop"
android:contentDescription="Cow Illustration"/>
</androidx.cardview.widget.CardView>
<!-- Title -->
<TextView
android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Cow Data Collector"
android:textSize="28sp"
android:textStyle="bold"
android:textColor="#3E2723"
android:textAlignment="center"
android:layout_marginBottom="8dp"/>
<!-- Subtitle -->
<TextView
android:id="@+id/tvSubtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Record and manage cow information easily."
android:textSize="16sp"
android:textColor="#6D4C41"
android:textAlignment="center"
android:layout_marginBottom="40dp"/>
<!-- Main Buttons Container -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center">
android:layout_marginBottom="32dp">
<TextView
<!-- Add New Cow Profile Button -->
<com.google.android.material.button.MaterialButton
android:id="@+id/btnSelectCow"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Settings"
android:layout_height="72dp"
android:text="Add New Cow Profile"
android:textSize="18sp"
android:textStyle="bold"
android:layout_marginBottom="8dp"/>
app:cornerRadius="16dp"
app:backgroundTint="#6D4C41"
app:icon="@android:drawable/ic_input_add"
app:iconGravity="textStart"
app:iconPadding="12dp"
android:layout_marginBottom="16dp"
android:elevation="4dp"/>
<LinearLayout
<!-- View Saved Profiles Button -->
<com.google.android.material.button.MaterialButton
android:id="@+id/btnViewGallery"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="8dp">
android:layout_height="72dp"
android:text="View Saved Profiles"
android:textSize="18sp"
android:textStyle="bold"
android:textColor="#5D4037"
app:cornerRadius="16dp"
app:backgroundTint="#EFEBE9"
app:strokeColor="#5D4037"
app:strokeWidth="1dp"
app:icon="@android:drawable/ic_menu_gallery"
app:iconTint="#5D4037"
app:iconGravity="textStart"
app:iconPadding="12dp"
android:elevation="4dp"/>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Algorithm:"
android:layout_marginEnd="8dp"/>
<Spinner
android:id="@+id/spinnerAlgorithm"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
</LinearLayout>
<!-- Settings Card -->
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="16dp"
app:cardElevation="2dp"
app:cardBackgroundColor="#FFFFFF"
android:layout_marginBottom="24dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginBottom="16dp">
android:padding="20dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Settings"
android:textSize="18sp"
android:textStyle="bold"
android:textColor="#3E2723"
android:layout_marginBottom="16dp"/>
<!-- Algorithm Selection -->
<TextView
android:id="@+id/tvAlgorithmLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Algorithm"
android:textSize="14sp"
android:textColor="#5D4037"
android:layout_marginBottom="8dp"/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_spinner_rounded"
android:padding="4dp"
android:layout_marginBottom="20dp">
<Spinner
android:id="@+id/spinnerAlgorithm"
android:layout_width="match_parent"
android:layout_height="48dp"/>
</FrameLayout>
<!-- Threshold Slider -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
android:gravity="center_vertical"
android:layout_marginBottom="8dp">
<TextView
android:layout_width="wrap_content"
android:id="@+id/tvThresholdLabel"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Threshold: "/>
android:layout_weight="1"
android:text="Match Threshold"
android:textSize="14sp"
android:textColor="#5D4037"/>
<TextView
android:id="@+id/tvThresholdValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="75%"/>
android:text="75%"
android:textStyle="bold"
android:textColor="#3E2723"/>
</LinearLayout>
<SeekBar
@ -86,37 +189,10 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="100"
android:progress="75"/>
android:progressTint="#6D4C41"
android:thumbTint="#6D4C41"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start New Rating"
android:textSize="18sp"
android:textColor="#666666"
android:layout_marginBottom="16dp"/>
<Button
android:id="@+id/btnSelectCow"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Select Cow"
android:textSize="16sp"
android:padding="12dp"
android:backgroundTint="#FF5722"
android:textColor="#FFFFFF"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
<Button
android:id="@+id/btnViewGallery"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="View Collected Images"
android:textSize="16sp"
android:padding="12dp"
android:backgroundTint="#2196F3"
android:textColor="#FFFFFF"/>
</LinearLayout>
</LinearLayout>
</ScrollView>

View File

@ -1,4 +1,5 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -29,4 +30,25 @@
android:alpha="0.9"
android:elevation="10dp"/>
<com.google.android.material.button.MaterialButton
android:id="@+id/btnExit"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="top|start"
android:layout_margin="16dp"
style="@style/Widget.MaterialComponents.Button.Icon"
app:icon="@drawable/ic_back_arrow"
app:iconSize="24dp"
app:iconTint="#FFFFFF"
app:backgroundTint="#80000000"
app:cornerRadius="24dp"
android:padding="0dp"
android:insetLeft="0dp"
android:insetTop="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
app:iconGravity="textStart"
app:iconPadding="0dp"
android:gravity="center"/>
</FrameLayout>

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="4dp">
<androidx.cardview.widget.CardView
android:layout_width="100dp"
android:layout_height="100dp"
app:cardCornerRadius="8dp"
app:cardElevation="2dp">
<ImageView
android:id="@+id/ivThumbnail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:background="#E0E0E0"/>
</androidx.cardview.widget.CardView>
<com.google.android.material.button.MaterialButton
android:id="@+id/btnDelete"
style="@style/Widget.MaterialComponents.Button.Icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="top|end"
android:layout_margin="4dp"
app:icon="@android:drawable/ic_delete"
app:iconSize="14dp"
app:iconTint="#FFFFFF"
android:backgroundTint="#C62828"
app:cornerRadius="12dp"
android:padding="0dp"
android:insetLeft="0dp"
android:insetTop="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
app:iconGravity="textStart"
app:iconPadding="0dp"
android:gravity="center"/>
</FrameLayout>

View File

@ -0,0 +1,118 @@
{
"English": {
"app_name": "Animal Rating",
"title_home": "Animal Rating",
"title_gallery": "Saved Cow Profiles",
"title_add_cow_details": "Add Cow Details",
"title_cow_selection": "Cow Selection",
"btn_view_gallery": "View Saved Cow Profiles",
"btn_select_cow": "Select a Cow",
"label_algorithm": "Algorithm",
"label_match_threshold": "Match Threshold",
"btn_edit": "Edit",
"hint_search_profiles": "Search profiles...",
"toast_image_deleted": "Image deleted",
"toast_error_deleting_image": "Error deleting image",
"text_cow_id": "Cow ID:",
"label_species": "Species:",
"label_breed": "Breed:",
"label_age": "Age:",
"unit_years": "years",
"label_milk_yield": "Milk Yield:",
"unit_liters": "L",
"label_calving_no": "Calving #:",
"label_status": "Status:",
"hint_species": "Species",
"hint_breed": "Breed",
"hint_age": "Age (Years)",
"hint_milk_yield": "Milk Yield (L)",
"hint_calving_number": "Calving Number",
"label_reproductive_status": "Reproductive Status",
"radio_pregnant": "Pregnant",
"radio_calved": "Calved",
"radio_none": "None",
"hint_description": "Description",
"label_upload_photos": "Upload Photos",
"text_front_view": "Front View",
"text_rear_view": "Rear View",
"text_left_side": "Left Side",
"text_right_side": "Right Side",
"text_angle_view": "Angle View",
"btn_save_profile": "Save Profile",
"btn_cancel": "Cancel",
"toast_profile_saved": "Profile Saved!",
"toast_error_saving_profile": "Error saving profile:",
"toast_capture_failed": "Photo capture failed",
"toast_saved_as": "Saved as",
"toast_error_saving_image": "Error saving image",
"content_desc_back": "Back",
"content_desc_full_screen_image": "Full Screen Image",
"species_cow": "Cow",
"species_buffalo": "Buffalo",
"breed_holstein": "Holstein Friesian",
"breed_jersey": "Jersey",
"breed_sahiwal": "Sahiwal",
"breed_gir": "Gir",
"breed_red_sindhi": "Red Sindhi",
"breed_murrah": "Murrah",
"breed_surti": "Surti"
},
"Hindi": {
"app_name": "पशु रेटिंग",
"title_home": "पशु रेटिंग",
"title_gallery": "सहेजे गए गाय प्रोफाइल",
"title_add_cow_details": "गाय का विवरण जोड़ें",
"title_cow_selection": "गाय का चयन",
"btn_view_gallery": "सहेजे गए प्रोफाइल देखें",
"btn_select_cow": "एक गाय का चयन करें",
"label_algorithm": "एल्गोरिदम",
"label_match_threshold": "मैच थ्रेसहोल्ड",
"btn_edit": "संपादित करें",
"hint_search_profiles": "प्रोफ़ाइल खोजें...",
"toast_image_deleted": "छवि हटा दी गई",
"toast_error_deleting_image": "छवि हटाने में त्रुटि",
"text_cow_id": "गाय आईडी:",
"label_species": "प्रजाति:",
"label_breed": "नस्ल:",
"label_age": "आयु:",
"unit_years": "वर्ष",
"label_milk_yield": "दूध की उपज:",
"unit_liters": "L",
"label_calving_no": "बछड़ों की संख्या:",
"label_status": "स्थिति:",
"hint_species": "प्रजाति",
"hint_breed": "नस्ल",
"hint_age": "आयु (वर्ष)",
"hint_milk_yield": "दूध की उपज (L)",
"hint_calving_number": "बछड़ों की संख्या",
"label_reproductive_status": "प्रजनन स्थिति",
"radio_pregnant": "गर्भवती",
"radio_calved": "बछड़ा हुआ",
"radio_none": "कोई नहीं",
"hint_description": "विवरण",
"label_upload_photos": "तस्वीरें अपलोड करें",
"text_front_view": "सामने का दृश्य",
"text_rear_view": "पीछे का दृश्य",
"text_left_side": "बाईं ओर",
"text_right_side": "दाईं ओर",
"text_angle_view": "कोणीय दृश्य",
"btn_save_profile": "प्रोफ़ाइल सहेजें",
"btn_cancel": "रद्द करें",
"toast_profile_saved": "प्रोफ़ाइल सहेजा गया!",
"toast_error_saving_profile": "प्रोफ़ाइल सहेजने में त्रुटि:",
"toast_capture_failed": "फोटो कैप्चर विफल",
"toast_saved_as": "के रूप में सहेजा गया",
"toast_error_saving_image": "छवि सहेजने में त्रुटि",
"content_desc_back": "वापस",
"content_desc_full_screen_image": "पूर्ण स्क्रीन छवि",
"species_cow": "गाय",
"species_buffalo": "भैंस",
"breed_holstein": "होल्सटीन फ्राइज़ियन",
"breed_jersey": "जर्सी",
"breed_sahiwal": "साहिवाल",
"breed_gir": "गिर",
"breed_red_sindhi": "लाल सिंधी",
"breed_murrah": "मुर्रा",
"breed_surti": "सुरती"
}
}

View File

@ -1,5 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.AnimalRating" parent="Theme.AppCompat.Light.NoActionBar" />
<style name="Theme.AnimalRating" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">#6D4C41</item>
<item name="colorPrimaryVariant">#5D4037</item>
<item name="colorOnPrimary">#FFFFFF</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">#FF5722</item>
<item name="colorSecondaryVariant">#E64A19</item>
<item name="colorOnSecondary">#FFFFFF</item>
<!-- Status bar color. -->
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
</resources>

1
vectors_source.md Normal file
View File

@ -0,0 +1 @@
Adobe Stock - https://stock.adobe.com/