Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 @@ -14,15 +14,9 @@ internal class TrainerHomeContract {
val selectedDay: LocalDate = LocalDate.now(),
val dailyPtSessionCount: Map<LocalDate, Int> = mapOf(),
val selectedDayPtSessions: List<PtSession>? = null,
val dialogState: DialogState = DialogState.NONE,
val dialogState: TrainerHomeDialog = TrainerHomeDialog.None,
val isDialogHiddenForThreeDays: Boolean = false,
) : UiState {
enum class DialogState {
NONE,
HOME_CONNECT,
ADD_PT_CONNECT,
}
}
) : UiState

sealed interface TrainerHomeUiEvent : UiEvent {
data object OnScreen : TrainerHomeUiEvent
Expand All @@ -32,6 +26,7 @@ internal class TrainerHomeContract {
data object OnClickAddPtSession : TrainerHomeUiEvent
data class OnClickPtSessionComplete(val ptSession: PtSession) : TrainerHomeUiEvent
data object OnConfirmConnectDialog : TrainerHomeUiEvent
data class OnConfirmEarlyPtCompletion(val ptSession: PtSession) : TrainerHomeUiEvent
data object OnChangeHideDialogOption : TrainerHomeUiEvent
data object OnDismissDialog : TrainerHomeUiEvent
}
Expand All @@ -45,4 +40,11 @@ internal class TrainerHomeContract {
val type: SnackbarType = SnackbarType.WARNING,
) : TrainerHomeSideEffect
}

sealed interface TrainerHomeDialog {
data object None : TrainerHomeDialog
data object HomeConnect : TrainerHomeDialog
data object AddPtConnect : TrainerHomeDialog
data class EarlyPtCompletion(val ptSession: PtSession) : TrainerHomeDialog
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,22 +42,26 @@ import co.kr.tnt.core.designsystem.R.drawable.ic_add
import co.kr.tnt.core.designsystem.R.drawable.ic_fill_check_false
import co.kr.tnt.core.designsystem.R.drawable.ic_fill_check_true
import co.kr.tnt.core.designsystem.R.drawable.img_default
import co.kr.tnt.core.ui.R.string.core_cancel
import co.kr.tnt.core.ui.R.string.core_connect
import co.kr.tnt.core.ui.R.string.core_do_not_see_for_three_days
import co.kr.tnt.core.ui.R.string.core_next_time
import co.kr.tnt.core.ui.R.string.core_ok
import co.kr.tnt.designsystem.component.TnTIconPopupDialog
import co.kr.tnt.designsystem.component.TnTPopupDialog
import co.kr.tnt.designsystem.component.button.TnTFabButton
import co.kr.tnt.designsystem.component.calendar.TnTIndicatorMonthCalendar
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.component.calendar.utils.rememberMostVisibleMonth
import co.kr.tnt.designsystem.component.calendar.utils.rememberMostVisibleYearMonth
import co.kr.tnt.designsystem.component.card.TnTSessionRecordCard
import co.kr.tnt.designsystem.snackbar.LocalSnackbar
import co.kr.tnt.designsystem.theme.TnTTheme
import co.kr.tnt.domain.model.PtSession
import co.kr.tnt.domain.utils.DateFormatter
import co.kr.tnt.feature.trainer.home.R
import co.kr.tnt.navigation.model.ScreenMode
import co.kr.tnt.trainer.home.TrainerHomeContract.TrainerHomeDialog
import co.kr.tnt.trainer.home.TrainerHomeContract.TrainerHomeSideEffect
import co.kr.tnt.trainer.home.TrainerHomeContract.TrainerHomeUiEvent
import co.kr.tnt.trainer.home.TrainerHomeContract.TrainerHomeUiState
Expand All @@ -66,8 +70,8 @@ import co.kr.tnt.ui.component.TnTHomeTopBar
import co.kr.tnt.ui.utils.throttled
import coil.compose.rememberAsyncImagePainter
import coil.request.ImageRequest
import com.kizitonwose.calendar.compose.CalendarState
import com.kizitonwose.calendar.compose.rememberCalendarState
import com.kizitonwose.calendar.compose.weekcalendar.WeekCalendarState
import com.kizitonwose.calendar.compose.weekcalendar.rememberWeekCalendarState
import kotlinx.coroutines.launch
import java.time.DayOfWeek
import java.time.LocalDate
Expand Down Expand Up @@ -109,9 +113,9 @@ internal fun TrainerHomeRoute(
}
}

