expandable attendance list bug fix

This commit is contained in:
chandrashekhar reddy
2025-02-21 13:14:56 +05:30
parent 304f2cbe60
commit a72c062b96
3 changed files with 158 additions and 33 deletions

11
.idea/other.xml generated
View File

@@ -378,6 +378,17 @@
<option name="screenY" value="384" />
<option name="type" value="WEAR_OS" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="r11q" />
<option name="id" value="r11q" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="SM-S711U" />
<option name="screenDensity" value="450" />
<option name="screenX" value="1080" />
<option name="screenY" value="2340" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="30" />
<option name="brand" value="google" />

View File

@@ -13,8 +13,8 @@ android {
applicationId "in.sminnovations.smiadmin"
minSdk 26
targetSdk 34
versionCode 4
versionName "1.4"
versionCode 5
versionName "1.5"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

View File

@@ -1,11 +1,13 @@
package `in`.sminnovations.smiadmin.ui.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TextView
import androidx.cardview.widget.CardView
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import `in`.sminnovations.smiadmin.R
import `in`.sminnovations.smiadmin.data.AttendanceData
@@ -33,31 +35,45 @@ class AttendanceAdapter : RecyclerView.Adapter<AttendanceAdapter.ViewHolder>() {
// Clear previous views
holder.checkInsLayout.removeAllViews()
// Create check-in/check-out pairs dynamically
val context = holder.itemView.context
for (i in 1..attendance.checkIns.size) {
val checkInKey = "checkIn$i"
val checkOutKey = "checkOut$i"
if (attendance.checkIns.containsKey(checkInKey)) {
val pairLayout = LayoutInflater.from(context)
.inflate(R.layout.item_checkin_checkout_pair, holder.checkInsLayout, false)
val checkInView = pairLayout.findViewById<TextView>(R.id.textViewCheckIn)
val checkOutView = pairLayout.findViewById<TextView>(R.id.textViewCheckOut)
checkInView.text = "Check In: ${attendance.checkIns[checkInKey]}"
checkOutView.text = "Check Out: ${attendance.checkOuts[checkOutKey] ?: "Pending"}"
holder.checkInsLayout.addView(pairLayout)
}
}
// Display all attendance records
displayAttendanceRecords(holder.itemView.context, holder, attendance)
// Set up expansion/collapse
holder.expandableLayout.visibility = if (attendance.isExpanded) View.VISIBLE else View.GONE
holder.expandableLayout.apply {
visibility = if (attendance.isExpanded) View.VISIBLE else View.GONE
// Add animation for smooth expansion/collapse
alpha = if (attendance.isExpanded) 1.0f else 0.0f
animate()
.alpha(if (attendance.isExpanded) 1.0f else 0.0f)
.setDuration(200)
.start()
}
holder.cardView.setOnClickListener {
attendance.isExpanded = !attendance.isExpanded
// Toggle expansion state
val wasExpanded = attendance.isExpanded
attendance.isExpanded = !wasExpanded
// Animate the change
if (!wasExpanded) {
holder.expandableLayout.visibility = View.VISIBLE
holder.expandableLayout.alpha = 0.0f
holder.expandableLayout.animate()
.alpha(1.0f)
.setDuration(200)
.start()
} else {
holder.expandableLayout.animate()
.alpha(0.0f)
.setDuration(200)
.withEndAction {
if (!attendance.isExpanded) {
holder.expandableLayout.visibility = View.GONE
}
}
.start()
}
notifyItemChanged(position)
}
}
@@ -65,16 +81,114 @@ class AttendanceAdapter : RecyclerView.Adapter<AttendanceAdapter.ViewHolder>() {
override fun getItemCount() = attendanceList.size
fun updateAttendance(newAttendance: List<AttendanceData>) {
val diffCallback = AttendanceDiffCallback(attendanceList, newAttendance)
val diffResult = DiffUtil.calculateDiff(diffCallback)
attendanceList.clear()
// Convert date string to comparable format and sort
attendanceList.addAll(newAttendance.sortedByDescending {
// Convert dd-MM-yyyy to comparable format
val parts = it.date.split("-")
attendanceList.addAll(newAttendance.sortedByDescending { it.getComparableDate() })
diffResult.dispatchUpdatesTo(this)
}
private fun displayAttendanceRecords(
context: Context,
holder: ViewHolder,
attendance: AttendanceData
) {
// Create a set of all unique check-in keys
val allCheckInKeys = attendance.checkIns.keys
// Handle numbered check-ins
for (i in 1..attendance.checkIns.size) {
val checkInKey = "checkIn$i"
val checkOutKey = "checkOut$i"
if (attendance.checkIns.containsKey(checkInKey)) {
addCheckInPair(
context,
holder,
checkInKey,
checkOutKey,
attendance.checkIns[checkInKey]!!,
attendance.checkOuts[checkOutKey]
)
}
}
// Handle non-numbered check-ins
allCheckInKeys
.filter { !it.matches(Regex("checkIn\\d+")) }
.forEach { checkInKey ->
val baseKey = checkInKey.replace("checkIn", "")
val checkOutKey = "checkOut$baseKey"
addCheckInPair(
context,
holder,
checkInKey,
checkOutKey,
attendance.checkIns[checkInKey]!!,
attendance.checkOuts[checkOutKey]
)
}
}
private fun addCheckInPair(
context: Context,
holder: ViewHolder,
checkInKey: String,
checkOutKey: String,
checkInValue: String,
checkOutValue: String?
) {
val pairLayout = LayoutInflater.from(context)
.inflate(R.layout.item_checkin_checkout_pair, holder.checkInsLayout, false)
val checkInView = pairLayout.findViewById<TextView>(R.id.textViewCheckIn)
val checkOutView = pairLayout.findViewById<TextView>(R.id.textViewCheckOut)
// Display the original key name for non-standard keys
val checkInLabel = if (checkInKey.matches(Regex("checkIn\\d+"))) {
"Check In"
} else {
"Check In (${checkInKey.replace("checkIn", "")})"
}
val checkOutLabel = if (checkOutKey.matches(Regex("checkOut\\d+"))) {
"Check Out"
} else {
"Check Out (${checkOutKey.replace("checkOut", "")})"
}
checkInView.text = "$checkInLabel: $checkInValue"
checkOutView.text = "$checkOutLabel: ${checkOutValue ?: "Pending"}"
holder.checkInsLayout.addView(pairLayout)
}
}
// DiffUtil callback for efficient updates
private class AttendanceDiffCallback(
private val oldList: List<AttendanceData>,
private val newList: List<AttendanceData>
) : DiffUtil.Callback() {
override fun getOldListSize() = oldList.size
override fun getNewListSize() = newList.size
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition].date == newList[newItemPosition].date
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition] == newList[newItemPosition]
}
}
// Extension function for AttendanceData to get comparable date
private fun AttendanceData.getComparableDate(): String {
val parts = date.split("-")
val day = parts[0].toInt()
val month = parts[1].toInt()
val year = parts[2].toInt()
String.format("%04d%02d%02d", year, month, day)
})
notifyDataSetChanged()
}
return String.format("%04d%02d%02d", year, month, day)
}