Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[UI/#20] 캘린더뷰 / 주간 캘린더 구현 #33

Merged
merged 16 commits into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,8 @@ package com.terning.core.extension
import java.time.LocalDate

fun LocalDate.getStringAsTitle(): String =
"${year}년 ${monthValue.toString().padStart(2, '0')}월"
"${year}년 ${monthValue.toString().padStart(2, '0')}월"

fun LocalDate.getWeekIndexContainingSelectedDate(): Int = dayOfMonth / 7

fun LocalDate.isToday(): Boolean = this == LocalDate.now()
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.terning.core.designsystem.theme.Grey150
import com.terning.core.designsystem.theme.TerningPointTheme
import com.terning.core.designsystem.theme.TerningTheme
import com.terning.core.extension.isToday
import com.terning.feature.calendar.models.MonthData
import com.terning.feature.calendar.models.Scrap
import com.terning.feature.calendar.models.SelectedDateState
import java.time.LocalDate
import java.time.YearMonth

Expand All @@ -26,7 +27,7 @@ fun CalendarMonth(
modifier: Modifier = Modifier,
monthData: MonthData,
onDateSelected: (LocalDate) -> Unit,
selectedDate: LocalDate,
selectedDate: SelectedDateState,
scrapLists: List<List<Scrap>> = listOf()
) {
Column(
Expand All @@ -48,8 +49,8 @@ fun CalendarMonth(
) {
CalendarDay(
dayData = day,
isSelected = selectedDate == day.date,
isToday = day.date == LocalDate.now(),
isSelected = selectedDate.selectedDate == day.date && selectedDate.isEnabled,
isToday = day.date.isToday(),
onDateSelected = onDateSelected
)
if(!day.isOutDate) {
Expand Down Expand Up @@ -79,7 +80,7 @@ fun CalendarMonthPreview() {
TerningPointTheme {
CalendarMonth(
monthData = MonthData(YearMonth.now()),
selectedDate = LocalDate.now(),
selectedDate = SelectedDateState(LocalDate.now(), true),
onDateSelected = {},
scrapLists = listOf()
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.terning.feature.calendar

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.runtime.Composable
Expand All @@ -11,17 +10,18 @@ import com.terning.feature.calendar.models.CalendarDefaults.flingBehavior
import com.terning.feature.calendar.models.CalendarState.Companion.getDateByPage
import com.terning.feature.calendar.models.MonthData
import com.terning.feature.calendar.models.Scrap
import com.terning.feature.calendar.models.SelectedDateState
import java.time.LocalDate
import java.time.YearMonth

@Composable
fun CalendarMonths(
modifier: Modifier = Modifier,
listState: LazyListState,
onDateSelected: (LocalDate) -> Unit,
pages: Int,
selectedDate: LocalDate,
scrapLists: List<List<Scrap>>
selectedDate: SelectedDateState,
scrapLists: List<List<Scrap>>,
modifier: Modifier = Modifier,
) {
LazyRow(
modifier = modifier
Expand Down
89 changes: 63 additions & 26 deletions feature/src/main/java/com/terning/feature/calendar/CalendarRoute.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package com.terning.feature.calendar

import androidx.activity.compose.BackHandler
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.SizeTransform
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
Expand All @@ -21,14 +26,17 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import com.terning.core.designsystem.theme.Grey200
import com.terning.feature.R
import com.terning.feature.calendar.component.CalendarTopBar
import com.terning.feature.calendar.component.WeekDaysHeader
import com.terning.feature.calendar.models.CalendarState
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.launch
import java.time.LocalDate

@Composable
fun CalendarRoute() {
Expand All @@ -41,34 +49,32 @@ fun CalendarScreen(
viewModel: CalendarViewModel = hiltViewModel()
) {
val selectedDate by viewModel.selectedDate.collectAsState()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

collectAsStateWithLifecycle()로 바꿔주세요!!

val state by remember{ mutableStateOf(CalendarState()) }
val state by remember { mutableStateOf(CalendarState()) }

val listState = rememberLazyListState(
initialFirstVisibleItemIndex = state.getInitialPage()
)

var currentDate by remember { mutableStateOf(selectedDate) }
var currentPage by remember { mutableIntStateOf(listState.firstVisibleItemIndex)}
var currentDate by remember { mutableStateOf(LocalDate.now()) }
var currentPage by remember { mutableIntStateOf(listState.firstVisibleItemIndex) }
Comment on lines +59 to +60
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요거 rememberSaveable로 해야 되나 했는데 저희 서비스는 가로모드 대응 안 하기 때문에 안 바꿔도 될 것 같네용


var isListExpanded by remember { mutableStateOf(false) }
var isWeekEnabled by remember { mutableStateOf(false) }

LaunchedEffect(key1 = listState) {
snapshotFlow { listState.firstVisibleItemIndex }
.distinctUntilChanged()
.collect{
val swipeDirection = (listState.firstVisibleItemIndex - currentPage).coerceIn(-1, 1).toLong()
.collect {
val swipeDirection =
(listState.firstVisibleItemIndex - currentPage).coerceIn(-1, 1).toLong()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오!! coerceIn() 처음 보는 것 같은데!! 새로운거 알아갑니당ㅎㅎ

currentDate = currentDate.plusMonths(swipeDirection)
currentPage = listState.firstVisibleItemIndex
}
}

LaunchedEffect(key1 = selectedDate) {
isWeekEnabled = true
}

BackHandler {
isWeekEnabled = false
if (selectedDate.isEnabled) {
viewModel.updateSelectedDate(selectedDate.selectedDate)
}
}

Scaffold(
Expand All @@ -91,26 +97,57 @@ fun CalendarScreen(
) { paddingValues ->
Column(
modifier = Modifier
.fillMaxWidth()
.fillMaxSize()
.padding(top = paddingValues.calculateTopPadding())
) {
WeekDaysHeader()
Spacer(modifier = Modifier
.fillMaxWidth()
.height(1.dp)
.background(color = Grey200)
Spacer(
modifier = Modifier
.fillMaxWidth()
.height(1.dp)
.background(color = Grey200)
)
CalendarMonths(
modifier = Modifier.fillMaxSize(),
selectedDate = selectedDate,
onDateSelected = {
viewModel.updateSelectedDate(it)

AnimatedContent(
targetState = selectedDate.isEnabled,
transitionSpec = {
if (!targetState) {
slideInVertically { fullHeight -> -fullHeight } togetherWith
slideOutVertically { fullHeight -> fullHeight }
} else {
slideInVertically { fullHeight -> fullHeight } togetherWith
slideOutVertically { fullHeight -> -fullHeight }
}.using(
sizeTransform = SizeTransform(clip = true)
)
},
listState = listState,
pages = state.getPageCount(),
scrapLists = viewModel.mockScrapList
)
label = stringResource(id = R.string.calendar_animation_label)
) { targetState ->
if (!targetState) {
CalendarMonths(
modifier = Modifier.fillMaxSize(),
selectedDate = selectedDate,
onDateSelected = {
viewModel.updateSelectedDate(it)
},
listState = listState,
pages = state.getPageCount(),
scrapLists = viewModel.mockScrapList,
)
} else {
CalendarWeekWithScrap(
modifier = Modifier
.fillMaxSize(),
selectedDate = selectedDate,
scrapLists = viewModel.mockScrapList,
onDateSelected = {
viewModel.updateSelectedDate(it)
}
)
}
}
}

}
}


Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import com.terning.core.designsystem.theme.CalPurple
import com.terning.core.designsystem.theme.CalRed
import com.terning.core.designsystem.theme.CalYellow
import com.terning.feature.calendar.models.Scrap
import com.terning.feature.calendar.models.SelectedDateState
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
Expand All @@ -21,12 +22,29 @@ import javax.inject.Inject
@HiltViewModel
class CalendarViewModel @Inject constructor(
) : ViewModel() {
private val _selectedDate = MutableStateFlow<LocalDate>(LocalDate.now())
private val _selectedDate = MutableStateFlow<SelectedDateState>(
SelectedDateState(
selectedDate = LocalDate.now(),
isEnabled = false
)
)
val selectedDate get() = _selectedDate.asStateFlow()

fun updateSelectedDate(date: LocalDate) = viewModelScope.launch {
if (_selectedDate.value != date) {
_selectedDate.value = date
if (_selectedDate.value.selectedDate != date) {
_selectedDate.update { currentState ->
currentState.copy(
selectedDate = date,
isEnabled = true
)
}
Comment on lines +35 to +40
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update라는 속성을 사용했을 때의 이점이 궁금해졌어요..!

} else {
_selectedDate.update { currentState ->
currentState.copy(
selectedDate = date,
isEnabled = !_selectedDate.value.isEnabled
)
}
}
}

Expand Down Expand Up @@ -61,18 +79,21 @@ class CalendarViewModel @Inject constructor(
)
)
}

3 -> {
list.add(
i,
listOf()
)
}

4 -> {
list.add(
i,
listOf()
)
}

5 -> {
list.add(
i,
Expand Down
54 changes: 54 additions & 0 deletions feature/src/main/java/com/terning/feature/calendar/CalendarWeek.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.terning.feature.calendar

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.terning.core.extension.getWeekIndexContainingSelectedDate
import com.terning.core.extension.isToday
import com.terning.feature.calendar.models.MonthData
import com.terning.feature.calendar.models.SelectedDateState
import java.time.LocalDate
import java.time.YearMonth

@Composable
fun CalendarWeek(
modifier: Modifier = Modifier,
selectedDate: SelectedDateState,
onDateSelected: (LocalDate) -> Unit = {}
) {
val date = selectedDate.selectedDate
val monthData = MonthData(YearMonth.of(date.year, date.monthValue))
val currentWeek = date.getWeekIndexContainingSelectedDate()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getWeekIndexContainingSelectedDate라는게 있군요,,,,,캘린더란,,,,,,,,


val pagerState = rememberPagerState (
initialPage = currentWeek,
pageCount = {monthData.totalDays / 7}
)

HorizontalPager(
modifier = modifier,
state = pagerState) { page ->
LazyRow(
modifier = Modifier
.fillMaxWidth()
.padding(20.dp),
horizontalArrangement = Arrangement.SpaceBetween
) {
items(items = monthData.calendarMonth.weekDays[page]) { day ->
CalendarDay(
dayData = day,
isSelected = selectedDate.selectedDate == day.date && selectedDate.isEnabled,
isToday = day.date.isToday(),
onDateSelected = onDateSelected
)
}
}
}
}
Loading
Loading