Files
ShiftRing/app/src/main/java/com/example/shiftalarm/CalendarAdapter.kt
T

253 lines
11 KiB
Kotlin

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<DayShift>,
private val listener: OnDayClickListener,
var showHolidays: Boolean = true
) : RecyclerView.Adapter<CalendarAdapter.ViewHolder>() {
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
}