package com.example.shiftalarm import android.content.Context import android.content.res.ColorStateList import android.graphics.Color import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.ImageView import android.widget.TextView import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView import java.time.LocalDate data class DayShift( val date: LocalDate?, val shift: String?, val hasMemo: Boolean = false, val memoContent: String? = null ) class CalendarAdapter( var days: List, private val listener: OnDayClickListener, var showHolidays: Boolean = true ) : RecyclerView.Adapter() { var rowHeight: Int = 0 interface OnDayClickListener { fun onDayClick(date: LocalDate, currentShift: String) } class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { val root: View = view.findViewById(R.id.dayRoot) val dayNumber: TextView = view.findViewById(R.id.dayNumber) val tvShiftSmall: TextView = view.findViewById(R.id.tvShiftSmall) val shiftChar: TextView = view.findViewById(R.id.shiftChar) val holidayNameSmall: TextView = view.findViewById(R.id.holidayNameSmall) val tvTide: TextView = view.findViewById(R.id.tvTide) val memoContent: TextView = view.findViewById(R.id.memoContent) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.item_day, parent, false) return ViewHolder(view) } private fun dpToPx(context: Context, dp: Float): Int { return (dp * context.resources.displayMetrics.density).toInt() } override fun onBindViewHolder(holder: ViewHolder, position: Int) { // Dynamic row height: fit exactly 5 rows, 6th row scrolls if (rowHeight > 0) { holder.itemView.layoutParams.height = rowHeight } val item = days[position] val context = holder.itemView.context if (item.date == null) { holder.itemView.visibility = View.INVISIBLE return } holder.itemView.visibility = View.VISIBLE // Day Number holder.dayNumber.text = item.date.dayOfMonth.toString() // Holiday / Weekend logic val isSunday = item.date.dayOfWeek == java.time.DayOfWeek.SUNDAY val isSaturday = item.date.dayOfWeek == java.time.DayOfWeek.SATURDAY val fullHolidayName = HolidayManager.getHolidayName(item.date) val isToday = item.date == LocalDate.now() val hasMemo = item.hasMemo && !item.memoContent.isNullOrEmpty() // Day Number Color if (fullHolidayName != null || isSunday) { holder.dayNumber.setTextColor(Color.parseColor("#FF5252")) } else if (isSaturday) { holder.dayNumber.setTextColor(Color.parseColor("#448AFF")) } else { holder.dayNumber.setTextColor(ContextCompat.getColor(context, R.color.text_primary)) } // Tide Display val prefs = context.getSharedPreferences("ShiftAlarmPrefs", Context.MODE_PRIVATE) val showTide = prefs.getBoolean("show_tide", false) val tideLocation = prefs.getString("selected_tide_location", "군산") ?: "군산" if (showTide) { val tide = HolidayManager.getTide(item.date, tideLocation) if (tide.isNotEmpty()) { holder.tvTide.visibility = View.VISIBLE holder.tvTide.text = tide } else { holder.tvTide.visibility = View.GONE } } else { holder.tvTide.visibility = View.GONE } // --- Shift & Holiday Display Logic --- holder.shiftChar.background = null holder.shiftChar.text = "" holder.tvShiftSmall.visibility = View.GONE holder.holidayNameSmall.visibility = View.GONE holder.shiftChar.textSize = 18f if (showHolidays && fullHolidayName != null) { // Holiday Mode (Priority): Show full holiday name, no circle holder.shiftChar.text = fullHolidayName holder.shiftChar.setTextColor(Color.parseColor("#FF5252")) holder.shiftChar.textSize = 13f holder.shiftChar.background = null holder.shiftChar.visibility = View.VISIBLE } else if (item.shift != null && item.shift != "비번") { // Shift Mode val shiftAbbreviation = when (item.shift) { "주간" -> "주" "석간" -> "석" "야간" -> "야" "주간 맞교대" -> "주맞" "야간 맞교대" -> "야맞" "휴무", "휴가" -> "휴" "월차" -> "월" "연차" -> "연" "반월" -> "월" "반년" -> "년" "교육" -> "교" else -> item.shift.take(2) } val shiftColorRes = when (item.shift) { "주간" -> R.color.shift_lemon "석간" -> R.color.shift_seok "야간" -> R.color.shift_ya "주간 맞교대" -> R.color.shift_jumat "야간 맞교대" -> R.color.shift_yamat "휴무", "휴가", "월차", "연차" -> R.color.shift_red "반월", "반년" -> R.color.shift_red "교육" -> R.color.primary else -> R.color.text_secondary } val shiftColor = ContextCompat.getColor(context, shiftColorRes) if (hasMemo) { // When day has a memo: show small shift badge next to day number, hide large center shift circle holder.shiftChar.visibility = View.GONE holder.tvShiftSmall.visibility = View.VISIBLE holder.tvShiftSmall.text = shiftAbbreviation holder.tvShiftSmall.textSize = if (shiftAbbreviation.length > 1) 7.5f else 9.5f holder.tvShiftSmall.setTypeface(null, android.graphics.Typeface.BOLD) if (item.shift == "반월" || item.shift == "반년") { holder.tvShiftSmall.text = if (item.shift == "반월") "월" else "년" holder.tvShiftSmall.setTextColor(ContextCompat.getColor(context, R.color.black)) holder.tvShiftSmall.background = ContextCompat.getDrawable(context, R.drawable.bg_shift_half_red) } else if (isToday) { val smallBg = ContextCompat.getDrawable(context, R.drawable.bg_shift_solid_v4)?.constantState?.newDrawable()?.mutate() as? android.graphics.drawable.GradientDrawable smallBg?.setColor(shiftColor) holder.tvShiftSmall.background = smallBg holder.tvShiftSmall.setTextColor(if (item.shift == "주간" || item.shift == "석간") ContextCompat.getColor(context, R.color.black) else Color.WHITE) } else { val smallBg = ContextCompat.getDrawable(context, R.drawable.bg_shift_stroke_v4)?.constantState?.newDrawable()?.mutate() as? android.graphics.drawable.GradientDrawable smallBg?.setStroke(dpToPx(context, 1.2f), shiftColor) smallBg?.setColor(Color.TRANSPARENT) holder.tvShiftSmall.background = smallBg holder.tvShiftSmall.setTextColor(shiftColor) } } else { // When day has NO memo: standard large centered shift circle holder.shiftChar.visibility = View.VISIBLE holder.tvShiftSmall.visibility = View.GONE if (item.shift == "반월" || item.shift == "반년") { holder.shiftChar.text = if (item.shift == "반월") "월" else "년" holder.shiftChar.setTextColor(ContextCompat.getColor(context, R.color.black)) holder.shiftChar.textSize = 18f holder.shiftChar.background = ContextCompat.getDrawable(context, R.drawable.bg_shift_half_red) } else { holder.shiftChar.text = shiftAbbreviation holder.shiftChar.textSize = 20f holder.shiftChar.setTypeface(null, android.graphics.Typeface.BOLD) if (isToday) { // Today: Solid Circle val background = ContextCompat.getDrawable(context, R.drawable.bg_shift_solid_v4) as? android.graphics.drawable.GradientDrawable background?.setColor(shiftColor) holder.shiftChar.background = background holder.shiftChar.backgroundTintList = null if (item.shift == "주간" || item.shift == "석간") { holder.shiftChar.setTextColor(ContextCompat.getColor(context, R.color.black)) } else { holder.shiftChar.setTextColor(Color.WHITE) } } else { // Not Today: Stroke Circle val background = ContextCompat.getDrawable(context, R.drawable.bg_shift_stroke_v4) as? android.graphics.drawable.GradientDrawable background?.setStroke(dpToPx(context, 1.5f), shiftColor) background?.setColor(Color.TRANSPARENT) holder.shiftChar.background = background holder.shiftChar.backgroundTintList = null holder.shiftChar.setTextColor(shiftColor) } } } } // Lunar date small display if requested or just default if (!showHolidays && fullHolidayName != null) { holder.holidayNameSmall.visibility = View.VISIBLE holder.holidayNameSmall.text = fullHolidayName } else { holder.holidayNameSmall.visibility = View.GONE } if (showHolidays && fullHolidayName == null) { holder.shiftChar.text = HolidayManager.getLunarDateString(item.date) holder.shiftChar.textSize = 13f holder.shiftChar.setTextColor(ContextCompat.getColor(context, R.color.text_tertiary)) holder.shiftChar.background = null holder.shiftChar.visibility = View.VISIBLE } // Memo Content Text (Up to 4 lines in center of day cell) if (hasMemo) { holder.memoContent.visibility = View.VISIBLE holder.memoContent.text = item.memoContent } else { holder.memoContent.visibility = View.GONE } // Today Border or Highlight if (isToday) { holder.root.setBackgroundResource(R.drawable.bg_grid_cell_today_v4) } else { holder.root.setBackgroundResource(R.drawable.bg_grid_cell_v4) } holder.itemView.setOnClickListener { if (item.date != null && item.shift != null) { listener.onDayClick(item.date, item.shift) } } } override fun getItemCount(): Int = days.size }