Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e37a989
♻️ Refactor: 캘린더 칩 사이즈 변경
dogmania May 2, 2026
e6013f1
♻️ Refactor: Chip 사이 간격 수정
dogmania May 16, 2026
c5d9877
✨ Feat: pad 없는 날짜 포맷팅 메서드 추가
dogmania May 16, 2026
e906211
♻️ Refactor: 캘린더 바텀시트 날짜 렌더링 형식 변경
dogmania May 16, 2026
3285511
♻️ Refactor: GNB 아이콘 변경 및 간격 수정
dogmania May 16, 2026
0c546a1
🍱 Chore: String 리소스 추가
dogmania May 16, 2026
b069b50
✨ Feat: TodayFAB 컴포넌트 구현
dogmania May 16, 2026
a779af4
✨ Feat: 현재 날짜와 다른 달로 넘겼을 때 TodayFAB 렌더링 및 클릭 시 오늘 날짜로 복귀
dogmania May 16, 2026
80243e7
♻️ Refactor: ktlint 적용
dogmania May 16, 2026
abf5252
🍱 Chore: String 리소스 추가
dogmania May 16, 2026
80ed51d
✨ Feat: preparationNote 상태 변수 추가
dogmania May 16, 2026
88e66eb
✨ Feat: 준비물 정보 렌더링
dogmania May 16, 2026
c59b06b
🍱 Chore: String 리소스 추가
dogmania May 19, 2026
2c8e590
✨ Feat: 칩 최대 개수 초과시 남은 개수 렌더링
dogmania May 19, 2026
2258b23
✨ Feat: hasActivieAlarm 프로퍼티 추가
dogmania May 20, 2026
e86ae27
✨ Feat: isRepeat, hasActiveAlarm 상태 저장 로직 추가
dogmania May 20, 2026
0b53a82
✨ Feat: isRepeat, hasActiveAlarm에 따른 색상 변경 로직 구현
dogmania May 20, 2026
f417601
⬆️ Upgrade: 버전 업데이트
dogmania May 31, 2026
a19b659
✨Feat: System Trace expect 정의
dogmania Jun 2, 2026
6468261
✨ Feat: System Trace 로깅 Modifier 확장 메서드 구현
dogmania Jun 2, 2026
ce15f5c
✨ Feat: system trace 기록 메서드 호출
dogmania Jun 2, 2026
e6c7c40
🍱 Chore: BodySmallM 폰트 스타일 추가
dogmania Jun 2, 2026
f305161
✨ Feat: 반복, 비반복, off 일정 칩 색상 및 border 적용
dogmania Jun 2, 2026
6d83125
♻️ Refactor: 집 주소와 달라지면 집에서 출발해요 체크박스 해제
dogmania Jun 2, 2026
f12b8b5
♻️ Refactor: 준비물 텍스트 오버플로우 처리
dogmania Jun 2, 2026
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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,6 @@ fun OnDotTextStyle.toTextStyle(): TextStyle {
OnDotTextStyle.BodySmallR1 -> typo.bodySmallR1
OnDotTextStyle.BodySmallR2 -> typo.bodySmallR2
OnDotTextStyle.BodySmallR3 -> typo.bodySmallR3
OnDotTextStyle.BodySmallM -> typo.bodySmallM
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ data class OnDotTypography(
val bodySmallR1: TextStyle,
val bodySmallR2: TextStyle,
val bodySmallR3: TextStyle,
val bodySmallM: TextStyle,
)

@Composable
Expand Down Expand Up @@ -79,5 +80,6 @@ fun OnDotTypo(): OnDotTypography {
bodySmallR1 = TextStyle(fontFamily = fontFamily, fontWeight = FontWeight.Normal, fontSize = 12.sp, lineHeight = lh(12)),
bodySmallR2 = TextStyle(fontFamily = fontFamily, fontWeight = FontWeight.Normal, fontSize = 11.sp, lineHeight = lh(11)),
bodySmallR3 = TextStyle(fontFamily = fontFamily, fontWeight = FontWeight.Normal, fontSize = 8.sp, lineHeight = lh(8)),
bodySmallM = TextStyle(fontFamily = fontFamily, fontWeight = FontWeight.Medium, fontSize = 9.sp, lineHeight = lh(9)),
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,13 @@ const val WORD_DELETE = "삭제"
const val WORD_YES = "예"
const val WORD_NO = "아니요"
const val WORD_PREPARATION = "준비"
const val WORD_PREPARATION_ITEM = "준비물"
const val WORD_DEPARTURE = "출발"
const val WORD_DELETE_ACCOUNT_ACTION = "탈퇴하기"
const val WORD_RESTORE_ACTION = "되돌리기"
const val WORD_HOME = "집"
const val WORD_EVERYTIME = "에브리타임"
const val WORD_TODAY = "오늘"

// 알람 카테고리
const val CATEGORY_GENERAL = "기본"
Expand Down Expand Up @@ -255,3 +257,5 @@ const val EVERYTIME_ROUTE_LOADING_LABEL = "수업 일정에 맞춰\n알람을

// Calendar
const val CALENDAR_EMPTY_SCHEDULES_GUIDE = "등록된 알람이 없습니다."

fun calendarOverflowScheduleCount(count: Int) = "+$count"
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.ondot.ui.util

import android.os.Trace
import com.dh.core.ui.BuildConfig

actual inline fun <T> systemTrace(
name: String,
block: () -> T,
): T {
if (!BuildConfig.DEBUG) {
return block()
}

Trace.beginSection(name)
return try {
block()
} finally {
Trace.endSection()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.ondot.ui.util

expect inline fun <T> systemTrace(
name: String,
block: () -> T,
): T
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.ondot.ui.util

import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.layout.layout

/**
* Compose의 Layout 단계에서
* measure(크기 계산), layout(위치 계산) 각각의 시간이 얼마나 걸리는지를 System Trace에 기록하는 함수
* */
fun Modifier.traceLayout(name: String): Modifier =
layout { measurable, constraints ->
val placeable =
systemTrace("measure:$name") {
measurable.measure(constraints)
}

systemTrace("layout:$name") {
layout(placeable.width, placeable.height) {
placeable.placeRelative(0, 0)
}
}
Comment thread
dogmania marked this conversation as resolved.
}

/**
* Compose의 Draw 단계에서
* draw(그리기) 시간이 얼마나 걸리는지를 System Trace에 기록하는 함수
* */
fun Modifier.traceDraw(name: String): Modifier =
drawWithContent {
systemTrace("draw:$name") {
drawContent()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.ondot.ui.util

actual inline fun <T> systemTrace(
name: String,
block: () -> T,
): T = block()
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,9 @@ object DateTimeFormatter {
/** LocalDate 06월 13일 화요일 형태로 포맷 */
fun LocalDate.formatKoreanMonthDay(): String = "${month.number.pad2()}월 ${day.pad2()}일 ${this.extractDayOfWeek()}"

/** LocalDate 6월 13일 화요일 형태로 포맷 */
fun LocalDate.formatKoreanMonthDayWithoutPad(): String = "${month.number}월 ${day}일 ${this.extractDayOfWeek()}"

/** iso 문자열을 days 만큼 뒤로 미룸 */
fun plusDays(
iso: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,6 @@ data class CalendarScheduleSummaryResponse(
val isRepeat: Boolean,
@SerialName("appointmentAt")
val appointmentAt: String,
@SerialName("hasActiveAlarm")
val hasActiveAlarm: Boolean,
Comment thread
dogmania marked this conversation as resolved.
)
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ fun CalendarRangeResponse.toDomain(): List<CalendarDateScheduleSummary> =
CalendarDateScheduleSummaryItem(
scheduleId = it.scheduleId,
title = it.title,
isRepeat = it.isRepeat,
hasActiveAlarm = it.hasActiveAlarm,
)
},
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ data class CalendarDateScheduleSummary(
data class CalendarDateScheduleSummaryItem(
val scheduleId: Long,
val title: String,
val isRepeat: Boolean,
val hasActiveAlarm: Boolean,
)
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ enum class OnDotTextStyle {
BodySmallR1,
BodySmallR2,
BodySmallR3,
BodySmallM,
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ sealed interface CalendarIntent : Intent {

data object MoveToNextMonth : CalendarIntent

data object MoveToToday : CalendarIntent

data class ToggleAlarm(
val scheduleId: Long,
val enabled: Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ data class CalendarScheduleItemUiModel(
val isAlarmEnabled: Boolean,
val isPast: Boolean,
val repeatDays: List<Int>,
val preparationNote: String = "",
)
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ data class CalendarMonth(
data class CalendarScheduleMarker(
val scheduleId: Long,
val title: String,
val isRepeat: Boolean,
val hasActiveAlarm: Boolean,
)

@Immutable
Expand Down Expand Up @@ -156,6 +158,7 @@ fun Schedule.toCalendarScheduleItemUiModel(
isAlarmEnabled = hasActiveAlarm,
isPast = isPast,
repeatDays = repeatDays,
preparationNote = preparationNote,
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.datetime.DatePeriod
import kotlinx.datetime.LocalDate
import kotlinx.datetime.TimeZone
import kotlinx.datetime.number
import kotlinx.datetime.plus
import kotlinx.datetime.toLocalDateTime
import kotlin.coroutines.cancellation.CancellationException
import kotlin.time.Clock
import kotlin.time.ExperimentalTime

class CalendarViewModel(
private val calendarRepository: CalendarRepository,
Expand Down Expand Up @@ -84,6 +88,21 @@ class CalendarViewModel(
loadSchedulesFor(nextSelectedDate)
}

CalendarIntent.MoveToToday -> {
val today = today()
val todayMonth = CalendarMonth(today.year, today.month.number)

reduce {
copy(
currentMonth = todayMonth,
selectedDate = today,
)
}

getScheduleMarkersInRange(today)
loadSchedulesFor(today)
}

is CalendarIntent.ToggleAlarm -> {
toggleAlarm(
scheduleId = intent.scheduleId,
Expand Down Expand Up @@ -141,7 +160,12 @@ class CalendarViewModel(
summaries.associate { summary ->
summary.date to
summary.schedules.map { schedule ->
CalendarScheduleMarker(scheduleId = schedule.scheduleId, title = schedule.title)
CalendarScheduleMarker(
scheduleId = schedule.scheduleId,
title = schedule.title,
isRepeat = schedule.isRepeat,
hasActiveAlarm = schedule.hasActiveAlarm,
)
}
}

Expand Down Expand Up @@ -513,3 +537,10 @@ private fun daysInMonth(
}

private fun isLeapYear(year: Int): Boolean = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)

@OptIn(ExperimentalTime::class)
private fun today(): LocalDate =
Clock.System
.now()
.toLocalDateTime(TimeZone.currentSystemDefault())
.date
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ 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.CalendarMonth
import com.ondot.calendar.contract.CalendarSheetAnchor
import com.ondot.calendar.contract.CalendarSheetState
import com.ondot.calendar.contract.CalendarSideEffect
Expand All @@ -60,6 +61,7 @@ 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.calendar.ui.component.TodayFAB
import com.ondot.designsystem.components.OnDotDialog
import com.ondot.designsystem.components.OnDotText
import com.ondot.designsystem.theme.OnDotColor.Gray800
Expand All @@ -70,10 +72,15 @@ import com.ondot.domain.model.enums.OnDotTextStyle
import com.ondot.ui.util.ToastManager
import kotlinx.coroutines.launch
import kotlinx.datetime.LocalDate
import kotlinx.datetime.TimeZone
import kotlinx.datetime.number
import kotlinx.datetime.toLocalDateTime
import ondot.core.design_system.generated.resources.Res
import ondot.core.design_system.generated.resources.ic_plus
import org.jetbrains.compose.resources.painterResource
import org.koin.compose.viewmodel.koinViewModel
import kotlin.time.Clock
import kotlin.time.ExperimentalTime

@Composable
fun CalendarRoute(
Expand Down Expand Up @@ -102,19 +109,22 @@ fun CalendarRoute(
onSelectDate = { viewModel.dispatch(CalendarIntent.SelectDate(it)) },
onMoveToPreviousMonth = { viewModel.dispatch(CalendarIntent.MoveToPreviousMonth) },
onMoveToNextMonth = { viewModel.dispatch(CalendarIntent.MoveToNextMonth) },
onMoveToToday = { viewModel.dispatch(CalendarIntent.MoveToToday) },
onToggleAlarm = { scheduleId, enabled -> viewModel.dispatch(CalendarIntent.ToggleAlarm(scheduleId, enabled)) },
onAddSchedule = navigateToCreateGeneralSchedule,
onDelete = { id, isPast -> viewModel.dispatch(CalendarIntent.DeleteScheduleItem(id, isPast)) },
onClickSchedule = { navigateToEditSchedule(it) },
)
}

@OptIn(ExperimentalTime::class)
@Composable
private fun CalendarScreen(
uiState: CalendarUiState,
onSelectDate: (LocalDate) -> Unit,
onMoveToPreviousMonth: () -> Unit,
onMoveToNextMonth: () -> Unit,
onMoveToToday: () -> Unit,
onToggleAlarm: (Long, Boolean) -> Unit,
onAddSchedule: () -> Unit,
onDelete: (Long, Boolean) -> Unit,
Expand Down Expand Up @@ -149,6 +159,20 @@ private fun CalendarScreen(

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

// TodayFAB 렌더링을 위한 상태 변수
val today =
remember {
Clock.System
.now()
.toLocalDateTime(TimeZone.currentSystemDefault())
.date
}
val todayMonth =
remember(today) {
CalendarMonth(today.year, today.month.number)
}
val shouldShowTodayFab = uiState.currentMonth != todayMonth

BoxWithConstraints(
modifier =
Modifier
Expand Down Expand Up @@ -300,7 +324,7 @@ private fun CalendarScreen(
Spacer(Modifier.height(20.dp))

CalendarWeekHeader(
modifier = Modifier.padding(horizontal = 22.dp),
modifier = Modifier.padding(horizontal = 16.dp),
)
}

Expand All @@ -309,7 +333,7 @@ private fun CalendarScreen(
Modifier
.fillMaxWidth()
.height(calendarBodyHeight)
.padding(horizontal = 22.dp)
.padding(horizontal = 16.dp)
.clip(RoundedCornerShape(bottomStart = 24.dp, bottomEnd = 24.dp)),
) {
AnimatedContent(
Expand Down Expand Up @@ -384,6 +408,7 @@ private fun CalendarScreen(
onDelete = onDelete,
onClickSchedule = onClickSchedule,
onShowScheduleDeleteDialog = { scheduleIdPendingDelete = it },
traceName = "CalendarBottomSheetBase",
)
}
}
Expand Down Expand Up @@ -417,6 +442,7 @@ private fun CalendarScreen(
onDelete = onDelete,
onClickSchedule = onClickSchedule,
onShowScheduleDeleteDialog = { scheduleIdPendingDelete = it },
traceName = "CalendarBottomSheetOverlay",
)
}

Expand All @@ -428,6 +454,16 @@ private fun CalendarScreen(
onClick = onAddSchedule,
)

if (shouldShowTodayFab) {
TodayFAB(
modifier =
Modifier
.align(Alignment.BottomCenter)
.padding(bottom = 24.dp),
onClick = onMoveToToday,
)
}

if (scheduleIdPendingDelete != null) {
OnDotDialog(
dialogType = DialogType.TWO,
Expand Down
Loading
Loading