Skip to content

Commit fec7a5c

Browse files
authored
[MERGE] #305 -> develop
[UI/#305] ์บ˜๋ฆฐํ„ฐ ํ„ฐ์น˜ ์˜์—ญ ์ˆ˜์ •
2 parents 1a90ef2 + 2743ab1 commit fec7a5c

28 files changed

+1036
-674
lines changed
Lines changed: 145 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,37 @@
11
package com.terning.feature.calendar.calendar
22

3+
import androidx.compose.animation.core.Transition
34
import androidx.compose.animation.core.tween
5+
import androidx.compose.animation.core.updateTransition
46
import androidx.compose.animation.slideInHorizontally
57
import androidx.compose.animation.slideInVertically
68
import androidx.compose.animation.slideOutHorizontally
79
import androidx.compose.animation.slideOutVertically
810
import androidx.compose.animation.togetherWith
9-
import androidx.compose.foundation.background
1011
import androidx.compose.foundation.layout.Column
1112
import androidx.compose.foundation.layout.fillMaxSize
13+
import androidx.compose.foundation.pager.PagerState
1214
import androidx.compose.foundation.pager.rememberPagerState
1315
import androidx.compose.material3.HorizontalDivider
1416
import androidx.compose.runtime.Composable
15-
import androidx.compose.runtime.CompositionLocalProvider
1617
import androidx.compose.runtime.LaunchedEffect
1718
import androidx.compose.runtime.getValue
1819
import androidx.compose.runtime.rememberCoroutineScope
1920
import androidx.compose.runtime.snapshotFlow
2021
import androidx.compose.ui.Modifier
2122
import androidx.compose.ui.unit.dp
2223
import androidx.hilt.navigation.compose.hiltViewModel
23-
import androidx.lifecycle.compose.LocalLifecycleOwner
2424
import androidx.lifecycle.compose.collectAsStateWithLifecycle
2525
import com.terning.core.analytics.EventType
2626
import com.terning.core.analytics.LocalTracker
2727
import com.terning.core.designsystem.component.topappbar.CalendarTopAppBar
28+
import com.terning.core.designsystem.extension.getWeekIndexContainingSelectedDate
2829
import com.terning.core.designsystem.theme.Grey200
29-
import com.terning.core.designsystem.theme.White
3030
import com.terning.feature.calendar.calendar.component.ScreenTransition
3131
import com.terning.feature.calendar.calendar.component.WeekDaysHeader
32-
import com.terning.feature.calendar.calendar.model.CalendarModel.Companion.getLocalDateByPage
33-
import com.terning.feature.calendar.calendar.model.CalendarModel.Companion.getYearMonthByPage
3432
import com.terning.feature.calendar.calendar.model.CalendarUiState
35-
import com.terning.feature.calendar.calendar.model.LocalPagerState
33+
import com.terning.feature.calendar.calendar.model.DayModel
34+
import com.terning.feature.calendar.calendar.model.TerningCalendarModel
3635
import com.terning.feature.calendar.list.CalendarListRoute
3736
import com.terning.feature.calendar.month.CalendarMonthRoute
3837
import com.terning.feature.calendar.week.CalendarWeekRoute
@@ -45,12 +44,10 @@ fun CalendarRoute(
4544
modifier: Modifier = Modifier,
4645
viewModel: CalendarViewModel = hiltViewModel()
4746
) {
48-
val lifecycleOwner = LocalLifecycleOwner.current
49-
val uiState by viewModel.uiState.collectAsStateWithLifecycle(lifecycleOwner = lifecycleOwner)
47+
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
5048
val amplitudeTracker = LocalTracker.current
5149

5250
CalendarScreen(
53-
modifier = modifier,
5451
uiState = uiState,
5552
navigateToAnnouncement = navigateToAnnouncement,
5653
onClickNewDate = viewModel::onSelectNewDate,
@@ -65,23 +62,29 @@ fun CalendarRoute(
6562
)
6663
}
6764
viewModel.updateListVisibility(!uiState.isListEnabled)
68-
}
65+
},
66+
modifier = modifier,
6967
)
7068
}
7169

