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 @@ -178,6 +178,8 @@ const val DELETE_ALARM_TITLE = "알람 삭제"
const val DELETE_ALARM_CONTENT = "정말 알람을 삭제하시겠어요?"
const val MAP_PROVIDER_TITLE = "어떤 지도 앱을\n자주 사용하시나요?"
const val MAP_PROVIDER_CONTENT = "길 안내에 사용될 예정이에요."
const val DELETE_REPEAT_SCHEDULE_TITLE = "반복 일정 삭제"
const val DELETE_REPEAT_SCHEDULE_CONTENT = "이 알람을 삭제하면 이후 반복 알람도 함께 사라져요"

// Setting
const val LOGOUT_SUCCESS_MESSAGE = "정상적으로 로그아웃되었습니다."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ sealed interface CalendarIntent : Intent {

object Init : CalendarIntent

data class DeleteHistory(
data class DeleteScheduleItem(
val scheduleId: Long,
val isPast: Boolean,
) : CalendarIntent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ class CalendarViewModel(
loadSchedulesFor(currentState.selectedDate)
}

is CalendarIntent.DeleteHistory -> {
is CalendarIntent.DeleteScheduleItem -> {
if (intent.isPast) {
deleteHistory(intent.scheduleId)
} else {
Expand All @@ -105,7 +105,10 @@ class CalendarViewModel(
}
}

private fun getScheduleMarkersInRange(currentDate: LocalDate) {
private fun getScheduleMarkersInRange(
currentDate: LocalDate,
clearOnError: Boolean = true,
) {
// 동시에 여러 요청이 발생했을 때 뒤늦은 응답이 상태를 잘못 덮어쓰지 않도록 방어
val requestedMonth = CalendarMonth(currentDate.year, currentDate.month.number)
val requestId = ++markersRequestId
Expand Down Expand Up @@ -151,11 +154,14 @@ class CalendarViewModel(
if (requestId != markersRequestId) return@onError
if (currentState.currentMonth != requestedMonth) return@onError

reduce {
copy(
schedulesByDate = emptyMap(),
)
if (clearOnError) {
reduce {
copy(
schedulesByDate = emptyMap(),
)
}
}

emitEffect(CalendarSideEffect.ShowToast(ERROR_GET_SCHEDULE_LIST, ToastType.ERROR))
},
)
Expand Down Expand Up @@ -386,7 +392,6 @@ class CalendarViewModel(
val selectedDate = currentState.selectedDate
val previousSchedules = currentState.selectedDateSchedules
val previousItems = currentState.selectedDateScheduleItems
val previousSchedulesByDate = currentState.schedulesByDate

val targetSchedule =
previousSchedules.firstOrNull { it.scheduleId == scheduleId }
Expand All @@ -398,25 +403,12 @@ class CalendarViewModel(
val updatedSchedules = previousSchedules.filter { it.scheduleId != scheduleId }
val updatedItems = previousItems.filter { it.scheduleId != scheduleId }

val previousMarkersForDate = previousSchedulesByDate[selectedDate].orEmpty()
val updatedMarkersForDate = previousMarkersForDate.filter { it.scheduleId != scheduleId }

val updatedSchedulesByDate =
previousSchedulesByDate.toMutableMap().apply {
if (updatedMarkersForDate.isEmpty()) {
remove(selectedDate)
} else {
this[selectedDate] = updatedMarkersForDate
}
}

viewModelScope.launch {
try {
reduce {
copy(
selectedDateSchedules = updatedSchedules,
selectedDateScheduleItems = updatedItems,
schedulesByDate = updatedSchedulesByDate,
)
}

Expand All @@ -433,6 +425,9 @@ class CalendarViewModel(
ToastType.INFO,
),
)

// 마커 데이터는 UI에서 optimistic 계산이 어려워서 다시 조회
getScheduleMarkersInRange(selectedDate, false)
}

is AppResult.Error -> {
Expand All @@ -443,21 +438,6 @@ class CalendarViewModel(
schedules = previousSchedules,
)

val rolledBackSchedulesByDate =
currentState.schedulesByDate.toMutableMap().apply {
if (previousMarkersForDate.isEmpty()) {
remove(selectedDate)
} else {
this[selectedDate] = previousMarkersForDate
}
}

reduce {
copy(
schedulesByDate = rolledBackSchedulesByDate,
)
}

if (targetSchedule.hasActiveAlarm) {
applyAlarmToggleSerially(
scheduleId = scheduleId,
Expand All @@ -477,21 +457,6 @@ class CalendarViewModel(
schedules = previousSchedules,
)

val rolledBackSchedulesByDate =
currentState.schedulesByDate.toMutableMap().apply {
if (previousMarkersForDate.isEmpty()) {
remove(selectedDate)
} else {
this[selectedDate] = previousMarkersForDate
}
}

reduce {
copy(
schedulesByDate = rolledBackSchedulesByDate,
)
}

if (targetSchedule.hasActiveAlarm) {
applyAlarmToggleSerially(
scheduleId = scheduleId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
Expand All @@ -41,6 +42,9 @@ import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.dh.ondot.presentation.ui.theme.ADD_SCHEDULE
import com.dh.ondot.presentation.ui.theme.DELETE_REPEAT_SCHEDULE_CONTENT
import com.dh.ondot.presentation.ui.theme.DELETE_REPEAT_SCHEDULE_TITLE
import com.dh.ondot.presentation.ui.theme.WORD_DELETE
import com.ondot.calendar.contract.CalendarIntent
import com.ondot.calendar.contract.CalendarInteractionState
import com.ondot.calendar.contract.CalendarSheetAnchor
Expand All @@ -55,10 +59,12 @@ import com.ondot.calendar.ui.component.CalendarBottomSheet
import com.ondot.calendar.ui.component.CalendarMonthGrid
import com.ondot.calendar.ui.component.CalendarTopBar
import com.ondot.calendar.ui.component.CalendarWeekHeader
import com.ondot.designsystem.components.OnDotDialog
import com.ondot.designsystem.components.OnDotText
import com.ondot.designsystem.theme.OnDotColor.Gray800
import com.ondot.designsystem.theme.OnDotColor.Gray900
import com.ondot.designsystem.theme.OnDotColor.Green500
import com.ondot.domain.model.enums.DialogType
import com.ondot.domain.model.enums.OnDotTextStyle
import kotlinx.coroutines.launch
import kotlinx.datetime.LocalDate
Expand Down Expand Up @@ -86,7 +92,7 @@ fun CalendarRoute(
onMoveToNextMonth = { viewModel.dispatch(CalendarIntent.MoveToNextMonth) },
onToggleAlarm = { scheduleId, enabled -> viewModel.dispatch(CalendarIntent.ToggleAlarm(scheduleId, enabled)) },
onAddSchedule = navigateToCreateGeneralSchedule,
onDelete = { id, isPast -> viewModel.dispatch(CalendarIntent.DeleteHistory(id, isPast)) },
onDelete = { id, isPast -> viewModel.dispatch(CalendarIntent.DeleteScheduleItem(id, isPast)) },
onClickSchedule = { navigateToEditSchedule(it) },
)
}
Expand Down Expand Up @@ -129,6 +135,8 @@ private fun CalendarScreen(
val eventLabelAlpha = 1f - hiddenToPeek
val dimAlpha = peekToExpanded * 0.08f

var scheduleIdPendingDelete by remember { mutableStateOf<Long?>(null) }

BoxWithConstraints(
modifier =
Modifier
Expand Down Expand Up @@ -363,6 +371,7 @@ private fun CalendarScreen(
onToggleAlarm = onToggleAlarm,
onDelete = onDelete,
onClickSchedule = onClickSchedule,
onShowScheduleDeleteDialog = { scheduleIdPendingDelete = it },
)
}
}
Expand Down Expand Up @@ -395,6 +404,7 @@ private fun CalendarScreen(
onToggleAlarm = onToggleAlarm,
onDelete = onDelete,
onClickSchedule = onClickSchedule,
onShowScheduleDeleteDialog = { scheduleIdPendingDelete = it },
)
}

Expand All @@ -405,6 +415,22 @@ private fun CalendarScreen(
.padding(bottom = 20.dp, end = 22.dp),
onClick = onAddSchedule,
)

if (scheduleIdPendingDelete != null) {
OnDotDialog(
dialogType = DialogType.TWO,
dialogTitle = DELETE_REPEAT_SCHEDULE_TITLE,
dialogContent = DELETE_REPEAT_SCHEDULE_CONTENT,
positiveText = WORD_DELETE,
onDismiss = { scheduleIdPendingDelete = null },
onNegativeClick = { scheduleIdPendingDelete = null },
onPositiveClick = {
val id = scheduleIdPendingDelete ?: return@OnDotDialog
scheduleIdPendingDelete = null
onDelete(id, false)
},
)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,9 @@ fun CalendarBottomSheet(
schedules: List<CalendarScheduleItemUiModel>,
togglingScheduleIds: Set<Long> = emptySet(),
onToggleAlarm: (Long, Boolean) -> Unit = { _, _ -> },
onDelete: (Long, Boolean) -> Unit = { _, _ -> },
onDelete: (Long, Boolean) -> Unit = { _, _ -> }, // 반복 일정이 아닌 경우 그냥 삭제
onClickSchedule: (Long) -> Unit = {},
onShowScheduleDeleteDialog: (Long) -> Unit = {}, // 반복 일정인 경우 삭제 다이얼로그 띄우기
) {
Surface(
modifier = modifier,
Expand Down Expand Up @@ -124,8 +125,13 @@ fun CalendarBottomSheet(
Spacer(Modifier.height(20.dp))
schedules.forEach { item ->
SwipeableDeleteItem(
enabled = item.isPast,
onDelete = { onDelete(item.scheduleId, item.isPast) },
onDelete = {
if (!item.isPast && item.isRepeat) {
onShowScheduleDeleteDialog(item.scheduleId)
} else {
onDelete(item.scheduleId, item.isPast)
}
},
) {
CalendarScheduleListItem(
item = item,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.ondot.calendar.ui.component
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
Expand Down Expand Up @@ -50,8 +51,8 @@ fun CalendarDay(
}
val backgroundColor =
when {
cell.isSelected -> Gray600
cell.isToday -> Green900
cell.isSelected -> Gray600
else -> Color.Transparent
}

Expand Down Expand Up @@ -91,25 +92,36 @@ fun CalendarDay(
val dotTranslateY = 6f * (1f - eventDotAlpha)

if (cell.markers.isNotEmpty()) {
Box(
modifier =
Modifier
.graphicsLayer {
alpha = eventLabelAlpha
scaleX = chipScale
scaleY = chipScale
translationY = chipTranslateY
},
BoxWithConstraints(
contentAlignment = Alignment.TopCenter,
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(3.dp),
val chipHeight = 14.dp
val chipSpacing = 3.dp
val maxChipCount =
((maxHeight + chipSpacing) / (chipHeight + chipSpacing))
.toInt()
.coerceAtLeast(1)

Box(
modifier =
Modifier
.graphicsLayer {
alpha = eventLabelAlpha
scaleX = chipScale
scaleY = chipScale
translationY = chipTranslateY
},
contentAlignment = Alignment.TopCenter,
) {
cell.markers.take(3).forEach { marker ->
ScheduleChip(
text = marker.title,
)
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(chipSpacing),
) {
cell.markers.take(maxChipCount).forEach { marker ->
ScheduleChip(
text = marker.title,
)
}
}
}
}
Expand All @@ -129,7 +141,7 @@ fun CalendarDay(
horizontalArrangement = Arrangement.spacedBy(3.dp),
verticalAlignment = Alignment.CenterVertically,
) {
cell.markers.take(2).forEach { _ ->
cell.markers.take(3).forEach { _ ->
Box(
modifier =
Modifier
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.ondot.calendar.ui.component
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
Expand All @@ -22,6 +23,7 @@ fun ScheduleChip(text: String) {
modifier =
Modifier
.fillMaxWidth()
.height(14.dp)
.clip(RoundedCornerShape(2.dp))
.background(Green500)
.padding(horizontal = 2.dp, vertical = 1.dp),
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ target.sdk=36
compile.sdk=36

# Version
version.code=33
version.code=34
version.name=1.3.0
4 changes: 2 additions & 2 deletions iosApp/iosApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@
CODE_SIGN_ENTITLEMENTS = iosApp/iosApp.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 33;
CURRENT_PROJECT_VERSION = 34;
DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\"";
ENABLE_PREVIEWS = YES;
FRAMEWORK_SEARCH_PATHS = (
Expand Down Expand Up @@ -520,7 +520,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 33;
CURRENT_PROJECT_VERSION = 34;
DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\"";
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = Y2Q4TFA96S;
Expand Down
Loading