Skip to content

Commit 9090bf6

Browse files
authored
Merge pull request #189 from simeunseok/feature/#160
체크포인트로 달력 나누는 기능 구현
2 parents 1c76212 + f4bb343 commit 9090bf6

File tree

4 files changed

+150
-85
lines changed

4 files changed

+150
-85
lines changed

app/src/main/java/com/drunkenboys/calendarun/ui/maincalendar/MainCalendarFragment.kt

Lines changed: 77 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,16 @@ class MainCalendarFragment : BaseFragment<FragmentMainCalendarBinding>(R.layout.
3434
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
3535
super.onViewCreated(view, savedInstanceState)
3636

37-
mainCalendarViewModel.fetchCalendarList()
3837
setupCalendarView()
3938
setupDataBinding()
39+
collectScheduleList()
40+
collectCalendarSet()
41+
collectCalendarList()
4042
setupToolbar()
4143
setupMonthCalendar()
4244
collectFabClickEvent()
43-
collectCalendarList()
44-
collectCheckPointList()
45-
collectScheduleList()
4645
collectDaySecondClickListener()
46+
mainCalendarViewModel.fetchCalendarList()
4747
collectCalendarDesignObject()
4848
}
4949

@@ -57,72 +57,6 @@ class MainCalendarFragment : BaseFragment<FragmentMainCalendarBinding>(R.layout.
5757
binding.mainCalendarViewModel = mainCalendarViewModel
5858
}
5959

