class SeatCanvasView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null ) : View(context, attrs) { data class Seat( val id: String, val row: Int, val col: Int, val type: String, // "lower" | "upper" val status: String, // "available" | "held" | "booked" | "selected" val fare: Int, val gender: String = "any" ) var seats: List = emptyList() set(value) { field = value; invalidate() } var onSeatClick: ((Seat) -> Unit)? = null private val paintAvailable = Paint().apply { color = Color.parseColor("#EAF3DE"); isAntiAlias = true } private val paintBooked = Paint().apply { color = Color.parseColor("#E8E8E8"); isAntiAlias = true } private val paintSelected = Paint().apply { color = Color.parseColor("#1D6FEB"); isAntiAlias = true } private val paintHeld = Paint().apply { color = Color.parseColor("#FFF3CD"); isAntiAlias = true } private val paintLadies = Paint().apply { color = Color.parseColor("#FBEAF0"); isAntiAlias = true } private val paintText = Paint().apply { color = Color.WHITE; textSize = 28f; textAlign = Paint.Align.CENTER; isAntiAlias = true } private val paintStroke = Paint().apply { style = Paint.Style.STROKE; strokeWidth = 2f; isAntiAlias = true } private val seatW = 90f private val seatH = 70f private val gap = 12f private val aisleW = 50f override fun onDraw(canvas: Canvas) { super.onDraw(canvas) seats.forEach { seat -> val left = calculateX(seat.col) val top = calculateY(seat.row) val rect = RectF(left, top, left + seatW, top + seatH) val paint = when { seat.status == "selected" -> paintSelected seat.status == "booked" -> paintBooked seat.status == "held" -> paintHeld seat.gender == "female" -> paintLadies else -> paintAvailable } paintStroke.color = when { seat.status == "selected" -> Color.parseColor("#0D47A1") seat.status == "booked" -> Color.parseColor("#BDBDBD") else -> Color.parseColor("#66BB6A") } canvas.drawRoundRect(rect, 12f, 12f, paint) canvas.drawRoundRect(rect, 12f, 12f, paintStroke) val textColor = if (seat.status == "selected") Color.WHITE else Color.parseColor("#333333") paintText.color = textColor canvas.drawText(seat.id, left + seatW/2, top + seatH/2 + 10f, paintText) } } private fun calculateX(col: Int): Float { return if (col <= 1) col * (seatW + gap) + gap else col * (seatW + gap) + aisleW + gap } private fun calculateY(row: Int): Float = row * (seatH + gap) + gap override fun onTouchEvent(event: MotionEvent): Boolean { if (event.action != MotionEvent.ACTION_UP) return true seats.forEach { seat -> val left = calculateX(seat.col) val top = calculateY(seat.row) if (event.x in left..(left+seatW) && event.y in top..(top+seatH)) { if (seat.status != "booked" && seat.status != "held") { onSeatClick?.invoke(seat) } } } return true } }