feat(live-reservation-all): 주간 캘린더 라이브러리 제거 및 개별 구현

This commit is contained in:
2025-10-22 12:12:02 +09:00
parent ff236ee6a1
commit dd236d8f19
6 changed files with 157 additions and 117 deletions

View File

@@ -60,7 +60,7 @@ android {
APPLINK_HOST : "voiceon.onelink.me", APPLINK_HOST : "voiceon.onelink.me",
FACEBOOK_APP_ID : "612448298237287", FACEBOOK_APP_ID : "612448298237287",
FACEBOOK_CLIENT_TOKEN: "32af760f4a7b7cb7e3b1e7ffd0b0da70", FACEBOOK_CLIENT_TOKEN: "32af760f4a7b7cb7e3b1e7ffd0b0da70",
KAKAO_APP_KEY: "231cf78acfa8252fca38b9eedf87c5cb" KAKAO_APP_KEY : "231cf78acfa8252fca38b9eedf87c5cb"
] ]
} }
@@ -86,7 +86,7 @@ android {
APPLINK_HOST : "voiceon-test.onelink.me", APPLINK_HOST : "voiceon-test.onelink.me",
FACEBOOK_APP_ID : "608674328645232", FACEBOOK_APP_ID : "608674328645232",
FACEBOOK_CLIENT_TOKEN: "3775e6ea83236a685d264b6c5a1bbb4d", FACEBOOK_CLIENT_TOKEN: "3775e6ea83236a685d264b6c5a1bbb4d",
KAKAO_APP_KEY: "20cf19413d63bfdfd30e8e6dff933d33" KAKAO_APP_KEY : "20cf19413d63bfdfd30e8e6dff933d33"
] ]
} }
} }
@@ -177,8 +177,6 @@ dependencies {
implementation 'com.github.bumptech.glide:glide:5.0.5' implementation 'com.github.bumptech.glide:glide:5.0.5'
annotationProcessor 'com.github.bumptech.glide:compiler:5.0.5' annotationProcessor 'com.github.bumptech.glide:compiler:5.0.5'
implementation "com.michalsvec:single-row-calednar:1.0.0"
// google in-app-purchase // google in-app-purchase
implementation "com.android.billingclient:billing-ktx:6.2.0" implementation "com.android.billingclient:billing-ktx:6.2.0"

View File

@@ -0,0 +1,9 @@
package kr.co.vividnext.sodalive.live.reservation.all
data class DayItem(
val year: Int,
val month: Int, // 0-11
val day: Int,
val dayOfWeek: Int, // Calendar.DAY_OF_WEEK
val epochMillis: Long
)

View File

@@ -5,16 +5,9 @@ import android.content.Intent
import android.graphics.Rect import android.graphics.Rect
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.michalsvec.singlerowcalendar.calendar.CalendarChangesObserver
import com.michalsvec.singlerowcalendar.calendar.CalendarViewManager
import com.michalsvec.singlerowcalendar.calendar.SingleRowCalendarAdapter
import com.michalsvec.singlerowcalendar.selection.CalendarSelectionManager
import com.michalsvec.singlerowcalendar.utils.DateUtils
import kr.co.vividnext.sodalive.R import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.base.BaseActivity import kr.co.vividnext.sodalive.base.BaseActivity
import kr.co.vividnext.sodalive.common.Constants import kr.co.vividnext.sodalive.common.Constants
@@ -46,6 +39,7 @@ class LiveReservationAllActivity : BaseActivity<ActivityLiveReservationAllBindin
private lateinit var loadingDialog: LoadingDialog private lateinit var loadingDialog: LoadingDialog
private lateinit var adapter: LiveReservationAdapter private lateinit var adapter: LiveReservationAdapter
private lateinit var calendarAdapter: WeekCalendarAdapter
private lateinit var selectedDateString: String private lateinit var selectedDateString: String
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@@ -54,109 +48,38 @@ class LiveReservationAllActivity : BaseActivity<ActivityLiveReservationAllBindin
} }
private fun setupCalendar() { private fun setupCalendar() {
val myCalendarViewManager = object : CalendarViewManager { val dates = buildNext7Days()
override fun setCalendarViewResourceId( calendarAdapter = WeekCalendarAdapter(
position: Int, dates = dates,
date: Date, onDateSelected = { dayItem ->
isSelected: Boolean onSelectDate(dayItem)
): Int { },
return if (isSelected) selectedBgRes = R.drawable.bg_round_corner_4_7_3bb9f1
R.layout.item_calendar_selected
else
R.layout.item_calendar
}
override fun bindDataToCalendarView(
holder: SingleRowCalendarAdapter.CalendarViewHolder,
date: Date,
position: Int,
isSelected: Boolean
) {
holder.itemView.findViewById<TextView>(
R.id.tv_date_calendar_item
).text = DateUtils.getDayNumber(date)
val tvDayCalendarItem = holder.itemView.findViewById<TextView>(
R.id.tv_day_calendar_item
) )
tvDayCalendarItem.text = DateUtils.getDay3LettersName(date)
val cal = Calendar.getInstance() binding.rvCalendar.apply {
cal.time = date layoutManager = LinearLayoutManager(
when (cal[Calendar.DAY_OF_WEEK]) {
Calendar.SATURDAY -> tvDayCalendarItem.setTextColor(
ContextCompat.getColor(
applicationContext, applicationContext,
R.color.color_2f90b7 LinearLayoutManager.HORIZONTAL,
false
) )
) this.adapter = calendarAdapter
setHasFixedSize(true)
Calendar.SUNDAY -> tvDayCalendarItem.setTextColor(
ContextCompat.getColor(
applicationContext,
R.color.color_a94400
)
)
else -> tvDayCalendarItem.setTextColor(
ContextCompat.getColor(
applicationContext,
R.color.white
)
)
}
}
} }
// using calendar changes observer we can track changes in calendar onSelectDate(dates.first())
val myCalendarChangesObserver = object : }
CalendarChangesObserver {
// you can override more methods, in this example we need only this one private fun onSelectDate(dayItem: DayItem) {
override fun whenSelectionChanged(isSelected: Boolean, position: Int, date: Date) {
if (isSelected) {
val sdf = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) val sdf = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
selectedDateString = sdf.format(date.time) selectedDateString = sdf.format(Date(dayItem.epochMillis))
calendarAdapter.selectDate(dayItem)
adapter.clear() adapter.clear()
viewModel.page = 1 viewModel.page = 1
viewModel.isLast = false viewModel.isLast = false
viewModel.getLiveReservation(selectedDateString) viewModel.getLiveReservation(selectedDateString)
} }
super.whenSelectionChanged(isSelected, position, date)
}
}
// selection manager is responsible for managing selection
val mySelectionManager = object : CalendarSelectionManager {
override fun canBeItemSelected(position: Int, date: Date): Boolean {
return true
}
}
binding.calendarView.apply {
calendarViewManager = myCalendarViewManager
calendarChangesObserver = myCalendarChangesObserver
calendarSelectionManager = mySelectionManager
setDates(getDates(mutableListOf()))
init()
select(0)
}
}
private fun getDates(list: MutableList<Date>): List<Date> {
// load dates of whole month
val calendar = Calendar.getInstance()
val currentMonth = calendar[Calendar.MONTH]
calendar.set(Calendar.MONTH, currentMonth)
calendar.set(Calendar.DAY_OF_MONTH, calendar[Calendar.DAY_OF_MONTH])
list.add(calendar.time)
for (index in 1..6) {
calendar.add(Calendar.DATE, +1)
list.add(calendar.time)
}
calendar.add(Calendar.DATE, -1)
return list
}
@SuppressLint("NotifyDataSetChanged") @SuppressLint("NotifyDataSetChanged")
override fun setupView() { override fun setupView() {
@@ -362,4 +285,29 @@ class LiveReservationAllActivity : BaseActivity<ActivityLiveReservationAllBindin
} }
) )
} }
private fun buildNext7Days(): List<DayItem> {
val list = ArrayList<DayItem>(7)
val cal = Calendar.getInstance() // device timezone
// "오늘 00:00"로 정규화(선택 비교를 쉽게)
cal.set(Calendar.HOUR_OF_DAY, 0)
cal.set(Calendar.MINUTE, 0)
cal.set(Calendar.SECOND, 0)
cal.set(Calendar.MILLISECOND, 0)
repeat(7) { i ->
if (i > 0) cal.add(Calendar.DAY_OF_MONTH, 1)
list.add(
DayItem(
year = cal.get(Calendar.YEAR),
month = cal.get(Calendar.MONTH), // 0~11
day = cal.get(Calendar.DAY_OF_MONTH),
dayOfWeek = cal.get(Calendar.DAY_OF_WEEK), // 1=일, 7=토
epochMillis = cal.timeInMillis
)
)
}
return list
}
} }