60-
private fun setupToolbar() {
61-
binding.toolbarMainCalendar.setupWithNavController(navController, binding.layoutDrawer)
62-
setupOnMenuItemClickListener()
63-
setupAddDrawerListener()
64-
}
65-
66-
private fun setupAddDrawerListener() = with(binding) {
67-
val drawerHeaderBinding = DrawerHeaderBinding.bind(navView.getHeaderView(FIRST_HEADER))
68-
layoutDrawer.addDrawerListener(object : DrawerLayout.DrawerListener {
69-
override fun onDrawerSlide(drawerView: View, slideOffset: Float) {
70-
val menuItemOrder = this@MainCalendarFragment.mainCalendarViewModel.menuItemOrder.value
71-
if (binding.navView.menu.isEmpty()) return
72-
binding.navView.menu[menuItemOrder].isChecked = true
73-
drawerHeaderBinding.tvDrawerHeaderTitle.text = binding.navView.menu[menuItemOrder].title
74-
}
75-
76-
override fun onDrawerOpened(drawerView: View) {}
77-
override fun onDrawerClosed(drawerView: View) {}
78-
override fun onDrawerStateChanged(newState: Int) {}
79-
})
80-
}
81-
82-
private fun setupOnMenuItemClickListener() {
83-
binding.toolbarMainCalendar.setOnMenuItemClickListener { item ->
84-
when (item.itemId) {
85-
R.id.menu_main_calendar_calendar -> {
86-
isMonthCalendar = !isMonthCalendar
87-
setupCalendarView()
88-
}
89-
R.id.menu_main_calendar_search -> navigateToSearchSchedule()
90-
else -> return@setOnMenuItemClickListener false
91-
}
92-
true
93-
}
94-
}
95-
96-
private fun navigateToSearchSchedule() {
97-
val action = MainCalendarFragmentDirections.toSearchSchedule()
98-
navController.navigate(action)
99-
}
100-
101-
private fun setupMonthCalendar() {
102-
// TODO: 2021-11-16 이벤트를 발행하는 부분을 xml로 이동시킬 수 있으면 좋을듯
103-
binding.calendarMonth.setOnDaySecondClickListener { date, _ ->
104-
mainCalendarViewModel.emitDaySecondClickEvent(date)
105-
}
106-
}
107-
108-
private fun collectFabClickEvent() {
109-
sharedCollect(mainCalendarViewModel.fabClickEvent) { calendarId ->
110-
val action = MainCalendarFragmentDirections.toSaveSchedule(calendarId, 0)
111-
navController.navigate(action)
112-
}
113-
}
114-
115-
private fun collectCalendarList() {
116-
stateCollect(mainCalendarViewModel.calendarList) { calendarList ->
117-
setupNavigationView(calendarList)
118-
119-
val menuItemOrder = mainCalendarViewModel.menuItemOrder.value
120-
if (calendarList.isEmpty()) return@stateCollect
121-
val calendar = calendarList[menuItemOrder]
122-
mainCalendarViewModel.setCalendar(calendar)
123-
}
124-
}
125-
12660
private fun setupNavigationView(calendarList: List<Calendar>) {
12761
val menu = binding.navView.menu
12862
menu.clear()
@@ -133,7 +67,6 @@ class MainCalendarFragment : BaseFragment<FragmentMainCalendarBinding>(R.layout.
13367
.setCheckable(true)
13468
.setOnMenuItemClickListener {
13569
mainCalendarViewModel.setMenuItemOrder(index)
136-
// TODO: 2021-11-11 item에 맞는 캘린더 뷰로 변경
13770
mainCalendarViewModel.setCalendar(calendar)
13871
binding.layoutDrawer.closeDrawer(GravityCompat.START)
13972
true
@@ -158,6 +91,7 @@ class MainCalendarFragment : BaseFragment<FragmentMainCalendarBinding>(R.layout.
15891
manageMenu.add(getString(R.string.drawer_theme_setting))
15992
.setIcon(R.drawable.ic_palette)
16093
.setOnMenuItemClickListener {
94+
// TODO: 2021-11-11 테마 설정 화면으로 이동
16195
val action = MainCalendarFragmentDirections.toThemeFragment()
16296
navController.navigate(action)
16397
true
@@ -176,19 +110,85 @@ class MainCalendarFragment : BaseFragment<FragmentMainCalendarBinding>(R.layout.
176110
binding.layoutDrawer.closeDrawer(GravityCompat.START)
177111
}
178112

179-
private fun collectCheckPointList() {
180-
stateCollect(mainCalendarViewModel.checkPointList) { checkPointList ->
181-
// TODO: 2021-11-10 CheckPoint 날짜 읽어서 뷰 나누기
182-
}
183-
}
184-
185113
private fun collectScheduleList() {
186114
stateCollect(mainCalendarViewModel.scheduleList) { scheduleList ->
187115
binding.calendarMonth.setSchedules(scheduleList)
188116
binding.calendarYear.setSchedules(scheduleList)
189117
}
190118
}
191119

120+
private fun collectCalendarSet() {
121+
stateCollect(mainCalendarViewModel.calendarSetList) { calendarSetList ->
122+
binding.calendarMonth.setCalendarSetList(calendarSetList)
123+
}
124+
}
125+
126+
private fun collectCalendarList() {
127+
stateCollect(mainCalendarViewModel.calendarList) { calendarList ->
128+
setupNavigationView(calendarList)
129+
130+
val menuItemOrder = mainCalendarViewModel.menuItemOrder.value
131+
if (calendarList.isEmpty()) return@stateCollect
132+
val calendar = calendarList[menuItemOrder]
133+
mainCalendarViewModel.setCalendar(calendar)
134+
}
135+
}
136+
137+
private fun setupToolbar() {
138+
binding.toolbarMainCalendar.setupWithNavController(navController, binding.layoutDrawer)
139+
setupOnMenuItemClickListener()
140+
setupAddDrawerListener()
141+
}
142+
143+
private fun setupAddDrawerListener() = with(binding) {
144+
val drawerHeaderBinding = DrawerHeaderBinding.bind(navView.getHeaderView(FIRST_HEADER))
145+
layoutDrawer.addDrawerListener(object : DrawerLayout.DrawerListener {
146+
override fun onDrawerSlide(drawerView: View, slideOffset: Float) {
147+
val menuItemOrder = this@MainCalendarFragment.mainCalendarViewModel.menuItemOrder.value
148+
if (binding.navView.menu.isEmpty()) return
149+
binding.navView.menu[menuItemOrder].isChecked = true
150+
drawerHeaderBinding.tvDrawerHeaderTitle.text = binding.navView.menu[menuItemOrder].title
151+
}
152+
153+
override fun onDrawerOpened(drawerView: View) {}
154+
override fun onDrawerClosed(drawerView: View) {}
155+
override fun onDrawerStateChanged(newState: Int) {}
156+
})
157+
}
158+
159+
private fun setupOnMenuItemClickListener() {
160+
binding.toolbarMainCalendar.setOnMenuItemClickListener { item ->
161+
when (item.itemId) {
162+
R.id.menu_main_calendar_calendar -> {
163+
isMonthCalendar = !isMonthCalendar
164+
setupCalendarView()
165+
}
166+
R.id.menu_main_calendar_search -> navigateToSearchSchedule()
167+
else -> return@setOnMenuItemClickListener false
168+
}
169+
true
170+
}
171+
}
172+
173+
private fun navigateToSearchSchedule() {
174+
val action = MainCalendarFragmentDirections.toSearchSchedule()
175+
navController.navigate(action)
176+
}
177+
178+
private fun setupMonthCalendar() {
179+
// TODO: 2021-11-16 이벤트를 발행하는 부분을 xml로 이동시킬 수 있으면 좋을듯
180+
binding.calendarMonth.setOnDaySecondClickListener { date, _ ->
181+
mainCalendarViewModel.emitDaySecondClickEvent(date)
182+
}
183+
}
184+
185+
private fun collectFabClickEvent() {
186+
sharedCollect(mainCalendarViewModel.fabClickEvent) { calendarId ->
187+
val action = MainCalendarFragmentDirections.toSaveSchedule(calendarId, 0)
188+
navController.navigate(action)
189+
}
190+
}
191+
192192
private fun collectDaySecondClickListener() {
193193
// TODO: 2021-11-16 현재 flow 확장함수가 StateFlow와 SharedFlow만 받기 때문에 라이프사이클 처리를 명시해주고 있는데 개선이 필요해보임.
194194
viewLifecycleOwner.lifecycleScope.launch {

app/src/main/java/com/drunkenboys/calendarun/ui/maincalendar/MainCalendarViewModel.kt

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,16 @@ import com.drunkenboys.calendarun.data.checkpoint.entity.CheckPoint
99
import com.drunkenboys.calendarun.data.checkpoint.local.CheckPointLocalDataSource
1010
import com.drunkenboys.calendarun.data.schedule.entity.Schedule
1111
import com.drunkenboys.calendarun.data.schedule.local.ScheduleLocalDataSource
12+
import com.drunkenboys.calendarun.util.nextDay
1213
import com.drunkenboys.calendarun.ui.theme.toCalendarDesignObject
1314
import com.drunkenboys.ckscalendar.data.CalendarScheduleObject
15+
import com.drunkenboys.ckscalendar.data.CalendarSet
1416
import dagger.hilt.android.lifecycle.HiltViewModel
17+
import kotlinx.coroutines.Job
18+
import kotlinx.coroutines.flow.MutableSharedFlow
19+
import kotlinx.coroutines.flow.MutableStateFlow
20+
import kotlinx.coroutines.flow.SharedFlow
21+
import kotlinx.coroutines.flow.StateFlow
1522
import kotlinx.coroutines.flow.*
1623
import kotlinx.coroutines.launch
1724
import java.time.LocalDate
@@ -32,11 +39,13 @@ class MainCalendarViewModel @Inject constructor(
3239
val calendarList: StateFlow<List<Calendar>> = _calendarList
3340

3441
private val _checkPointList = MutableStateFlow<List<CheckPoint>>(emptyList())
35-
val checkPointList: StateFlow<List<CheckPoint>> = _checkPointList
3642

3743
private val _scheduleList = MutableStateFlow<List<CalendarScheduleObject>>(emptyList())
3844
val scheduleList: StateFlow<List<CalendarScheduleObject>> = _scheduleList
3945

46+
private val _calendarSetList = MutableStateFlow<List<CalendarSet>>(emptyList())
47+
val calendarSetList: StateFlow<List<CalendarSet>> = _calendarSetList
48+
4049
private val _menuItemOrder = MutableStateFlow(0)
4150
val menuItemOrder: StateFlow<Int> = _menuItemOrder
4251

@@ -49,8 +58,9 @@ class MainCalendarViewModel @Inject constructor(
4958
fun setCalendar(calendar: Calendar) {
5059
viewModelScope.launch {
5160
_calendar.emit(calendar)
52-
fetchCheckPointList(calendar.id)
61+
fetchCheckPointList(calendar.id).join()
5362
fetchScheduleList(calendar.id)
63+
createCalendarSetList()
5464
}
5565
}
5666

@@ -60,9 +70,9 @@ class MainCalendarViewModel @Inject constructor(
6070
}
6171
}
6272

63-
private fun fetchCheckPointList(calendarId: Long) {
64-
viewModelScope.launch {
65-
_checkPointList.emit(checkPointLocalDataSource.fetchCalendarCheckPoints(calendarId))
73+
private fun fetchCheckPointList(calendarId: Long): Job {
74+
return viewModelScope.launch {
75+
_checkPointList.emit(checkPointLocalDataSource.fetchCalendarCheckPoints(calendarId).sortedBy { checkPoint -> checkPoint.date })
6676
}
6777
}
6878

@@ -100,6 +110,57 @@ class MainCalendarViewModel @Inject constructor(
100110
}
101111
}
102112

113+
private fun createCalendarSetList() {
114+
viewModelScope.launch {
115+
val calendarNameList = createCalendarSetNameList() ?: return@launch
116+
val calendarDateList = createCalendarSetDateList() ?: return@launch
117+
val (calendarStartDateList, calendarEndDateList) = calendarDateList.first to calendarDateList.second
118+
119+
val calendarSetList = mutableListOf<CalendarSet>()
120+
121+
for (i in calendarNameList.indices) {
122+
calendarSetList.add(
123+
CalendarSet(
124+
id = i,
125+
name = calendarNameList[i],
126+
startDate = calendarStartDateList[i],
127+
endDate = calendarEndDateList[i]
128+
)
129+
)
130+
}
131+
132+
_calendarSetList.emit(calendarSetList.toList())
133+
}
134+
}
135+
136+
private fun createCalendarSetNameList(): List<String>? {
137+
val calendarName = _calendar.value?.name ?: return null
138+
val checkPointNameList = _checkPointList.value.map { checkPoint -> checkPoint.name }
139+
140+
val calendarSetNameList = mutableListOf<String>()
141+
checkPointNameList.forEach { checkPointName -> calendarSetNameList.add(checkPointName) }
142+
calendarSetNameList.add(calendarName)
143+
144+
return calendarSetNameList
145+
}
146+
147+
private fun createCalendarSetDateList(): Pair<List<LocalDate>, List<LocalDate>>? {
148+
val startDate = _calendar.value?.startDate ?: return null
149+
val endDate = _calendar.value?.endDate ?: return null
150+
val checkPointDateList = _checkPointList.value.map { checkPoint -> checkPoint.date }
151+
val calendarStartDateList = mutableListOf<LocalDate>()
152+
val calendarEndDateList = mutableListOf<LocalDate>()
153+
154+
calendarStartDateList.add(startDate)
155+
if (checkPointDateList.isNotEmpty()) {
156+
calendarStartDateList.addAll(checkPointDateList.map { localDate -> localDate.nextDay() })
157+
calendarEndDateList.addAll(checkPointDateList)
158+
}
159+
calendarEndDateList.add(endDate)
160+
161+
return calendarStartDateList to calendarEndDateList
162+
}
163+
103164
fun fetchCalendarDesignObject() = calendarThemeDataSource.fetchCalendarTheme()
104165
.map { it.toCalendarDesignObject() }
105166
}

app/src/main/java/com/drunkenboys/calendarun/util/DateConverter.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,8 @@ fun stringToLocalDate(date: String): LocalDate =
1212

1313
fun LocalDate?.localDateToString(): String = this?.format(DateTimeFormatter.ofPattern("yyyy.M.d")) ?: ""
1414

15-
fun LocalDate.toLong() = toEpochDay() * 24 * 60 * 60 * 1000
15+
fun LocalDate.toSecondLong() = toEpochDay() * 24 * 60 * 60 * 1000
16+
17+
fun LocalDate.toLong() = toEpochDay()
18+
19+
fun LocalDate.nextDay(): LocalDate = LocalDate.ofEpochDay(toLong() + 1L)

app/src/main/java/com/drunkenboys/calendarun/util/extensions/FragmentExt.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import androidx.lifecycle.Lifecycle
66
import androidx.lifecycle.lifecycleScope
77
import androidx.lifecycle.repeatOnLifecycle
88
import com.drunkenboys.calendarun.R
9-
import com.drunkenboys.calendarun.util.toLong
9+
import com.drunkenboys.calendarun.util.toSecondLong
1010
import com.google.android.material.datepicker.MaterialDatePicker
1111
import com.google.android.material.timepicker.MaterialTimePicker
1212
import com.google.android.material.timepicker.TimeFormat
@@ -27,7 +27,7 @@ fun Fragment.showToast(message: String) {
2727
suspend fun Fragment.pickDateInMillis(localDate: LocalDate? = null) = suspendCancellableCoroutine<Long?> { cont ->
2828
val datePicker = MaterialDatePicker.Builder.datePicker()
2929
.setTitleText(getString(R.string.saveSchedule_pickDate))
30-
.setSelection(localDate?.toLong() ?: MaterialDatePicker.todayInUtcMilliseconds())
30+
.setSelection(localDate?.toSecondLong() ?: MaterialDatePicker.todayInUtcMilliseconds())
3131
.build()
3232
datePicker.apply {
3333
addOnPositiveButtonClickListener { timeInMillis -> cont.resume(timeInMillis) }

0 commit comments

Comments
 (0)