diff --git a/core/src/main/java/com/sopt/core/util/time/CalculateTimeFromLocalDate.kt b/core/src/main/java/com/sopt/core/util/time/CalculateTimeFromLocalDate.kt new file mode 100644 index 00000000..6cb5525f --- /dev/null +++ b/core/src/main/java/com/sopt/core/util/time/CalculateTimeFromLocalDate.kt @@ -0,0 +1,16 @@ +package com.sopt.core.util.time + +import java.time.LocalDate +import java.time.format.TextStyle +import java.util.Locale + +class CalculateTimeFromLocalDate { + // ex) 1월 1일 (월) + fun formatLocalDateWithDay(localDate: LocalDate): String { + val month = localDate.monthValue + val day = localDate.dayOfMonth + val dayOfWeek = localDate.dayOfWeek.getDisplayName(TextStyle.SHORT, Locale.KOREAN) + + return "${month}월 ${day}일 ($dayOfWeek)" + } +} diff --git a/core/src/main/java/com/sopt/core/util/CalculateTime.kt b/core/src/main/java/com/sopt/core/util/time/CalculateTimeFromString.kt similarity index 96% rename from core/src/main/java/com/sopt/core/util/CalculateTime.kt rename to core/src/main/java/com/sopt/core/util/time/CalculateTimeFromString.kt index fc306788..7fce3017 100644 --- a/core/src/main/java/com/sopt/core/util/CalculateTime.kt +++ b/core/src/main/java/com/sopt/core/util/time/CalculateTimeFromString.kt @@ -1,11 +1,11 @@ -package com.sopt.core.util +package com.sopt.core.util.time import java.time.LocalDateTime import java.time.format.DateTimeFormatter import java.time.format.TextStyle import java.util.Locale -class CalculateTime { +class CalculateTimeFromString { // ex) 09/07 fun extractFullDateWithSlash(dateTime: String): String { return parseDateTime(dateTime).toLocalDate().format(DateTimeFormatter.ofPattern("MM/dd")) diff --git a/core/src/main/java/com/sopt/core/util/timetable/TimeTable.kt b/core/src/main/java/com/sopt/core/util/timetable/TimeTable.kt index 35b3a1a1..cbe07ffa 100644 --- a/core/src/main/java/com/sopt/core/util/timetable/TimeTable.kt +++ b/core/src/main/java/com/sopt/core/util/timetable/TimeTable.kt @@ -5,7 +5,7 @@ import androidx.compose.ui.graphics.Color import com.sopt.core.designsystem.theme.NoostakTheme import com.sopt.core.type.AvailabilityLevel import com.sopt.core.type.CellType -import com.sopt.core.util.CalculateTime +import com.sopt.core.util.time.CalculateTimeFromString import com.sopt.domain.entity.AppointmentMembersInfoEntity import com.sopt.domain.entity.TimeEntity @@ -138,8 +138,8 @@ class TimeTable { } private fun formatDateTimeToCustomFormat(dateTime: String): String { - val dayOfWeek = CalculateTime().extractDayOfWeek(dateTime) - val date = CalculateTime().extractDateWithSlash(dateTime) + val dayOfWeek = CalculateTimeFromString().extractDayOfWeek(dateTime) + val date = CalculateTimeFromString().extractDateWithSlash(dateTime) return "$dayOfWeek\n$date" } diff --git a/data/src/main/java/com/sopt/data/mapper/ResponseGetConfirmedDtoMapper.kt b/data/src/main/java/com/sopt/data/mapper/ResponseGetConfirmedDtoMapper.kt index 2b2bd66e..949a7ee2 100644 --- a/data/src/main/java/com/sopt/data/mapper/ResponseGetConfirmedDtoMapper.kt +++ b/data/src/main/java/com/sopt/data/mapper/ResponseGetConfirmedDtoMapper.kt @@ -6,6 +6,7 @@ import com.sopt.domain.entity.IdentityEntity fun ResponseGetOptionDetailDto.toAppointmentDetailEntity() = AppointmentDetailEntity( myIdentity = myInfo?.toIdentityEntity() ?: IdentityEntity("unavailable", -1, "나"), + appointmentName = appointmentName, date = appointmentTime.date, startTime = appointmentTime.startTime, endTime = appointmentTime.endTime, diff --git a/data/src/main/java/com/sopt/data/mapper/ResponseGetGroupConfirmedDetailDtoMapper.kt b/data/src/main/java/com/sopt/data/mapper/ResponseGetGroupConfirmedDetailDtoMapper.kt index d8b16c71..d896df7c 100644 --- a/data/src/main/java/com/sopt/data/mapper/ResponseGetGroupConfirmedDetailDtoMapper.kt +++ b/data/src/main/java/com/sopt/data/mapper/ResponseGetGroupConfirmedDetailDtoMapper.kt @@ -10,6 +10,7 @@ fun ResponseGetGroupConfirmedDetailDto.toConfirmedDetailEntity() = ConfirmedDeta position = myInfo.position, name = myInfo.name ), + appointmentName = appointmentName, date = appointmentTime.date, startTime = appointmentTime.startTime, endTime = appointmentTime.endTime, diff --git a/domain/src/main/java/com/sopt/domain/entity/AppointmentDetailEntity.kt b/domain/src/main/java/com/sopt/domain/entity/AppointmentDetailEntity.kt index 04ed688c..0547e612 100644 --- a/domain/src/main/java/com/sopt/domain/entity/AppointmentDetailEntity.kt +++ b/domain/src/main/java/com/sopt/domain/entity/AppointmentDetailEntity.kt @@ -2,12 +2,13 @@ package com.sopt.domain.entity data class AppointmentDetailEntity( val myIdentity: IdentityEntity, - val date: String, - val startTime: String, - val endTime: String, - val category: String, - val availableMembersCount: Int, + val appointmentName: String = "", + val date: String = "", + val startTime: String = "", + val endTime: String = "", + val category: String = "", + val availableMembersCount: Int = 0, val availableMembers: List, - val unavailableMembersCount: Int, + val unavailableMembersCount: Int = 0, val unavailableMembers: List ) diff --git a/domain/src/main/java/com/sopt/domain/entity/ConfirmedDetailEntity.kt b/domain/src/main/java/com/sopt/domain/entity/ConfirmedDetailEntity.kt index 2b907743..2446930c 100644 --- a/domain/src/main/java/com/sopt/domain/entity/ConfirmedDetailEntity.kt +++ b/domain/src/main/java/com/sopt/domain/entity/ConfirmedDetailEntity.kt @@ -2,6 +2,7 @@ package com.sopt.domain.entity data class ConfirmedDetailEntity( val myIdentity: IdentityEntity, + val appointmentName: String = "", val date: String, val startTime: String, val endTime: String, diff --git a/domain/src/main/java/com/sopt/domain/entity/ScheduleDetailEntity.kt b/domain/src/main/java/com/sopt/domain/entity/ScheduleDetailEntity.kt deleted file mode 100644 index a87f7bfc..00000000 --- a/domain/src/main/java/com/sopt/domain/entity/ScheduleDetailEntity.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.sopt.domain.entity - -data class ScheduleDetailEntity( - val myIdentity: IdentityEntity, - val appointmentName: String = "", - val date: String = "", // YYYY-MM-DDTHH:mm:ss - ex) 2024-09-07T00:00:00 - val startTime: String = "", // YYYY-MM-DDTHH:mm:ss - ex) 2024-09-07T00:00:00 - val endTime: String = "", // YYYY-MM-DDTHH:mm:ss - ex) 2024-09-07T00:00:00 - val category: String = "", - val availableMembersCount: Int = 0, - val availableMembers: List, - val unavailableMembersCount: Int = 0, - val unavailableMembers: List -) diff --git a/domain/src/main/java/com/sopt/domain/entity/ScheduleEntity.kt b/domain/src/main/java/com/sopt/domain/entity/ScheduleEntity.kt index 93dcb63b..8410a2d4 100644 --- a/domain/src/main/java/com/sopt/domain/entity/ScheduleEntity.kt +++ b/domain/src/main/java/com/sopt/domain/entity/ScheduleEntity.kt @@ -1,7 +1,9 @@ package com.sopt.domain.entity +import java.time.LocalDate + data class ScheduleEntity( val groupId: Long = -1, - val date: String, // M월 D일 (E) - ex) 1월 13일 (월) + val date: LocalDate, val scheduleList: List ) diff --git a/presentation/src/main/java/com/sopt/presentation/appointment/appointmentConfirm/AppointmentConfirmRoute.kt b/presentation/src/main/java/com/sopt/presentation/appointment/appointmentConfirm/AppointmentConfirmRoute.kt index 687cb373..b0c1b745 100644 --- a/presentation/src/main/java/com/sopt/presentation/appointment/appointmentConfirm/AppointmentConfirmRoute.kt +++ b/presentation/src/main/java/com/sopt/presentation/appointment/appointmentConfirm/AppointmentConfirmRoute.kt @@ -39,8 +39,8 @@ import com.sopt.core.designsystem.theme.NoostakAndroidTheme import com.sopt.core.designsystem.theme.NoostakTheme import com.sopt.core.extension.showIf import com.sopt.core.state.UiState -import com.sopt.core.util.CalculateTime import com.sopt.core.util.RearrangeList +import com.sopt.core.util.time.CalculateTimeFromString import com.sopt.domain.entity.AppointmentDetailEntity import com.sopt.domain.entity.IdentityEntity import com.sopt.presentation.R @@ -104,7 +104,7 @@ fun AppointmentConfirmRoute( ) } - else -> {} + else -> Unit } if (showErrorDialog.first) { @@ -131,7 +131,7 @@ fun AppointmentConfirmScreen( onConfirmButtonClick: (Long) -> Unit, data: AppointmentDetailEntity ) { - val calculateTime = CalculateTime() + val calculateTime = CalculateTimeFromString() val date = calculateTime.extractDateWithKorean(data.date) val dayOfWeek = calculateTime.extractDayOfWeekWithBraces(data.date) val startHour = calculateTime.extractHourWithZero(data.startTime) diff --git a/presentation/src/main/java/com/sopt/presentation/appointment/screen/RecommendationScreen.kt b/presentation/src/main/java/com/sopt/presentation/appointment/screen/RecommendationScreen.kt index ea801e8d..99dc4138 100644 --- a/presentation/src/main/java/com/sopt/presentation/appointment/screen/RecommendationScreen.kt +++ b/presentation/src/main/java/com/sopt/presentation/appointment/screen/RecommendationScreen.kt @@ -41,8 +41,8 @@ import com.sopt.core.designsystem.theme.NoostakAndroidTheme import com.sopt.core.designsystem.theme.NoostakTheme import com.sopt.core.extension.noRippleClickable import com.sopt.core.extension.showIf -import com.sopt.core.util.CalculateTime import com.sopt.core.util.RearrangeList +import com.sopt.core.util.time.CalculateTimeFromString import com.sopt.domain.entity.IdentityEntity import com.sopt.domain.entity.OptionEntity import com.sopt.domain.entity.RecommendationPriorityEntity @@ -114,7 +114,7 @@ fun RecommendationItem( } } val (isLiked, likes) = likeState - val calculateTime = CalculateTime() + val calculateTime = CalculateTimeFromString() val date = calculateTime.extractDateWithKorean(data.date) val dayOfWeek = calculateTime.extractDayOfWeekWithBraces(data.date) val startHour = calculateTime.extractHourWithZero(data.startTime) diff --git a/presentation/src/main/java/com/sopt/presentation/calendar/CalendarRoute.kt b/presentation/src/main/java/com/sopt/presentation/calendar/CalendarRoute.kt index 5471649d..da1fba2f 100644 --- a/presentation/src/main/java/com/sopt/presentation/calendar/CalendarRoute.kt +++ b/presentation/src/main/java/com/sopt/presentation/calendar/CalendarRoute.kt @@ -1,5 +1,6 @@ package com.sopt.presentation.calendar +import android.annotation.SuppressLint import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues @@ -17,7 +18,10 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableLongStateOf +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -32,15 +36,20 @@ import androidx.navigation.compose.rememberNavController import com.sopt.core.designsystem.component.bottomsheet.NoostakBottomSheet import com.sopt.core.designsystem.component.calendar.WeekDaysHeader import com.sopt.core.designsystem.component.calendar.YearMonthHeader +import com.sopt.core.designsystem.component.dialog.NoostakDialog import com.sopt.core.designsystem.component.topappbar.NoostakLogoAppBar +import com.sopt.core.designsystem.screen.NoostakLoadingScreen import com.sopt.core.designsystem.theme.NoostakAndroidTheme import com.sopt.core.designsystem.theme.NoostakTheme import com.sopt.core.extension.getYearMonthByPage import com.sopt.core.extension.initialPage import com.sopt.core.extension.pageCount import com.sopt.core.state.UiState +import com.sopt.core.type.DialogType +import com.sopt.domain.entity.CalendarAppointmentEntity import com.sopt.domain.entity.CalendarSchedule import com.sopt.domain.entity.GroupEntity +import com.sopt.domain.entity.ScheduleEntity import com.sopt.presentation.R import com.sopt.presentation.calendar.component.CalendarFloatingActionDialog import com.sopt.presentation.calendar.component.CalendarGroup @@ -49,6 +58,7 @@ import com.sopt.presentation.calendar.component.bottomsheet.ScheduleListScreen import java.time.LocalDate import java.time.YearMonth +@SuppressLint("StateFlowValueCalledInComposition") @OptIn(ExperimentalMaterial3Api::class) @Composable fun CalendarRoute( @@ -58,10 +68,14 @@ fun CalendarRoute( navigateToGroupEnter: () -> Unit, navigateToAppointmentCreate: (Long) -> Unit ) { + val navController = rememberNavController() + val getGroupsState by calendarViewModel.getGroupsState.collectAsStateWithLifecycle() + val getConfirmedDetailState by calendarViewModel.getConfirmedDetailState.collectAsStateWithLifecycle() + val showAddDialog by calendarViewModel.showAddDialog.collectAsStateWithLifecycle() val showBottomSheet by calendarViewModel.showBottomSheet.collectAsStateWithLifecycle() - val navController = rememberNavController() + val showDataErrorDialog by calendarViewModel.showDataErrorDialog.collectAsStateWithLifecycle() val scheduleMap by calendarViewModel.scheduleMap.collectAsStateWithLifecycle() @@ -72,6 +86,9 @@ fun CalendarRoute( val currentYearMonth by remember { derivedStateOf { getYearMonthByPage(pagerState.currentPage) } } + var clickDate by remember { mutableStateOf(null) } + var clickAppointmentId by remember { mutableLongStateOf(-1) } + LaunchedEffect(pagerState) { snapshotFlow { pagerState.currentPage } .collect { page -> @@ -85,15 +102,31 @@ fun CalendarRoute( is CalendarSideEffect.NavigateToGroupCreate -> navigateToGroupCreate() is CalendarSideEffect.NavigateToGroupEnter -> navigateToGroupEnter() is CalendarSideEffect.NavigateToAppointmentCreate -> navigateToAppointmentCreate( - calendarViewModel.getSelectedScheduleEntity().groupId + calendarViewModel.selectedGroupId.value ?: -1 ) is CalendarSideEffect.ShowAddDialog -> calendarViewModel.showAddDialog(true) is CalendarSideEffect.ShowBottomSheet -> calendarViewModel.showBottomSheet(true) + is CalendarSideEffect.ShowDataErrorDialog -> calendarViewModel.showDataErrorDialog( + true + ) } } } + if (showDataErrorDialog) { + NoostakDialog( + dialogType = DialogType.DATA_FAILURE, + onClick = { + calendarViewModel.getConfirmedDetail(clickAppointmentId) + }, + onDismissRequest = { + calendarViewModel.showDataErrorDialog(false) + navController.popBackStack() + } + ) + } + if (showAddDialog) { CalendarFloatingActionDialog( onClick = { calendarViewModel.showAddDialog(false) }, @@ -117,30 +150,47 @@ fun CalendarRoute( }, content = { NavHost(navController, startDestination = SCHEDULE_LIST) { - composable(SCHEDULE_LIST) { backStackEntry -> - ScheduleListScreen( - data = calendarViewModel.getSelectedScheduleEntity(), - onItemClick = { schedule -> - backStackEntry.savedStateHandle[SCHEDULE] = - schedule.id // 바꿔야 함 - navController.navigate(SCHEDULE_DETAIL) - }, - onCreateAppointmentBtnClick = { - calendarViewModel.navigateToAppointmentCreate() - calendarViewModel.showBottomSheet(false) - } - ) + composable(SCHEDULE_LIST) { + clickDate?.let { date -> + ScheduleListScreen( + data = ScheduleEntity( + groupId = calendarViewModel.selectedGroupId.value ?: -1, + date = date, + scheduleList = calendarViewModel.selectedDayAppointments.value.map { + CalendarAppointmentEntity( + id = it.id, + name = it.name, + category = it.category, + startTime = it.startTime, + endTime = it.endTime, + duration = it.duration, + date = it.date + ) + } + ), + onItemClick = { id -> + clickAppointmentId = id + calendarViewModel.getConfirmedDetail(clickAppointmentId) + navController.navigate(SCHEDULE_DETAIL) + }, + onCreateAppointmentBtnClick = { + calendarViewModel.navigateToAppointmentCreate() + calendarViewModel.showBottomSheet(false) + } + ) + } } composable(SCHEDULE_DETAIL) { - val schedule = - navController.previousBackStackEntry?.savedStateHandle?.get( - SCHEDULE - ) - schedule?.let { id -> - ScheduleDetailScreen( - data = calendarViewModel.mockScheduleDetail, - onBackBtnClick = { navController.popBackStack() } - ) + when (getConfirmedDetailState) { + is UiState.Loading -> NoostakLoadingScreen() + is UiState.Success -> { + ScheduleDetailScreen( + data = (getConfirmedDetailState as UiState.Success).data, + onBackBtnClick = { navController.popBackStack() } + ) + } + + else -> Unit } } } @@ -157,6 +207,7 @@ fun CalendarRoute( showAddDialog = showAddDialog, onAddBtnClick = { calendarViewModel.showAddDialog(true) }, onItemClick = { clickedDate -> + clickDate = clickedDate calendarViewModel.onDayClicked(clickedDate) }, onGroupClick = { groupId -> @@ -236,7 +287,6 @@ private fun CalendarContent( } } -const val SCHEDULE = "schedule" const val SCHEDULE_LIST = "schedule_list" const val SCHEDULE_DETAIL = "schedule_detail" diff --git a/presentation/src/main/java/com/sopt/presentation/calendar/CalendarSideEffect.kt b/presentation/src/main/java/com/sopt/presentation/calendar/CalendarSideEffect.kt index 6811dec5..a4f32484 100644 --- a/presentation/src/main/java/com/sopt/presentation/calendar/CalendarSideEffect.kt +++ b/presentation/src/main/java/com/sopt/presentation/calendar/CalendarSideEffect.kt @@ -6,4 +6,5 @@ sealed interface CalendarSideEffect { data object NavigateToAppointmentCreate : CalendarSideEffect data class ShowAddDialog(val show: Boolean) : CalendarSideEffect data object ShowBottomSheet : CalendarSideEffect + data object ShowDataErrorDialog : CalendarSideEffect } diff --git a/presentation/src/main/java/com/sopt/presentation/calendar/CalendarViewModel.kt b/presentation/src/main/java/com/sopt/presentation/calendar/CalendarViewModel.kt index 7db3e28d..4048fc9d 100644 --- a/presentation/src/main/java/com/sopt/presentation/calendar/CalendarViewModel.kt +++ b/presentation/src/main/java/com/sopt/presentation/calendar/CalendarViewModel.kt @@ -4,14 +4,12 @@ import androidx.lifecycle.viewModelScope import com.sopt.core.extension.toDateString import com.sopt.core.state.UiState import com.sopt.core.util.BaseViewModel -import com.sopt.core.util.calendar.toFormattedKoreanDate import com.sopt.domain.entity.CalendarAppointmentDayEntity import com.sopt.domain.entity.CalendarAppointmentEntity import com.sopt.domain.entity.CalendarSchedule +import com.sopt.domain.entity.ConfirmedDetailEntity import com.sopt.domain.entity.GroupEntity -import com.sopt.domain.entity.IdentityEntity -import com.sopt.domain.entity.ScheduleDetailEntity -import com.sopt.domain.entity.ScheduleEntity +import com.sopt.domain.repository.GroupDetailRepository import com.sopt.domain.usecase.GetCalendarAppointmentsUseCase import com.sopt.domain.usecase.GetCalendarGroupsUseCase import dagger.hilt.android.lifecycle.HiltViewModel @@ -28,6 +26,7 @@ import javax.inject.Inject @HiltViewModel class CalendarViewModel @Inject constructor( private val getCalendarAppointmentsUseCase: GetCalendarAppointmentsUseCase, + private val groupDetailRepository: GroupDetailRepository, private val getCalendarGroupsUseCase: GetCalendarGroupsUseCase ) : BaseViewModel() { @@ -36,7 +35,7 @@ class CalendarViewModel @Inject constructor( val getGroupsState: StateFlow>> get() = _getGroupsState.asStateFlow() private val _selectedGroupId = MutableStateFlow(null) - private val selectedGroupId: StateFlow get() = _selectedGroupId + val selectedGroupId: StateFlow get() = _selectedGroupId private val _showAddDialog = MutableStateFlow(false) val showAddDialog get() = _showAddDialog @@ -44,6 +43,9 @@ class CalendarViewModel @Inject constructor( private val _showBottomSheet = MutableStateFlow(false) val showBottomSheet: StateFlow get() = _showBottomSheet + private val _showDataErrorDialog = MutableStateFlow(false) + val showDataErrorDialog: StateFlow get() = _showDataErrorDialog + private val _scheduleMap = MutableStateFlow>>(emptyMap()) val scheduleMap: StateFlow>> get() = _scheduleMap @@ -55,10 +57,31 @@ class CalendarViewModel @Inject constructor( private var _currentMonthAppointments = emptyList() + private val _getConfirmedDetailState = + MutableStateFlow>(UiState.Empty) + val getConfirmedDetailState: StateFlow> = + _getConfirmedDetailState.asStateFlow() + init { getGroups() } + fun getConfirmedDetail(appointmentId: Long) { + viewModelScope.launch { + _getConfirmedDetailState.emit(UiState.Loading) + groupDetailRepository.getConfirmedDetail(appointmentId) + .fold(onSuccess = { _getConfirmedDetailState.emit(UiState.Success(it)) }, + onFailure = { + triggerDataErrorDialog() + _getConfirmedDetailState.emit(UiState.Failure(it.message.toString())) + }) + } + } + + fun showDataErrorDialog(show: Boolean) { + _showDataErrorDialog.update { show } + } + fun showAddDialog(show: Boolean) { _showAddDialog.update { show } } @@ -67,6 +90,14 @@ class CalendarViewModel @Inject constructor( _showBottomSheet.update { show } } + private fun triggerDataErrorDialog() { + emitSideEffect(CalendarSideEffect.ShowDataErrorDialog) + } + + private fun triggerShowBottomSheet() { + emitSideEffect(CalendarSideEffect.ShowBottomSheet) + } + fun navigateToGroupCreate() { emitSideEffect(CalendarSideEffect.NavigateToGroupCreate) } @@ -101,7 +132,6 @@ class CalendarViewModel @Inject constructor( getCalendarAppointments(currentYearMonth.year, currentYearMonth.monthValue) } - // 캘린더 약속 정보 가져오기 private fun getCalendarAppointments(year: Int, month: Int) { viewModelScope.launch { selectedGroupId.value?.let { @@ -143,64 +173,11 @@ class CalendarViewModel @Inject constructor( val appointments = _currentMonthAppointments .firstOrNull { it.day == date.dayOfMonth && - currentYearMonth.year == date.year && - currentYearMonth.monthValue == date.monthValue + currentYearMonth.year == date.year && + currentYearMonth.monthValue == date.monthValue }?.appointments ?: emptyList() _selectedDayAppointments.value = appointments - - if (appointments.isNotEmpty()) { - showBottomSheet(true) - emitSideEffect(CalendarSideEffect.ShowBottomSheet) - } + triggerShowBottomSheet() } - - // 해당 날짜 일정 가져오기 - fun getSelectedScheduleEntity(): ScheduleEntity { - return ScheduleEntity( - groupId = selectedGroupId.value ?: -1, - date = _selectedDayAppointments.value.first().date.toFormattedKoreanDate(), - scheduleList = _selectedDayAppointments.value.map { - CalendarAppointmentEntity( - id = it.id, - name = it.name, - category = it.category, - startTime = it.startTime, - endTime = it.endTime, - duration = it.duration, - date = it.date - ) - } - ) - } - - val mockScheduleDetail = ScheduleDetailEntity( - myIdentity = IdentityEntity( - availability = "available", - position = 0, - name = "김언지" - ), - appointmentName = "누스탁이올시다 으아아아아아아아아아아아아아", - date = "1월 13일 (월)", - startTime = "1/13 21:00", - endTime = "1/13 21:00", - category = "기타", - availableMembersCount = 81, - availableMembers = listOf( - "하루", "야마다", "이누마키", "츠키시마", - "마이키", "호크스", "토도로키", "아이자와", "리바이", "이구로", "호시나", "신에이", - "하루", "야마다", "이누마키", "츠키시마", - "마이키", "호크스", "토도로키", "아이자와", "리바이", "이구로", "호시나", "신에이", - "하루", "야마다", "이누마키", "츠키시마", - "마이키", "호크스", "토도로키", "아이자와", "리바이", "이구로", "호시나", "신에이", - "하루", "야마다", "이누마키", "츠키시마", - "마이키", "호크스", "토도로키", "아이자와", "리바이", "이구로", "호시나", "신에이", - "하루", "야마다", "이누마키", "츠키시마", - "마이키", "호크스", "토도로키", "아이자와", "리바이", "이구로", "호시나", "신에이", - "하루", "야마다", "이누마키", "츠키시마", - "마이키", "호크스", "토도로키", "아이자와", "리바이", "이구로", "호시나", "신에이" - ), - unavailableMembersCount = 3, - unavailableMembers = listOf("박보검", "정해인", "권지용") - ) } diff --git a/presentation/src/main/java/com/sopt/presentation/calendar/component/bottomsheet/ScheduleDetailScreen.kt b/presentation/src/main/java/com/sopt/presentation/calendar/component/bottomsheet/ScheduleDetailScreen.kt index 91d5b0ff..300692de 100644 --- a/presentation/src/main/java/com/sopt/presentation/calendar/component/bottomsheet/ScheduleDetailScreen.kt +++ b/presentation/src/main/java/com/sopt/presentation/calendar/component/bottomsheet/ScheduleDetailScreen.kt @@ -27,15 +27,16 @@ import com.sopt.core.designsystem.component.chip.UnavailableUserChips import com.sopt.core.designsystem.theme.NoostakAndroidTheme import com.sopt.core.designsystem.theme.NoostakTheme import com.sopt.core.util.RearrangeList +import com.sopt.core.util.time.CalculateTimeFromString +import com.sopt.domain.entity.ConfirmedDetailEntity import com.sopt.domain.entity.IdentityEntity -import com.sopt.domain.entity.ScheduleDetailEntity import com.sopt.presentation.R import com.sopt.presentation.groupDetail.confirmedDetail.CompleteDetailInfo @OptIn(ExperimentalLayoutApi::class) @Composable fun ScheduleDetailScreen( - data: ScheduleDetailEntity, + data: ConfirmedDetailEntity, onBackBtnClick: () -> Unit = {} ) { val rearrangeList = RearrangeList() @@ -71,7 +72,12 @@ fun ScheduleDetailScreen( horizontalArrangement = Arrangement.spacedBy(13.dp) ) { Text( - text = data.date, + text = CalculateTimeFromString().extractDateWithSlash(data.date), + color = NoostakTheme.colors.black, + style = NoostakTheme.typography.b4SemiBold + ) + Text( + text = CalculateTimeFromString().extractHourWithZero(data.date), color = NoostakTheme.colors.black, style = NoostakTheme.typography.b4SemiBold ) @@ -129,14 +135,14 @@ fun ScheduleDetailScreen( fun ScheduleDetailScreenPreview() { NoostakAndroidTheme { ScheduleDetailScreen( - ScheduleDetailEntity( + ConfirmedDetailEntity( myIdentity = IdentityEntity( availability = "available", position = 0, name = "김언지" ), appointmentName = "누스탁 전체회의 호이호이호이호이호이", - date = "1월 13일 (월)", + date = "2024-09-07T00:00:00", startTime = "1/13 21:00", endTime = "1/13 21:00", category = "기타", diff --git a/presentation/src/main/java/com/sopt/presentation/calendar/component/bottomsheet/ScheduleItem.kt b/presentation/src/main/java/com/sopt/presentation/calendar/component/bottomsheet/ScheduleItem.kt index 4d28cb1f..9c703ab0 100644 --- a/presentation/src/main/java/com/sopt/presentation/calendar/component/bottomsheet/ScheduleItem.kt +++ b/presentation/src/main/java/com/sopt/presentation/calendar/component/bottomsheet/ScheduleItem.kt @@ -18,19 +18,20 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.sopt.core.designsystem.theme.NoostakTheme import com.sopt.core.extension.noRippleClickable +import com.sopt.core.util.time.CalculateTimeFromString import com.sopt.domain.entity.CalendarAppointmentEntity import com.sopt.presentation.R @Composable fun ScheduleItem( data: CalendarAppointmentEntity, - onItemClick: (CalendarAppointmentEntity) -> Unit = {} + onItemClick: (Long) -> Unit = {} ) { Row( verticalAlignment = Alignment.CenterVertically, modifier = Modifier .fillMaxWidth() - .noRippleClickable { onItemClick(data) } + .noRippleClickable { onItemClick(data.id) } .background(color = NoostakTheme.colors.gray50, shape = RoundedCornerShape(8.dp)) .padding(8.dp) ) { @@ -51,10 +52,20 @@ fun ScheduleItem( modifier = Modifier.padding(bottom = 3.dp) ) Text( - text = if (data.duration.toInt() == 24) stringResource(R.string.text_calendar_schedule_item_all_day) else data.duration.toString(), + text = if (data.duration.toInt() == FULL_DURATION) { + stringResource(R.string.text_calendar_schedule_item_all_day) + } else { + "${ + CalculateTimeFromString().extractHourWithZero( + data.startTime + ) + }~${CalculateTimeFromString().extractHourWithZero(data.endTime)}" + }, style = NoostakTheme.typography.c4Regular, color = NoostakTheme.colors.gray700 ) } } } + +const val FULL_DURATION = 24 diff --git a/presentation/src/main/java/com/sopt/presentation/calendar/component/bottomsheet/ScheduleListScreen.kt b/presentation/src/main/java/com/sopt/presentation/calendar/component/bottomsheet/ScheduleListScreen.kt index f2e9174a..8668844f 100644 --- a/presentation/src/main/java/com/sopt/presentation/calendar/component/bottomsheet/ScheduleListScreen.kt +++ b/presentation/src/main/java/com/sopt/presentation/calendar/component/bottomsheet/ScheduleListScreen.kt @@ -23,14 +23,16 @@ import com.sopt.core.designsystem.component.button.NoostakBottomButton import com.sopt.core.designsystem.screen.NoostakEmptyScreen import com.sopt.core.designsystem.theme.NoostakAndroidTheme import com.sopt.core.designsystem.theme.NoostakTheme +import com.sopt.core.util.time.CalculateTimeFromLocalDate import com.sopt.domain.entity.CalendarAppointmentEntity import com.sopt.domain.entity.ScheduleEntity import com.sopt.presentation.R +import java.time.LocalDate @Composable fun ScheduleListScreen( data: ScheduleEntity, - onItemClick: (CalendarAppointmentEntity) -> Unit = {}, + onItemClick: (Long) -> Unit = {}, onCreateAppointmentBtnClick: () -> Unit = {} ) { Column( @@ -45,7 +47,7 @@ fun ScheduleListScreen( contentAlignment = Alignment.Center ) { Text( - text = data.date, + text = CalculateTimeFromLocalDate().formatLocalDateWithDay(data.date), color = NoostakTheme.colors.black, style = NoostakTheme.typography.b1SemiBold ) @@ -99,14 +101,14 @@ fun ScheduleListScreenPreview() { ScheduleListScreen( data = ScheduleEntity( groupId = 1, - date = "1월 13일 (월)", + date = LocalDate.of(2025, 4, 4), scheduleList = listOf( CalendarAppointmentEntity( id = 1, name = "누스탁 회의dasfdsafsafdafdafsdfsafdsafdsadsdafsadfsdfsdafadafdsafsdafsaf", category = "중요", - startTime = "1월 13일(월)", - endTime = "1월 13일(월)", + startTime = "2024-09-07T00:00:00", + endTime = "2024-09-07T00:20:00", duration = 24, date = "" ), @@ -114,8 +116,8 @@ fun ScheduleListScreenPreview() { id = 2, name = "누스탁 모각작", category = "일정", - startTime = "1월 15일(수)", - endTime = "1월 15일(수)", + startTime = "2024-09-07T06:00:00", + endTime = "2024-09-07T08:00:00", duration = 5, date = "" ), @@ -123,8 +125,8 @@ fun ScheduleListScreenPreview() { id = 3, name = "누스탁 회식", category = "취미", - startTime = "1월 20일(화)", - endTime = "1월 20일(화)", + startTime = "2024-09-07T12:00:00", + endTime = "2024-09-07T13:00:00", duration = 2, date = "" ) diff --git a/presentation/src/main/java/com/sopt/presentation/groupCreate/GroupCreateViewModel.kt b/presentation/src/main/java/com/sopt/presentation/groupCreate/GroupCreateViewModel.kt index 699e6bc7..682b8077 100644 --- a/presentation/src/main/java/com/sopt/presentation/groupCreate/GroupCreateViewModel.kt +++ b/presentation/src/main/java/com/sopt/presentation/groupCreate/GroupCreateViewModel.kt @@ -86,7 +86,7 @@ class GroupCreateViewModel @Inject constructor( private fun validateGroupName(groupName: String) { viewModelScope.launch { - _groupProfileState.update { it.copy(isGroupNameCheck = groupName.length in 1..30) } + _groupProfileState.update { it.copy(isGroupNameCheck = groupName.isNotBlank() && groupName.length in 1..30) } } } } diff --git a/presentation/src/main/java/com/sopt/presentation/groupDetail/confirmedDetail/ConfirmedDetailRoute.kt b/presentation/src/main/java/com/sopt/presentation/groupDetail/confirmedDetail/ConfirmedDetailRoute.kt index c945cdbb..9921f49f 100644 --- a/presentation/src/main/java/com/sopt/presentation/groupDetail/confirmedDetail/ConfirmedDetailRoute.kt +++ b/presentation/src/main/java/com/sopt/presentation/groupDetail/confirmedDetail/ConfirmedDetailRoute.kt @@ -38,8 +38,8 @@ import com.sopt.core.designsystem.screen.NoostakLoadingScreen import com.sopt.core.designsystem.theme.NoostakAndroidTheme import com.sopt.core.designsystem.theme.NoostakTheme import com.sopt.core.state.UiState -import com.sopt.core.util.CalculateTime import com.sopt.core.util.RearrangeList +import com.sopt.core.util.time.CalculateTimeFromString import com.sopt.domain.entity.ConfirmedDetailEntity import com.sopt.presentation.R @@ -111,7 +111,7 @@ fun ConfirmedDetailScreen( ) } ) { innerPadding -> - val calculateTime = CalculateTime() + val calculateTime = CalculateTimeFromString() val date = calculateTime.extractDateWithSlash(data.date) val startHour = calculateTime.extractHourWithZero(data.startTime) val rearrangeList = RearrangeList() diff --git a/presentation/src/main/java/com/sopt/presentation/groupDetail/screen/ConfirmedScreen.kt b/presentation/src/main/java/com/sopt/presentation/groupDetail/screen/ConfirmedScreen.kt index 12ef97f1..87eba75d 100644 --- a/presentation/src/main/java/com/sopt/presentation/groupDetail/screen/ConfirmedScreen.kt +++ b/presentation/src/main/java/com/sopt/presentation/groupDetail/screen/ConfirmedScreen.kt @@ -22,7 +22,7 @@ import com.sopt.core.designsystem.component.box.CategoryBox import com.sopt.core.designsystem.theme.NoostakAndroidTheme import com.sopt.core.designsystem.theme.NoostakTheme import com.sopt.core.extension.noRippleClickable -import com.sopt.core.util.CalculateTime +import com.sopt.core.util.time.CalculateTimeFromString import com.sopt.domain.entity.ConfirmedEntity import com.sopt.presentation.R import com.sopt.presentation.groupDetail.GroupDetailViewModel @@ -71,7 +71,7 @@ fun ConfirmedItem( confirmedEntity: ConfirmedEntity, onItemClicked: (Long, Long, String) -> Unit ) { - val calculateTime = CalculateTime() + val calculateTime = CalculateTimeFromString() val date = calculateTime.extractDateWithKorean(confirmedEntity.date) val dayOfWeek = calculateTime.extractDayOfWeekWithBraces(confirmedEntity.date) val startHour = calculateTime.extractHourWithZero(confirmedEntity.startTime) diff --git a/presentation/src/main/java/com/sopt/presentation/groupDetail/screen/ProgressScreen.kt b/presentation/src/main/java/com/sopt/presentation/groupDetail/screen/ProgressScreen.kt index 7894d4b4..b5a21758 100644 --- a/presentation/src/main/java/com/sopt/presentation/groupDetail/screen/ProgressScreen.kt +++ b/presentation/src/main/java/com/sopt/presentation/groupDetail/screen/ProgressScreen.kt @@ -29,7 +29,7 @@ import androidx.hilt.navigation.compose.hiltViewModel import com.sopt.core.designsystem.theme.NoostakAndroidTheme import com.sopt.core.designsystem.theme.NoostakTheme import com.sopt.core.extension.noRippleClickable -import com.sopt.core.util.CalculateTime +import com.sopt.core.util.time.CalculateTimeFromString import com.sopt.domain.entity.ProgressEntity import com.sopt.presentation.R import com.sopt.presentation.groupDetail.GroupDetailViewModel @@ -74,7 +74,7 @@ fun ProgressItem( progressEntity: ProgressEntity, onItemClicked: (Long, Long, String) -> Unit ) { - val calculateTime = CalculateTime() + val calculateTime = CalculateTimeFromString() val startDate = calculateTime.extractDateWithKorean(progressEntity.startDate) val dayOfWeek = calculateTime.extractDayOfWeekWithBraces(progressEntity.startDate) val startHour = calculateTime.extractHourWithZero(progressEntity.startDate)