-
Notifications
You must be signed in to change notification settings - Fork 0
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
[TNT-180] 트레이니 주간 캘린더 연동 #67
Changes from 1 commit
73366b9
ff636c5
7e60275
63b34b4
1b8ba68
ed3afe6
56ee465
d47807d
a468017
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<vector xmlns:android="http://schemas.android.com/apk/res/android" | ||
android:width="24dp" | ||
android:height="24dp" | ||
android:viewportWidth="24" | ||
android:viewportHeight="24"> | ||
<path | ||
android:pathData="M5.202,17.5H18.798C19.844,17.5 20.551,16.434 20.146,15.471L19.701,14.415C19.238,13.316 19,12.136 19,10.944V9C19,5.134 15.866,2 12,2C8.134,2 5,5.134 5,9V10.944C5,12.136 4.762,13.316 4.299,14.415L3.854,15.471C3.449,16.434 4.156,17.5 5.202,17.5Z" | ||
android:strokeWidth="2" | ||
android:fillColor="#00000000" | ||
android:strokeColor="#262626"/> | ||
<path | ||
android:pathData="M9,18C9,18 9,21 12,21C15,21 15,18 15,18" | ||
android:strokeLineJoin="round" | ||
android:strokeWidth="2" | ||
android:fillColor="#00000000" | ||
android:strokeColor="#262626" | ||
android:strokeLineCap="round"/> | ||
</vector> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package co.kr.tnt.domain.model | ||
|
||
import java.time.LocalDate | ||
|
||
data class RecordList( | ||
val recordDate: LocalDate, | ||
val recordType: RecordType, | ||
val recordTime: String, | ||
val recordImage: String?, | ||
val recordContents: String, | ||
val hasFeedback: Boolean, | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,4 +10,5 @@ android { | |
|
||
dependencies { | ||
implementation(libs.kotlinx.immutable) | ||
implementation(libs.calendar.compose) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package co.kr.tnt.trainee.home | ||
|
||
import co.kr.tnt.domain.model.RecordList | ||
import co.kr.tnt.ui.base.UiEvent | ||
import co.kr.tnt.ui.base.UiSideEffect | ||
import co.kr.tnt.ui.base.UiState | ||
import java.time.LocalDate | ||
import java.time.YearMonth | ||
|
||
class TraineeHomeContract { | ||
data class TraineeHomeUiState( | ||
val visibleYearMonth: YearMonth = YearMonth.now(), | ||
val selectedDate: LocalDate = LocalDate.now(), | ||
val markedDates: List<LocalDate> = emptyList(), | ||
val recordList: List<RecordList> = emptyList(), | ||
) : UiState | ||
|
||
sealed interface TraineeHomeUiEvent : UiEvent { | ||
data object OnNextWeekClick : TraineeHomeUiEvent | ||
data object OnPreviousWeekClick : TraineeHomeUiEvent | ||
data class OnDayClick(val date: LocalDate) : TraineeHomeUiEvent | ||
} | ||
|
||
sealed interface TraineeHomeEffect : UiSideEffect { | ||
data class ShowToast(val message: String) : TraineeHomeEffect | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,37 +1,161 @@ | ||
package co.kr.tnt.trainee.home | ||
|
||
import android.widget.Toast | ||
import androidx.compose.foundation.layout.Box | ||
import androidx.compose.foundation.layout.Column | ||
import androidx.compose.foundation.layout.Spacer | ||
import androidx.compose.foundation.layout.fillMaxSize | ||
import androidx.compose.foundation.layout.fillMaxWidth | ||
import androidx.compose.foundation.layout.height | ||
import androidx.compose.foundation.layout.padding | ||
import androidx.compose.material3.Button | ||
import androidx.compose.material3.Icon | ||
import androidx.compose.material3.IconButton | ||
import androidx.compose.material3.Scaffold | ||
import androidx.compose.material3.Text | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.LaunchedEffect | ||
import androidx.compose.runtime.getValue | ||
import androidx.compose.runtime.rememberCoroutineScope | ||
import androidx.compose.ui.Alignment | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.platform.LocalContext | ||
import androidx.compose.ui.res.painterResource | ||
import androidx.compose.ui.tooling.preview.Preview | ||
import androidx.compose.ui.unit.dp | ||
import androidx.hilt.navigation.compose.hiltViewModel | ||
import androidx.lifecycle.compose.collectAsStateWithLifecycle | ||
import co.kr.tnt.designsystem.component.calendar.TnTCalendarSelector | ||
import co.kr.tnt.designsystem.component.calendar.TnTIndicatorWeekCalendar | ||
import co.kr.tnt.designsystem.component.calendar.model.DayIndicatorState | ||
import co.kr.tnt.designsystem.component.calendar.model.DayState | ||
import co.kr.tnt.designsystem.theme.TnTTheme | ||
import co.kr.tnt.trainee.home.TraineeHomeContract.TraineeHomeUiEvent | ||
import co.kr.tnt.trainee.home.TraineeHomeContract.TraineeHomeUiState | ||
import com.kizitonwose.calendar.compose.weekcalendar.rememberWeekCalendarState | ||
import kotlinx.coroutines.launch | ||
import java.time.LocalDate | ||
import java.time.YearMonth | ||
import co.kr.tnt.core.designsystem.R as uiResource | ||
|
||
@Composable | ||
@Suppress("UnusedParameter") | ||
internal fun TraineeHomeRoute( | ||
viewModel: TraineeHomeViewModel = hiltViewModel(), | ||
navigateToNotification: () -> Unit, | ||
) { | ||
TraineeHomeScreen(navigateToNotification) | ||
val context = LocalContext.current | ||
val uiState by viewModel.uiState.collectAsStateWithLifecycle() | ||
|
||
TraineeHomeScreen( | ||
state = uiState, | ||
navigateToNotification = navigateToNotification, | ||
onSelectDate = { date -> | ||
viewModel.setEvent(TraineeHomeUiEvent.OnDayClick(date)) | ||
}, | ||
onNextWeekClick = { viewModel.setEvent(TraineeHomeUiEvent.OnNextWeekClick) }, | ||
onPreviousWeekClick = { viewModel.setEvent(TraineeHomeUiEvent.OnPreviousWeekClick) }, | ||
) | ||
|
||
LaunchedEffect(viewModel.effect) { | ||
viewModel.effect.collect { effect -> | ||
when (effect) { | ||
is TraineeHomeContract.TraineeHomeEffect.ShowToast -> { | ||
Toast.makeText(context, effect.message, Toast.LENGTH_SHORT).show() | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
@Composable | ||
fun TraineeHomeScreen( | ||
private fun TraineeHomeScreen( | ||
state: TraineeHomeUiState, | ||
onSelectDate: (LocalDate) -> Unit, | ||
onNextWeekClick: () -> Unit, | ||
onPreviousWeekClick: () -> Unit, | ||
navigateToNotification: () -> Unit, | ||
) { | ||
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> | ||
Column { | ||
Text( | ||
text = "trainee home", | ||
modifier = Modifier.padding(innerPadding), | ||
) | ||
Button(onClick = navigateToNotification) { | ||
Text("navigate to notification") | ||
val now = LocalDate.now() | ||
val coroutineScope = rememberCoroutineScope() | ||
|
||
val weekCalendarState = rememberWeekCalendarState( | ||
startDate = now.minusWeeks(6), | ||
endDate = now.plusWeeks(6), | ||
firstVisibleWeekDate = state.selectedDate, | ||
) | ||
|
||
Scaffold( | ||
containerColor = TnTTheme.colors.commonColors.Common0, | ||
modifier = Modifier.fillMaxSize(), | ||
) { innerPadding -> | ||
Column(modifier = Modifier.padding(innerPadding)) { | ||
Box( | ||
contentAlignment = Alignment.Center, | ||
modifier = Modifier | ||
.fillMaxWidth() | ||
.padding(horizontal = 20.dp, vertical = 8.dp), | ||
) { | ||
Spacer(Modifier.height(8.dp)) | ||
TnTCalendarSelector( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 요거 제 브랜치에서 |
||
yearMonth = state.visibleYearMonth, | ||
onClickPrevious = { | ||
coroutineScope.launch { | ||
onPreviousWeekClick() | ||
weekCalendarState.animateScrollToWeek(state.selectedDate) | ||
} | ||
}, | ||
onClickNext = { | ||
coroutineScope.launch { | ||
onNextWeekClick() | ||
weekCalendarState.animateScrollToWeek(state.selectedDate) | ||
} | ||
}, | ||
modifier = Modifier.align(Alignment.Center), | ||
) | ||
IconButton( | ||
onClick = navigateToNotification, | ||
modifier = Modifier.align(Alignment.CenterEnd), | ||
) { | ||
Icon( | ||
painter = painterResource(uiResource.drawable.ic_alarm), | ||
contentDescription = "alarm", | ||
) | ||
} | ||
} | ||
Spacer(modifier = Modifier.height(16.dp)) | ||
TnTIndicatorWeekCalendar( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 최소 날짜, 최대 날짜 지정이 필요할 것 같습니다! |
||
state = weekCalendarState, | ||
dayState = { date -> | ||
DayState(isSelected = date == state.selectedDate) | ||
}, | ||
indicatorState = { date -> | ||
DayIndicatorState(showIcon = date in state.markedDates) | ||
}, | ||
onClickDay = { date -> | ||
onSelectDate(date) | ||
}, | ||
) | ||
Spacer(modifier = Modifier.height(12.dp)) | ||
} | ||
} | ||
} | ||
|
||
@Preview | ||
@Composable | ||
private fun TraineeHomeScreenPreview() { | ||
val now = LocalDate.now() | ||
|
||
val dummyUiState = TraineeHomeUiState( | ||
selectedDate = now, | ||
visibleYearMonth = YearMonth.from(now), | ||
markedDates = List(5) { now.minusDays(it.toLong() * 2) }, | ||
) | ||
|
||
TnTTheme { | ||
TraineeHomeScreen( | ||
state = dummyUiState, | ||
navigateToNotification = { }, | ||
onSelectDate = {}, | ||
onNextWeekClick = { }, | ||
onPreviousWeekClick = { }, | ||
) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,54 @@ | ||
package co.kr.tnt.trainee.home | ||
|
||
import androidx.lifecycle.ViewModel | ||
import co.kr.tnt.trainee.home.TraineeHomeContract.TraineeHomeEffect | ||
import co.kr.tnt.trainee.home.TraineeHomeContract.TraineeHomeUiEvent | ||
import co.kr.tnt.trainee.home.TraineeHomeContract.TraineeHomeUiState | ||
import co.kr.tnt.ui.base.BaseViewModel | ||
import dagger.hilt.android.lifecycle.HiltViewModel | ||
import java.time.LocalDate | ||
import java.time.YearMonth | ||
import javax.inject.Inject | ||
|
||
@HiltViewModel | ||
class TraineeHomeViewModel @Inject constructor() : ViewModel() | ||
internal class TraineeHomeViewModel @Inject constructor() : | ||
BaseViewModel<TraineeHomeUiState, TraineeHomeUiEvent, TraineeHomeEffect>( | ||
TraineeHomeUiState(), | ||
) { | ||
init { | ||
updateCalenderState() | ||
} | ||
|
||
override suspend fun handleEvent(event: TraineeHomeUiEvent) { | ||
when (event) { | ||
TraineeHomeUiEvent.OnNextWeekClick -> moveToNextWeek() | ||
TraineeHomeUiEvent.OnPreviousWeekClick -> moveToPreviousWeek() | ||
is TraineeHomeUiEvent.OnDayClick -> selectDate(event.date) | ||
} | ||
} | ||
|
||
// TODO : 주간 캘린더 API 연동 | ||
private fun updateCalenderState() { | ||
val today = LocalDate.now() | ||
val list = List(10) { | ||
today.minusDays((0..30).random().toLong()) | ||
} | ||
updateState { copy(markedDates = list) } | ||
} | ||
|
||
private fun selectDate(date: LocalDate) { | ||
updateState { | ||
copy( | ||
selectedDate = date, | ||
visibleYearMonth = YearMonth.from(date), | ||
) | ||
} | ||
} | ||
|
||
private fun moveToNextWeek() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
현재 보이는 '연월'은 위 기획과 동일하게 설정되도록 수정이 필요할 것 같아요! |
||
selectDate(currentState.selectedDate.plusWeeks(1)) | ||
} | ||
|
||
private fun moveToPreviousWeek() { | ||
selectDate(currentState.selectedDate.minusWeeks(1)) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
우리 앱의 첫번째 요일은 '일요일'이므로 별도로
FirstDayOfWeek
선언해주는게 좋을 것 같습니다 ~