when (state.dialogState) {
TrainerHomeUiState.DialogState.NONE -> Unit
TrainerHomeUiState.DialogState.HOME_CONNECT -> {
when (val dialogState = state.dialogState) {
TrainerHomeDialog.None -> Unit
TrainerHomeDialog.HomeConnect -> {
TnTCheckToggleDialog(
title = stringResource(R.string.please_connect_member),
content = stringResource(R.string.cannot_add_pt_without_connection),
Expand All @@ -126,7 +130,7 @@ internal fun TrainerHomeRoute(
)
}

TrainerHomeUiState.DialogState.ADD_PT_CONNECT -> {
TrainerHomeDialog.AddPtConnect -> {
TnTPopupDialog(
title = stringResource(R.string.please_connect_member),
content = stringResource(R.string.cannot_add_pt_without_connection),
Expand All @@ -137,6 +141,22 @@ internal fun TrainerHomeRoute(
onDismiss = { viewModel.setEvent(TrainerHomeUiEvent.OnDismissDialog) },
)
}

is TrainerHomeDialog.EarlyPtCompletion -> {
TnTIconPopupDialog(
title = stringResource(R.string.pt_early_completion_title),
content = stringResource(R.string.pt_early_completion_message),
leftButtonText = stringResource(core_cancel),
rightButtonText = stringResource(core_ok),
onLeftButtonClick = { viewModel.setEvent(TrainerHomeUiEvent.OnDismissDialog) },
onRightButtonClick = {
viewModel.setEvent(
TrainerHomeUiEvent.OnConfirmEarlyPtCompletion(dialogState.ptSession),
)
},
onDismiss = { viewModel.setEvent(TrainerHomeUiEvent.OnDismissDialog) },
)
}
}

// TODO 홈 화면 진입 시마다 데이터 조회 재고 필요
Expand All @@ -153,15 +173,14 @@ private fun TrainerHomeScreen(
onClickAddPtSession: () -> Unit,
onClickPtSessionComplete: (PtSession) -> Unit,
) {
val now = remember { YearMonth.now() }
val calendarState = rememberCalendarState(
firstVisibleMonth = now,
val weekCalendarState = rememberWeekCalendarState(
firstDayOfWeek = DayOfWeek.SUNDAY,
startMonth = now.minusYears(10),
endMonth = now.plusYears(10),
firstVisibleWeekDate = state.selectedDay,
startDate = state.selectedDay.minusYears(10),
endDate = state.selectedDay.plusYears(10),
)
val coroutineScope = rememberCoroutineScope()
val visibleMonth = rememberMostVisibleMonth(calendarState)
var visibleMonth = rememberMostVisibleYearMonth(weekCalendarState)
val dateFormatter = remember { DateFormatter() }

Box(modifier = Modifier.padding(padding)) {
Expand All @@ -181,27 +200,32 @@ private fun TrainerHomeScreen(
onClickNotification = onClickNotification,
onClickSelectorPrevious = {
coroutineScope.launch {
calendarState.animateScrollToMonth(visibleMonth.minusMonths(1))
val previousWeek = weekCalendarState.firstVisibleWeek.days.first().date.minusWeeks(1)
visibleMonth = YearMonth.from(previousWeek)
weekCalendarState.animateScrollToWeek(previousWeek)
}
},
onClickSelectorNext = {
coroutineScope.launch {
calendarState.animateScrollToMonth(visibleMonth.plusMonths(1))
val nextWeek =
weekCalendarState.firstVisibleWeek.days.first().date.plusWeeks(1)
visibleMonth = YearMonth.from(nextWeek)
weekCalendarState.animateScrollToWeek(nextWeek)
}
},
)
Spacer(modifier = Modifier.height(16.dp))
Calendar(
modifier = Modifier.background(color = TnTTheme.colors.commonColors.Common0),
calendarState = calendarState,
weekCalendarState = weekCalendarState,
selectedDay = state.selectedDay,
dailyPtSessionCount = state.dailyPtSessionCount,
onClickDay = onClickDay,
)
Spacer(modifier = Modifier.height(24.dp))
Spacer(modifier = Modifier.height(12.dp))
}
Column {
Spacer(modifier = Modifier.height(24.dp))
Spacer(modifier = Modifier.height(20.dp))
DailyPtSessionTitle(
day = state.selectedDay,
sessionCount = state.selectedDayPtSessions?.size ?: 0,
Expand Down Expand Up @@ -253,16 +277,14 @@ private fun TrainerHomeScreen(

@Composable
private fun Calendar(
calendarState: CalendarState,
weekCalendarState: WeekCalendarState,
selectedDay: LocalDate,
dailyPtSessionCount: Map<LocalDate, Int>,
onClickDay: (date: LocalDate) -> Unit,
modifier: Modifier = Modifier,
) {
TnTIndicatorMonthCalendar(
modifier = modifier,
state = calendarState,
onClickDay = onClickDay,
TnTIndicatorWeekCalendar(
state = weekCalendarState,
dayState = { day -> DayState(isSelected = day == selectedDay) },
indicatorState = { day ->
val count = dailyPtSessionCount[day] ?: 0
Expand All @@ -273,6 +295,8 @@ private fun Calendar(
showText = count != 0,
)
},
onClickDay = onClickDay,
modifier = modifier.background(TnTTheme.colors.commonColors.Common0),
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import co.kr.tnt.domain.model.trainer.TrainerDailyPtSessionCount
import co.kr.tnt.domain.repository.ConnectRepository
import co.kr.tnt.domain.repository.TrainerRepository
import co.kr.tnt.feature.trainer.home.R
import co.kr.tnt.trainer.home.TrainerHomeContract.TrainerHomeDialog
import co.kr.tnt.trainer.home.TrainerHomeContract.TrainerHomeSideEffect
import co.kr.tnt.trainer.home.TrainerHomeContract.TrainerHomeUiEvent
import co.kr.tnt.trainer.home.TrainerHomeContract.TrainerHomeUiState
import co.kr.tnt.trainer.home.TrainerHomeContract.TrainerHomeUiState.DialogState
import co.kr.tnt.ui.base.BaseViewModel
import co.kr.tnt.ui.model.SnackbarType
import co.kr.tnt.ui.resource.DisplayText
Expand Down Expand Up @@ -51,8 +51,11 @@ internal class TrainerHomeViewModel @Inject constructor(
is TrainerHomeUiEvent.OnChangeVisibleMonth -> getMonthlySessionCounts(event.yearMonth)
is TrainerHomeUiEvent.OnClickDay -> selectDay(event.day)
TrainerHomeUiEvent.OnClickAddPtSession -> showConnectDialog(false)

is TrainerHomeUiEvent.OnClickPtSessionComplete -> completePtSession(event.ptSession)
is TrainerHomeUiEvent.OnClickPtSessionComplete -> completePtSessionIfStartTimeBeforeNow(event.ptSession)
is TrainerHomeUiEvent.OnConfirmEarlyPtCompletion -> {
completePtSession(event.ptSession)
updateState { copy(dialogState = TrainerHomeDialog.None) }
}
TrainerHomeUiEvent.OnChangeHideDialogOption -> toggleDialogHiddenState()
TrainerHomeUiEvent.OnConfirmConnectDialog -> handleDialogConfirm()
TrainerHomeUiEvent.OnDismissDialog -> dismissDialog()
Expand Down Expand Up @@ -123,6 +126,15 @@ internal class TrainerHomeViewModel @Inject constructor(
updateState { copy(dailyPtSessionCount = updatedDailyPtSessionCount) }
}

private fun completePtSessionIfStartTimeBeforeNow(ptSession: PtSession) {
if (LocalDateTime.now().isBefore(ptSession.startTime)) {
updateState { copy(dialogState = TrainerHomeDialog.EarlyPtCompletion(ptSession)) }
return
}

completePtSession(ptSession)
}

private fun completePtSession(ptSession: PtSession) {
viewModelScope.launch {
runCatching {
Expand Down Expand Up @@ -178,7 +190,7 @@ internal class TrainerHomeViewModel @Inject constructor(
trainerRepository.getActiveMembers()
}.onSuccess { result ->
if (result.isNotEmpty()) {
updateState { copy(dialogState = DialogState.NONE) }
updateState { copy(dialogState = TrainerHomeDialog.None) }
if (triggeredByHome.not()) {
sendEffect(TrainerHomeSideEffect.NavigateToAddPtSession)
}
Expand All @@ -191,9 +203,9 @@ internal class TrainerHomeViewModel @Inject constructor(
Duration.between(lastHiddenDate, currentDateTime).toHours() < DIALOG_HIDE_DURATION_HOURS

if (isHidden.not() && triggeredByHome) {
updateState { copy(dialogState = DialogState.HOME_CONNECT) }
updateState { copy(dialogState = TrainerHomeDialog.HomeConnect) }
} else if (triggeredByHome.not()) {
updateState { copy(dialogState = DialogState.ADD_PT_CONNECT) }
updateState { copy(dialogState = TrainerHomeDialog.AddPtConnect) }
}
}
}
Expand All @@ -207,12 +219,15 @@ internal class TrainerHomeViewModel @Inject constructor(
updateCurrentDateTime()
}
val effect = when (currentState.dialogState) {
DialogState.HOME_CONNECT -> TrainerHomeSideEffect.NavigateToInvite
DialogState.ADD_PT_CONNECT -> TrainerHomeSideEffect.NavigateToInvite
TrainerHomeDialog.HomeConnect -> TrainerHomeSideEffect.NavigateToInvite
TrainerHomeDialog.AddPtConnect -> TrainerHomeSideEffect.NavigateToInvite
else -> return
}
updateState {
copy(dialogState = DialogState.NONE, isDialogHiddenForThreeDays = false)
copy(
dialogState = TrainerHomeDialog.None,
isDialogHiddenForThreeDays = false,
)
}
sendEffect(effect)
}
Expand All @@ -230,7 +245,7 @@ internal class TrainerHomeViewModel @Inject constructor(
}
updateState {
copy(
dialogState = DialogState.NONE,
dialogState = TrainerHomeDialog.None,
isDialogHiddenForThreeDays = false,
)
}
Expand Down
2 changes: 2 additions & 0 deletions feature/trainer/home/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@
<string name="no_pt_session_yet">아직 등록된 수업이 없어요.</string>
<string name="press_add_button_to_add_pt_session">추가 버튼을 눌러 PT 수업 일정을 추가해 보세요</string>
<string name="pt_session_count">%1$s회차 수업</string>
<string name="pt_early_completion_title">수업을 기록하시겠어요?</string>
<string name="pt_early_completion_message">아직 수업 시간이 지나지 않았어요</string>
</resources>