View File

@@ -0,0 +1,89 @@
package kr.co.vividnext.sodalive.live.reservation.all
import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TextView
import androidx.annotation.DrawableRes
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import kr.co.vividnext.sodalive.R
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
class WeekCalendarAdapter(
private val dates: List<DayItem>,
private val onDateSelected: (DayItem) -> Unit,
@DrawableRes private val selectedBgRes: Int
) : RecyclerView.Adapter<WeekCalendarAdapter.DateVH>() {
private var selectedKey: Long? = null // "자정 millis"로 비교
@SuppressLint("NotifyDataSetChanged")
fun selectDate(day: DayItem) {
selectedKey = day.epochMillis
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DateVH {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_calendar, parent, false)
return DateVH(view)
}
override fun onBindViewHolder(holder: DateVH, position: Int) {
val day = dates[position]
holder.bind(
day,
day.epochMillis == selectedKey,
selectedBgRes,
onDateSelected
)
}
override fun getItemCount() = dates.size
class DateVH(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val textDay = itemView.findViewById<TextView>(R.id.tv_day_calendar_item)
private val textDate = itemView.findViewById<TextView>(R.id.tv_date_calendar_item)
private val container = itemView.findViewById<LinearLayout>(R.id.ll_calendar_item)
private val dayFormatter = SimpleDateFormat("EEE", Locale.getDefault())
fun bind(
day: DayItem,
isSelected: Boolean,
@DrawableRes selectedBgRes: Int,
onDateSelected: (DayItem) -> Unit
) {
// 1) 표시 텍스트(요일 약칭, 일자)
val cal = Calendar.getInstance().apply { timeInMillis = day.epochMillis }
textDay.text = dayFormatter.format(cal.time) // 예: Sun, Mon …
textDate.text = day.day.toString()
// 2) 요일별 글자색 (토: 파랑, 일: 빨강, 그 외: 흰색)
val ctx = itemView.context
val color = when (day.dayOfWeek) {
Calendar.SATURDAY -> ContextCompat.getColor(ctx, R.color.color_2f90b7)
Calendar.SUNDAY -> ContextCompat.getColor(ctx, R.color.color_a94400)
else -> ContextCompat.getColor(ctx, R.color.white)
}
textDay.setTextColor(color)
textDate.setTextColor(color)
// 3) 선택 배경
container.background = if (isSelected) {
AppCompatResources.getDrawable(ctx, selectedBgRes)
} else {
null // 또는 ColorDrawable(Color.TRANSPARENT)
}
// 4) 클릭 처리
itemView.setOnClickListener { onDateSelected(day) }
}
}
}

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
@@ -10,16 +9,13 @@
android:id="@+id/toolbar" android:id="@+id/toolbar"
layout="@layout/detail_toolbar" /> layout="@layout/detail_toolbar" />
<com.michalsvec.singlerowcalendar.calendar.SingleRowCalendar <androidx.recyclerview.widget.RecyclerView
android:id="@+id/calendar_view" android:id="@+id/rv_calendar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="20dp" android:layout_marginTop="20dp"
android:clipToPadding="false" android:clipToPadding="false"
android:paddingHorizontal="15.3dp" android:paddingHorizontal="15.3dp" />
app:deselection="false"
app:longPress="false"
app:multiSelection="false" />
<View <View
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -63,10 +59,10 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_medium" android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center" android:gravity="center"
android:lineSpacingExtra="8dp"
android:text="지금 예약중인 라이브가 없습니다.\n다른 날짜의 라이브를 예약하고 참여해 보세요." android:text="지금 예약중인 라이브가 없습니다.\n다른 날짜의 라이브를 예약하고 참여해 보세요."
android:textColor="@color/color_bbbbbb" android:textColor="@color/color_bbbbbb"
android:textSize="13sp" android:textSize="13sp"
android:lineSpacingExtra="8dp"
tools:ignore="SmallSp" /> tools:ignore="SmallSp" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/cl_calendar_item" android:id="@+id/ll_calendar_item"
android:layout_width="53.3dp" android:layout_width="53.3dp"
android:layout_height="66.7dp" android:layout_height="66.7dp"
android:layout_marginHorizontal="6.7dp" android:layout_marginHorizontal="6.7dp"