7270
@Composable
7371
private fun CalendarScreen(
7472
uiState: CalendarUiState,
7573
navigateToAnnouncement: (Long) -> Unit,
76-
onClickNewDate: (LocalDate) -> Unit,
77-
updateSelectedDate: (LocalDate) -> Unit,
74+
onClickNewDate: (DayModel) -> Unit,
75+
updateSelectedDate: (DayModel) -> Unit,
7876
disableListVisibility: () -> Unit,
7977
disableWeekVisibility: () -> Unit,
8078
onClickListButton: () -> Unit,
8179
modifier: Modifier = Modifier,
8280
) {
8381
val coroutineScope = rememberCoroutineScope()
8482

83+
val calendarListTransition =
84+
updateTransition(!uiState.isListEnabled, label = "calendarListTransition")
85+
val monthWeekTransition =
86+
updateTransition(!uiState.isWeekEnabled, label = "monthWeekTransition")
87+
8588
val pagerState = rememberPagerState(
8689
initialPage = uiState.calendarModel.initialPage,
8790
pageCount = { uiState.calendarModel.pageCount }
@@ -90,95 +93,148 @@ private fun CalendarScreen(
9093
LaunchedEffect(key1 = pagerState, key2 = uiState.selectedDate) {
9194
snapshotFlow { pagerState.currentPage }
9295
.collect { current ->
93-
val date = getLocalDateByPage(current)
96+
val date = uiState.calendarModel.getLocalDateByPage(current)
97+
val month = uiState.calendarModel.getMonthModelByPage(current)
9498

9599
val newDate = LocalDate.of(
96100
date.year,
97101
date.month,
98-
uiState.selectedDate.dayOfMonth.coerceAtMost(date.month.minLength())
102+
uiState.selectedDate.date.dayOfMonth.coerceAtMost(date.month.minLength())
99103
)
100-
updateSelectedDate(newDate)
104+
105+
val currentWeek = newDate.getWeekIndexContainingSelectedDate(month.inDays)
106+
updateSelectedDate(DayModel(newDate, currentWeek))
101107
}
102108
}
103109

104-
CompositionLocalProvider(
105-
LocalPagerState provides pagerState
110+
111+
Column(
112+
modifier = modifier,
106113
) {
107-
Column(
108-
modifier = modifier,
109-
) {
110-
CalendarTopAppBar(
111-
date = getYearMonthByPage(pagerState.settledPage),
112-
isListExpanded = uiState.isListEnabled,
113-
onListButtonClicked = onClickListButton,
114-
onMonthNavigationButtonClicked = { direction ->
115-
coroutineScope.launch {
116-
pagerState.animateScrollToPage(
117-
page = pagerState.settledPage + direction,
118-
animationSpec = tween(500)
119-
)
120-
}
114+
CalendarTopAppBar(
115+
date = uiState.calendarModel.getYearMonthByPage(pagerState.settledPage),
116+
isListExpanded = uiState.isListEnabled,
117+
onListButtonClicked = {
118+
if(!calendarListTransition.isRunning)
119+
onClickListButton()
120+
},
121+
onMonthNavigationButtonClicked = { direction ->
122+
coroutineScope.launch {
123+
pagerState.animateScrollToPage(
124+
page = pagerState.settledPage + direction,
125+
animationSpec = tween(500)
126+
)
121127
}
122-
)
123-
ScreenTransition(
124-
targetState = !uiState.isListEnabled,
125-
transitionOne = slideInHorizontally { fullWidth -> -fullWidth } togetherWith
126-
slideOutHorizontally { fullWidth -> fullWidth },
127-
transitionTwo = slideInHorizontally { fullWidth -> fullWidth } togetherWith
128-
slideOutHorizontally { fullWidth -> -fullWidth },
129-
contentOne = {
130-
Column(
131-
modifier = Modifier
132-
.fillMaxSize()
133-
) {
134-
WeekDaysHeader()
135-
136-
HorizontalDivider(
137-
thickness = 1.dp,
138-
color = Grey200
139-
)
140-
141-
ScreenTransition(
142-
targetState = !uiState.isWeekEnabled,
143-
transitionOne = slideInVertically { fullHeight -> -fullHeight } togetherWith
144-
slideOutVertically { fullHeight -> fullHeight },
145-
transitionTwo = slideInVertically { fullHeight -> fullHeight } togetherWith
146-
slideOutVertically { fullHeight -> -fullHeight },
147-
contentOne = {
148-
CalendarMonthRoute(
149-
selectedDate = uiState.selectedDate,
150-
updateSelectedDate = { newDate ->
151-
if (!pagerState.isScrollInProgress)
152-
onClickNewDate(newDate)
153-
},
154-
modifier = Modifier
155-
.fillMaxSize()
156-
.background(White),
157-
)
158-
},
159-
contentTwo = {
160-
CalendarWeekRoute(
161-
calendarUiState = uiState,
162-
modifier = Modifier
163-
.fillMaxSize(),
164-
navigateUp = disableWeekVisibility,
165-
navigateToAnnouncement = navigateToAnnouncement,
166-
updateSelectedDate = onClickNewDate
167-
)
168-
}
169-
)
170-
}
171-
},
172-
contentTwo = {
173-
CalendarListRoute(
174-
navigateToAnnouncement = navigateToAnnouncement,
175-
navigateUp = disableListVisibility,
176-
modifier = Modifier
177-
.fillMaxSize()
128+
}
129+
)
130+
131+
CalendarListTransition(
132+
transition = calendarListTransition,
133+
calendarModel = uiState.calendarModel,
134+
pagerState = pagerState,
135+
onNavigateToAnnouncement = navigateToAnnouncement,
136+
onNavigateUpToCalendar = disableListVisibility,
137+
calendarContent = {
138+
Column(
139+
modifier = Modifier
140+
.fillMaxSize()
141+
) {
142+
WeekDaysHeader()
143+
144+
HorizontalDivider(
145+
thickness = 1.dp,
146+
color = Grey200
178147
)
148+
149+
MonthWeekTransition(
150+
transition = monthWeekTransition,
151+
selectedDate = uiState.selectedDate,
152+
calendarModel = uiState.calendarModel,
153+
pagerState = pagerState,
154+
onSelectDate = { newDate -> onClickNewDate(newDate) },
155+
onNavigateToAnnouncement = navigateToAnnouncement,
156+
onNavigateUpToMonth = disableWeekVisibility
157+
)
158+
}
159+
}
160+
)
161+
}
162+
}
163+
164+
165+
/** ๋‹ฌ๋ ฅ <-> ๋ชฉ๋ก ์ „ํ™˜ ์ปดํฌ์ €๋ธ” */
166+
@Composable
167+
private fun CalendarListTransition(
168+
transition: Transition<Boolean>,
169+
calendarModel: TerningCalendarModel,
170+
pagerState: PagerState,
171+
onNavigateToAnnouncement: (Long) -> Unit,
172+
onNavigateUpToCalendar: () -> Unit,
173+
calendarContent: @Composable () -> Unit,
174+
) {
175+
ScreenTransition(
176+
transition = transition,
177+
transitionOne = slideInHorizontally { fullWidth -> -fullWidth } togetherWith
178+
slideOutHorizontally { fullWidth -> fullWidth },
179+
transitionTwo = slideInHorizontally { fullWidth -> fullWidth } togetherWith
180+
slideOutHorizontally { fullWidth -> -fullWidth },
181+
contentOne = {
182+
calendarContent()
183+
},
184+
contentTwo = {
185+
CalendarListRoute(
186+
calendarModel = calendarModel,
187+
navigateToAnnouncement = onNavigateToAnnouncement,
188+
navigateUp = onNavigateUpToCalendar,
189+
pagerState = pagerState,
190+
modifier = Modifier
191+
.fillMaxSize()
192+
)
193+
},
194+
)
195+
}
196+
197+
/**์›”๊ฐ„ <-> ์ฃผ๊ฐ„ ์ „ํ™˜ ์ปดํฌ์ €๋ธ”*/
198+
@Composable
199+
private fun MonthWeekTransition(
200+
transition: Transition<Boolean>,
201+
selectedDate: DayModel,
202+
calendarModel: TerningCalendarModel,
203+
pagerState: PagerState,
204+
onSelectDate: (DayModel) -> Unit,
205+
onNavigateToAnnouncement: (Long) -> Unit,
206+
onNavigateUpToMonth: () -> Unit,
207+
) {
208+
ScreenTransition(
209+
transition = transition,
210+
transitionOne = slideInVertically { fullHeight -> -fullHeight } togetherWith
211+
slideOutVertically { fullHeight -> fullHeight },
212+
transitionTwo = slideInVertically { fullHeight -> fullHeight } togetherWith
213+
slideOutVertically { fullHeight -> -fullHeight },
214+
contentOne = {
215+
CalendarMonthRoute(
216+
selectedDate = selectedDate,
217+
updateSelectedDate = { newDate ->
218+
if (!pagerState.isScrollInProgress)
219+
onSelectDate(newDate)
179220
},
221+
pagerState = pagerState,
222+
calendarModel = calendarModel
223+
)
224+
},
225+
contentTwo = {
226+
CalendarWeekRoute(
227+
modifier = Modifier
228+
.fillMaxSize(),
229+
navigateUp = onNavigateUpToMonth,
230+
navigateToAnnouncement = onNavigateToAnnouncement,
231+
updateSelectedDate = onSelectDate,
232+
selectedDate = selectedDate,
233+
calendarModel = calendarModel,
234+
pagerState = pagerState,
180235
)
181236
}
182-
}
237+
)
183238
}
184239

240+
Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,22 @@
11
package com.terning.feature.calendar.calendar
22

33
import androidx.lifecycle.ViewModel
4-
import androidx.lifecycle.viewModelScope
54
import com.terning.feature.calendar.calendar.model.CalendarUiState
5+
import com.terning.feature.calendar.calendar.model.DayModel
66
import dagger.hilt.android.lifecycle.HiltViewModel
77
import kotlinx.coroutines.flow.MutableStateFlow
88
import kotlinx.coroutines.flow.asStateFlow
99
import kotlinx.coroutines.flow.update
10-
import kotlinx.coroutines.launch
11-
import java.time.LocalDate
1210
import javax.inject.Inject
1311

1412
@HiltViewModel
1513
class CalendarViewModel @Inject constructor() : ViewModel() {
1614
private var _uiState: MutableStateFlow<CalendarUiState> = MutableStateFlow(CalendarUiState())
1715
val uiState get() = _uiState.asStateFlow()
1816

19-
fun onSelectNewDate(selectedDate: LocalDate) = viewModelScope.launch {
20-
if (_uiState.value.selectedDate == selectedDate) {
21-
_uiState.update { currentState ->
22-
currentState.copy(
23-
isWeekEnabled = !_uiState.value.isWeekEnabled
24-
)
25-
}
17+
fun onSelectNewDate(selectedDate: DayModel) {
18+
if (_uiState.value.selectedDate.date == selectedDate.date) {
19+
updateWeekVisibility(!_uiState.value.isWeekEnabled)
2620
} else {
2721
_uiState.update { currentState ->
2822
currentState.copy(
@@ -33,27 +27,23 @@ class CalendarViewModel @Inject constructor() : ViewModel() {
3327
}
3428
}
3529

36-
fun updateSelectedDate(date: LocalDate) = viewModelScope.launch {
37-
_uiState.update { currentState ->
30+
fun updateSelectedDate(value: DayModel) = _uiState.update { currentState ->
3831
currentState.copy(
39-
selectedDate = date
32+
selectedDate = value
4033
)
4134
}
42-
}
4335

44-
fun updateListVisibility(visibility: Boolean) = viewModelScope.launch {
45-
_uiState.update { currentState ->
36+
37+
fun updateListVisibility(value: Boolean) = _uiState.update { currentState ->
4638
currentState.copy(
47-
isListEnabled = visibility
39+
isListEnabled = value
4840
)
4941
}
50-
}
5142

52-
fun updateWeekVisibility(visibility: Boolean) = viewModelScope.launch {
53-
_uiState.update { currentState ->
43+
44+
fun updateWeekVisibility(value: Boolean) = _uiState.update { currentState ->
5445
currentState.copy(
55-
isWeekEnabled = visibility
46+
isWeekEnabled = value
5647
)
5748
}
58-
}
5949
}

0 commit comments

Comments
ย (0)