253 lines
11 KiB
Kotlin
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
|
|
}
|