diff --git a/app/src/androidTest/java/com/afternote/afternote_fe/DailyQuestionResumeFailureAndroidTest.kt b/app/src/androidTest/java/com/afternote/afternote_fe/DailyQuestionResumeFailureAndroidTest.kt index c39be79572..8e9bfc2364 100644 --- a/app/src/androidTest/java/com/afternote/afternote_fe/DailyQuestionResumeFailureAndroidTest.kt +++ b/app/src/androidTest/java/com/afternote/afternote_fe/DailyQuestionResumeFailureAndroidTest.kt @@ -74,7 +74,12 @@ class DailyQuestionResumeFailureAndroidTest { composeRule.setContent { AfternoteTheme { - DailyQuestionWriteScreen(viewModel = viewModel, onSubmitSuccess = {}) + DailyQuestionWriteScreen( + viewModel = viewModel, + onSubmitSuccess = {}, + onBackClick = {}, + onDraftListClick = {}, + ) } } @@ -128,7 +133,12 @@ class DailyQuestionResumeFailureAndroidTest { composeRule.setContent { AfternoteTheme { - DailyQuestionWriteScreen(viewModel = viewModel, onSubmitSuccess = {}) + DailyQuestionWriteScreen( + viewModel = viewModel, + onSubmitSuccess = {}, + onBackClick = {}, + onDraftListClick = {}, + ) } } diff --git a/app/src/androidTest/java/com/afternote/afternote_fe/TimeLetterMindRecordCompletionAndroidTest.kt b/app/src/androidTest/java/com/afternote/afternote_fe/TimeLetterMindRecordCompletionAndroidTest.kt index 936444c658..b20305ae1d 100644 --- a/app/src/androidTest/java/com/afternote/afternote_fe/TimeLetterMindRecordCompletionAndroidTest.kt +++ b/app/src/androidTest/java/com/afternote/afternote_fe/TimeLetterMindRecordCompletionAndroidTest.kt @@ -368,7 +368,11 @@ class TimeLetterMindRecordCompletionAndroidTest { composeRule.setContent { AfternoteTheme { - DailyQuestionAnswerListScreen(viewModel = activeViewModel, onItemClick = { _, _ -> }) + DailyQuestionAnswerListScreen( + viewModel = activeViewModel, + onItemClick = { _, _ -> }, + onEditClick = {}, + ) } } @@ -432,7 +436,11 @@ class TimeLetterMindRecordCompletionAndroidTest { val activeWriteViewModel = writeViewModel AfternoteTheme { if (activeWriteViewModel == null) { - DailyQuestionAnswerListScreen(viewModel = listViewModel, onItemClick = { _, _ -> }) + DailyQuestionAnswerListScreen( + viewModel = listViewModel, + onItemClick = { _, _ -> }, + onEditClick = {}, + ) } else { DailyQuestionWriteScreen( viewModel = activeWriteViewModel, @@ -441,6 +449,8 @@ class TimeLetterMindRecordCompletionAndroidTest { writeViewModel = null listViewModel.refreshOnReturn() }, + onBackClick = {}, + onDraftListClick = {}, ) } } @@ -550,11 +560,15 @@ class TimeLetterMindRecordCompletionAndroidTest { errorReporter = FakeErrorReporter(), ) }, + onBackClick = {}, + onDailyQuestionDraftClick = {}, ) } else { DiaryWriteScreen( viewModel = activeWriteViewModel, onSubmitSuccess = { submitSuccessCalls += 1 }, + onBackClick = {}, + onDraftListClick = {}, ) } } diff --git a/docs/qa/assumptions.md b/docs/qa/assumptions.md index 05b3f70340..3bced234dd 100644 --- a/docs/qa/assumptions.md +++ b/docs/qa/assumptions.md @@ -392,6 +392,34 @@ navigate 대상 한 줄. `EditorFormState.currentServiceOptions` 다. 기존 값 정리(마이그레이션·삭제)가 확정되면 보존 동작을 그 정책으로 바꾼다. +## #1540 — no-op 콜백 디폴트 청소에서 드러난 배선 누락 2건 + +디폴트를 걷어내자 **컴파일러가 실호출부 2곳을 드러냈다.** 둘 다 사용자에게 버튼이 보이는데 +눌러도 아무 일이 없던 자리다. 고친 방향과 근거를 남긴다. + +### 1. `TextStyleToolbar` 의 링크·«T» 버튼 (추측 아님) + +`WriteTextField` 가 `onLinkClick`·`onTypeClick` 을 넘기지 않아 no-op 이었다. **같은 파일의 +`BottomToolbar` 가 같은 두 버튼을 갖고 있어** 배선을 그대로 가져왔다 — 스타일 툴바가 열리면 +하단 툴바를 덮으므로 같은 두 affordance 를 유지해야 한다. + +| 버튼 | BottomToolbar | 이번에 TextStyleToolbar 에 붙인 것 | +|---|---|---| +| 링크 아이콘(`core_ui_ic_link`) | `sheet = KeyboardSheet.MediaSelect` | 동일 | +| «T» | `showTextStyleToolbar = !showTextStyleToolbar` | 동일(= 열린 툴바를 닫는다) | + +### 2. 주간 리포트 HISTORY 의 «더보기» (판단이 들어감) + +`WeeklyReportScreen` 이 `DailyQuestionListCard(answer = …)` 만 넘겨, 수정·삭제 메뉴가 뜨는데 +둘 다 no-op 이었다. + +**배선하지 않고 감췄다.** 주간 리포트는 읽기 전용 요약이고 편집·삭제는 데일리질문 목록의 +몫이라고 봤다. 배선하려면 VM 삭제 경로와 편집 내비게이션이 새로 필요해 refactor 범위를 +벗어난다. #1540 이 든 처방(「`= {}` 로 죽은 버튼을 그리는 대신 nullable + UI 숨김」)과도 같다. + +읽기 전용이 아니라 **편집 가능이 맞다면** 이 판단이 틀린 것이므로, 그때는 `onEdit`·`onDelete` +에 실핸들러를 넘기면 메뉴가 그대로 돌아온다(컴포넌트는 이미 nullable 로 열려 있다). + ## #700 — 홈 시안 정본 (해소) + 타임레터 NEXT STEP 문구 (추측 진행) **정본은 확정됐다 — 추측이 아니다.** 파일에 페이지가 둘뿐이고(`정리 Screen Design`, diff --git a/feature/home/presentation/src/main/kotlin/com/afternote/feature/home/presentation/WeeklySummaryGrid.kt b/feature/home/presentation/src/main/kotlin/com/afternote/feature/home/presentation/WeeklySummaryGrid.kt index 2b7dec1465..a2c7cb7ffd 100644 --- a/feature/home/presentation/src/main/kotlin/com/afternote/feature/home/presentation/WeeklySummaryGrid.kt +++ b/feature/home/presentation/src/main/kotlin/com/afternote/feature/home/presentation/WeeklySummaryGrid.kt @@ -47,8 +47,8 @@ fun WeeklySummaryGrid( * `null` 은 «아직 모름» 이라 숫자 대신 대시를 그린다. 0 은 확정값이라 그대로 그린다. */ recordedCount: Int?, - onImageClick: () -> Unit = {}, - onCountCardClick: () -> Unit = {}, + onImageClick: () -> Unit, + onCountCardClick: () -> Unit, ) { BoxWithConstraints(modifier = modifier.fillMaxWidth()) { val gap = 8.dp @@ -152,6 +152,10 @@ fun WeeklySummaryGrid( @Composable private fun WeeklySummaryGridPreview() { AfternoteTheme { - WeeklySummaryGrid(recordedCount = 3) + WeeklySummaryGrid( + recordedCount = 3, + onCountCardClick = {}, + onImageClick = {}, + ) } } diff --git a/feature/home/presentation/src/screenshotTest/kotlin/com/afternote/feature/home/presentation/WeeklySummaryGridScreenshotTest.kt b/feature/home/presentation/src/screenshotTest/kotlin/com/afternote/feature/home/presentation/WeeklySummaryGridScreenshotTest.kt index 80c5985b97..508bc3330d 100644 --- a/feature/home/presentation/src/screenshotTest/kotlin/com/afternote/feature/home/presentation/WeeklySummaryGridScreenshotTest.kt +++ b/feature/home/presentation/src/screenshotTest/kotlin/com/afternote/feature/home/presentation/WeeklySummaryGridScreenshotTest.kt @@ -13,6 +13,11 @@ import com.android.tools.screenshot.PreviewTest @Composable internal fun weeklySummaryGridScreenshot() { AfternoteTheme { - WeeklySummaryGrid(recordedCount = 3, modifier = Modifier.padding(16.dp)) + WeeklySummaryGrid( + recordedCount = 3, + modifier = Modifier.padding(16.dp), + onCountCardClick = {}, + onImageClick = {}, + ) } } diff --git a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/DailyQuestionListCard.kt b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/DailyQuestionListCard.kt index 772e1f6d52..47b3ebc635 100644 --- a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/DailyQuestionListCard.kt +++ b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/DailyQuestionListCard.kt @@ -50,10 +50,17 @@ private val DateFormatter = DateTimeFormatter.ofPattern("yyyy.MM.dd") fun DailyQuestionListCard( answer: DailyQuestion, modifier: Modifier = Modifier, - /** 카드 전체 탭 — 저장된 기록 본문을 여는 상세 화면으로 간다 (#759). */ - onClick: () -> Unit = {}, - onEdit: () -> Unit = {}, - onDelete: () -> Unit = {}, + /** + * 카드 전체 탭 — 저장된 기록 본문을 여는 상세 화면으로 간다 (#759). + * + * **`null` 이면 클릭 자체를 붙이지 않는다** (#1540 리뷰). + * + * no-op 을 넘기면 `Role.Button` 이 그대로 실려 스크린리더가 「버튼」으로 읽는데 눌러도 + * 아무 일이 없다 — 읽기 전용으로 쓰는 자리(주간 리포트 HISTORY)가 그랬다. + */ + onClick: (() -> Unit)?, + onEdit: (() -> Unit)?, + onDelete: (() -> Unit)?, ) { OutlinedCard( colors = @@ -62,7 +69,10 @@ fun DailyQuestionListCard( ), border = BorderStroke(1.dp, color = AfternoteDesign.colors.gray2), shape = CardShape, - modifier = modifier.fillMaxWidth().clickable(role = Role.Button, onClick = onClick), + modifier = + modifier + .fillMaxWidth() + .then(if (onClick != null) Modifier.clickable(role = Role.Button, onClick = onClick) else Modifier), ) { if (answer.imageUrl != null) { ThumbnailCardContent(answer = answer, onEdit = onEdit, onDelete = onDelete) @@ -76,8 +86,8 @@ fun DailyQuestionListCard( @Composable private fun TextCardContent( answer: DailyQuestion, - onEdit: () -> Unit, - onDelete: () -> Unit, + onEdit: (() -> Unit)?, + onDelete: (() -> Unit)?, ) { Column( modifier = Modifier.padding(16.dp), @@ -106,8 +116,8 @@ private fun TextCardContent( @Composable private fun ThumbnailCardContent( answer: DailyQuestion, - onEdit: () -> Unit, - onDelete: () -> Unit, + onEdit: (() -> Unit)?, + onDelete: (() -> Unit)?, ) { Row( modifier = Modifier.padding(12.dp), @@ -149,8 +159,8 @@ private fun ThumbnailCardContent( @Composable private fun CardHeaderRow( date: LocalDate, - onEdit: () -> Unit, - onDelete: () -> Unit, + onEdit: (() -> Unit)?, + onDelete: (() -> Unit)?, ) { var menuExpanded by remember { mutableStateOf(false) } @@ -172,28 +182,35 @@ private fun CardHeaderRow( ) } - Box { - Icon( - painter = painterResource(R.drawable.mindrecord_horizontal), - tint = AfternoteDesign.colors.gray5, - contentDescription = stringResource(R.string.mindrecord_more_menu_cd), - modifier = - Modifier - .size(20.dp) - .clickable(role = Role.Button) { menuExpanded = true }, - ) - if (menuExpanded) { - RecordActionPopup( - onDismiss = { menuExpanded = false }, - onDelete = { - menuExpanded = false - onDelete() - }, - onEdit = { - menuExpanded = false - onEdit() - }, + // **핸들러가 없으면 «더보기» 자체를 그리지 않는다** (#1540). + // + // 종전에는 `= {}` 디폴트라, 핸들러를 안 넘긴 화면(주간 리포트 HISTORY)에서도 메뉴가 + // 뜨고 «수정»·«삭제» 를 눌러도 아무 일이 없었다. 눌러도 아무 일 없는 버튼을 그리는 + // 대신 없는 상호작용은 보여 주지 않는다. + if (onEdit != null && onDelete != null) { + Box { + Icon( + painter = painterResource(R.drawable.mindrecord_horizontal), + tint = AfternoteDesign.colors.gray5, + contentDescription = stringResource(R.string.mindrecord_more_menu_cd), + modifier = + Modifier + .size(20.dp) + .clickable(role = Role.Button) { menuExpanded = true }, ) + if (menuExpanded) { + RecordActionPopup( + onDismiss = { menuExpanded = false }, + onDelete = { + menuExpanded = false + onDelete() + }, + onEdit = { + menuExpanded = false + onEdit() + }, + ) + } } } } @@ -210,6 +227,9 @@ private fun DailyQuestionCardPreview() { content = "아무 말 없이 그저 나의 곁을 지켜주는 아내가 고맙다.", date = LocalDate.now(), ), + onClick = {}, + onDelete = {}, + onEdit = {}, ) } } @@ -226,6 +246,9 @@ private fun DailyQuestionCardWithImagePreview() { date = LocalDate.now(), imageUrl = "https://example.com/image.jpg", ), + onClick = {}, + onDelete = {}, + onEdit = {}, ) } } diff --git a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/DiaryCard.kt b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/DiaryCard.kt index 48b54d6a4d..c60f645bb8 100644 --- a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/DiaryCard.kt +++ b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/DiaryCard.kt @@ -53,9 +53,9 @@ fun DiaryCard( diary: DailyDiary, modifier: Modifier = Modifier, /** 카드 전체 탭 — 저장된 기록 본문을 여는 상세 화면으로 간다 (#759). */ - onClick: () -> Unit = {}, - onEdit: () -> Unit = {}, - onDelete: () -> Unit = {}, + onClick: () -> Unit, + onEdit: () -> Unit, + onDelete: () -> Unit, ) { var menuExpanded by remember { mutableStateOf(false) } @@ -189,6 +189,9 @@ private fun DiaryCardPreview() { emotion = "😊", imageUrl = "https://example.com/image.jpg", ), + onClick = {}, + onDelete = {}, + onEdit = {}, ) } } @@ -205,6 +208,9 @@ private fun DiaryCardNoImagePreview() { date = LocalDate.now(), emotion = "😊", ), + onClick = {}, + onDelete = {}, + onEdit = {}, ) } } diff --git a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/DiaryComponent.kt b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/DiaryComponent.kt index e5eb2f5925..256bf50b9b 100644 --- a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/DiaryComponent.kt +++ b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/DiaryComponent.kt @@ -51,9 +51,9 @@ fun DiaryComponent( diary: DailyDiary, modifier: Modifier = Modifier, /** 카드 전체 탭 — 저장된 기록 본문을 여는 상세 화면으로 간다 (#759). */ - onClick: () -> Unit = {}, - onEdit: () -> Unit = {}, - onDelete: () -> Unit = {}, + onClick: () -> Unit, + onEdit: () -> Unit, + onDelete: () -> Unit, ) { var menuExpanded by remember { mutableStateOf(false) } @@ -171,6 +171,9 @@ private fun DiaryComponentPreview() { emotion = "😊", imageUrl = "https://example.com/image.jpg", ), + onClick = {}, + onDelete = {}, + onEdit = {}, ) } } @@ -187,6 +190,9 @@ private fun DiaryComponentNoImagePreview() { date = LocalDate.now(), emotion = "😊", ), + onClick = {}, + onDelete = {}, + onEdit = {}, ) } } diff --git a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/InsightCard.kt b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/InsightCard.kt deleted file mode 100644 index 4084137743..0000000000 --- a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/InsightCard.kt +++ /dev/null @@ -1,67 +0,0 @@ -package com.afternote.feature.mindrecord.presentation.component - -import androidx.compose.foundation.BorderStroke -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.CardDefaults -import androidx.compose.material3.OutlinedCard -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import com.afternote.core.ui.theme.AfternoteDesign -import com.afternote.core.ui.theme.AfternoteTheme -import com.afternote.feature.mindrecord.presentation.R - -@Composable -fun InsightCard( - modifier: Modifier = Modifier, - bodyText: String = stringResource(R.string.mindrecord_insight_card_default_body), -) { - OutlinedCard( - colors = - CardDefaults.cardColors( - containerColor = Color(0xFFFFFFFF), - ), - border = BorderStroke(1.dp, color = Color(0xFF000000).copy(alpha = 0.05f)), - modifier = modifier.fillMaxWidth(), - ) { - Column(modifier = Modifier.padding(16.dp)) { - Text( - text = "INSIGHTS", - style = AfternoteDesign.typography.mono, - color = AfternoteDesign.colors.gray6, - ) - - Spacer(modifier = Modifier.height(17.dp)) - - Text( - text = bodyText, - style = AfternoteDesign.typography.bodySmallB, - color = AfternoteDesign.colors.black.copy(alpha = 0.7f), - ) - - Spacer(modifier = Modifier.height(17.dp)) - - Text( - text = stringResource(R.string.mindrecord_insight_card_footer), - style = AfternoteDesign.typography.captionLargeR, - color = AfternoteDesign.colors.gray6, - ) - } - } -} - -@Preview(showBackground = true) -@Composable -private fun InsightCardPreview() { - AfternoteTheme { - InsightCard() - } -} diff --git a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/KeyBoardToolBar.kt b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/KeyBoardToolBar.kt index 603d3109cf..748436e42f 100644 --- a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/KeyBoardToolBar.kt +++ b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/KeyBoardToolBar.kt @@ -42,9 +42,9 @@ fun BottomToolbar( onTextStyleClick: () -> Unit, onAlignChange: (TextAlign) -> Unit, modifier: Modifier = Modifier, - onLinkClick: () -> Unit = {}, - onSaveDraftClick: () -> Unit = {}, - onDraftCountClick: () -> Unit = {}, + onLinkClick: () -> Unit, + onSaveDraftClick: () -> Unit, + onDraftCountClick: () -> Unit, /** 임시저장 개수. `null` 은 아직 모름(조회 중·실패) — 0 으로 단정하지 않는다. */ draftCount: Int? = null, ) { @@ -133,8 +133,8 @@ fun TextStyleToolbar( onTextStyleChange: (TextStyleType) -> Unit, styleState: TextStyleState, modifier: Modifier = Modifier, - onLinkClick: () -> Unit = {}, - onTypeClick: () -> Unit = {}, + onLinkClick: () -> Unit, + onTypeClick: () -> Unit, ) { Column( modifier = diff --git a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/TodayQuestionCard.kt b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/TodayQuestionCard.kt index 09e47ccdc1..dee71c4b27 100644 --- a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/TodayQuestionCard.kt +++ b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/TodayQuestionCard.kt @@ -51,7 +51,7 @@ fun TodayQuestionCard( modifier: Modifier = Modifier, questionText: String? = null, isQuestionLoading: Boolean = false, - onAnswerClick: () -> Unit = {}, + onAnswerClick: () -> Unit, ) { Column( modifier = @@ -168,6 +168,7 @@ private fun TodayQuestionCardPreview() { dateText = "2026.04.10", questionText = "오늘 내가 배운\n가장 작은 교훈은 무엇인가요?", modifier = Modifier.padding(16.dp), + onAnswerClick = {}, ) } } @@ -180,6 +181,7 @@ private fun TodayQuestionCardUnavailablePreview() { dateText = "2026.04.10", questionText = null, modifier = Modifier.padding(16.dp), + onAnswerClick = {}, ) } } diff --git a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/WeeklyEmotionCard.kt b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/WeeklyEmotionCard.kt deleted file mode 100644 index 33be8f4345..0000000000 --- a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/WeeklyEmotionCard.kt +++ /dev/null @@ -1,60 +0,0 @@ -package com.afternote.feature.mindrecord.presentation.component - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.CardDefaults -import androidx.compose.material3.OutlinedCard -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import com.afternote.core.ui.theme.AfternoteDesign -import com.afternote.core.ui.theme.AfternoteTheme -import com.afternote.feature.mindrecord.presentation.R - -@Composable -fun WeeklyEmotionCard(modifier: Modifier = Modifier) { - OutlinedCard( - colors = - CardDefaults.cardColors( - containerColor = AfternoteDesign.colors.gray2, - ), - modifier = modifier.fillMaxWidth(), - shape = RoundedCornerShape(100.dp), - ) { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.SpaceBetween, - modifier = - Modifier - .fillMaxWidth() - .padding(horizontal = 17.dp, vertical = 9.dp), - ) { - Text( - text = stringResource(R.string.mindrecord_weekly_report_avg_emotion_weekly), - style = AfternoteDesign.typography.captionLargeR, - color = AfternoteDesign.colors.gray9, - ) - - Text( - text = stringResource(R.string.mindrecord_weekly_report_avg_mood_good), - style = AfternoteDesign.typography.captionLargeR, - color = AfternoteDesign.colors.gray9, - ) - } - } -} - -@Preview(showBackground = true) -@Composable -private fun WeeklyEmotionCardPreview() { - AfternoteTheme { - WeeklyEmotionCard() - } -} diff --git a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/WeeklyReportCard.kt b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/WeeklyReportCard.kt deleted file mode 100644 index 8f781828a9..0000000000 --- a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/WeeklyReportCard.kt +++ /dev/null @@ -1,106 +0,0 @@ -package com.afternote.feature.mindrecord.presentation.component - -import androidx.compose.foundation.border -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.Text -import androidx.compose.material3.VerticalDivider -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import com.afternote.core.ui.theme.AfternoteDesign -import com.afternote.core.ui.theme.AfternoteTheme -import com.afternote.feature.mindrecord.presentation.R - -@Composable -fun WeeklyReportCard(modifier: Modifier = Modifier) { - Box( - modifier = - modifier.border( - 1.dp, - color = AfternoteDesign.colors.gray2, - shape = RoundedCornerShape(6.dp), - ), - ) { - Column( - modifier = - Modifier - .fillMaxWidth() - .padding(21.dp), - ) { - Text( - text = stringResource(R.string.mindrecord_weekly_report_title), - style = AfternoteDesign.typography.bodyLargeB, - ) - Spacer(modifier = Modifier.height(8.dp)) - Text( - text = stringResource(R.string.mindrecord_weekly_report_subtitle), - style = AfternoteDesign.typography.captionLargeR, - color = AfternoteDesign.colors.gray5, - ) - - Spacer(modifier = Modifier.height(16.dp)) - - Row(verticalAlignment = Alignment.CenterVertically) { - Column { - Text( - text = "42", - style = - AfternoteDesign.typography.h2.copy( - lineHeight = 32.sp, - ), - ) - - Text( - text = stringResource(R.string.mindrecord_weekly_report_total_record), - style = - AfternoteDesign.typography.captionLargeR.copy( - fontSize = 11.sp, - lineHeight = 16.sp, - ), - color = AfternoteDesign.colors.black.copy(alpha = 0.35f), - ) - } - Spacer(modifier = Modifier.width(24.dp)) - VerticalDivider(modifier = Modifier.height(30.dp)) - Spacer(modifier = Modifier.width(24.dp)) - Column { - Text( - text = "7", - style = - AfternoteDesign.typography.h2.copy( - lineHeight = 32.sp, - ), - ) - - Text( - text = stringResource(R.string.mindrecord_weekly_report_this_week), - style = - AfternoteDesign.typography.captionLargeR.copy( - fontSize = 11.sp, - lineHeight = 16.sp, - ), - color = AfternoteDesign.colors.black.copy(alpha = 0.35f), - ) - } - } - } - } -} - -@Preview(showBackground = true) -@Composable -private fun WeeklyReportCardPreview() { - AfternoteTheme { WeeklyReportCard() } -} diff --git a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/WeeklyReportReviewCard.kt b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/WeeklyReportReviewCard.kt index c81e215ff5..e72511979f 100644 --- a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/WeeklyReportReviewCard.kt +++ b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/WeeklyReportReviewCard.kt @@ -46,7 +46,7 @@ fun WeeklyReportReviewCard( modifier: Modifier = Modifier, selectedMonday: LocalDate? = null, weekOptions: List = emptyList(), - onWeekSelect: (LocalDate) -> Unit = {}, + onWeekSelect: (LocalDate) -> Unit, dateRange: String = "2025.11.10. - 2025.11.16.", counts: List> = listOf( @@ -220,7 +220,9 @@ private fun weekLabel(monday: LocalDate): String = @Composable private fun WeeklyReportScreenPreview() { AfternoteTheme { - WeeklyReportReviewCard() + WeeklyReportReviewCard( + onWeekSelect = {}, + ) } } diff --git a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/WriteTextField.kt b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/WriteTextField.kt index b6ff315ffd..ce52a13c54 100644 --- a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/WriteTextField.kt +++ b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/WriteTextField.kt @@ -76,8 +76,8 @@ fun WriteTextField( modifier: Modifier = Modifier, value: String? = null, onValueChange: ((String) -> Unit)? = null, - onSaveDraftClick: () -> Unit = {}, - onDraftCountClick: () -> Unit = {}, + onSaveDraftClick: () -> Unit, + onDraftCountClick: () -> Unit, draftCount: Int? = null, /** * 갤러리에서 고른 이미지를 서버에 업로드하고 URL 을 반환하는 업로더 @@ -285,6 +285,11 @@ fun WriteTextField( onTextStyleChange = { type -> keepEditorFocus { state.addSpanStyle(type.toSpanStyle()) } }, + // **하단 툴바와 같은 배선이다.** 스타일 툴바가 열리면 하단 툴바를 덮으므로 + // 같은 두 affordance(링크·«T»)를 그대로 갖는다. 종전에는 두 인자를 넘기지 + // 않아 no-op 디폴트가 먹었고, **눌러도 아무 일이 없는 버튼 두 개**였다 (#1540). + onLinkClick = { sheet = KeyboardSheet.MediaSelect }, + onTypeClick = { showTextStyleToolbar = !showTextStyleToolbar }, ) } @@ -403,7 +408,10 @@ private fun currentTextStyleType(currentFontSize: Float): TextStyleType = @Composable private fun WriteTextFieldPreview() { AfternoteTheme { - WriteTextField() + WriteTextField( + onDraftCountClick = {}, + onSaveDraftClick = {}, + ) } } diff --git a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/receiver/ReceiverMindRecordScreen.kt b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/receiver/ReceiverMindRecordScreen.kt index 2edb001f08..1eec190c09 100644 --- a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/receiver/ReceiverMindRecordScreen.kt +++ b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/receiver/ReceiverMindRecordScreen.kt @@ -13,7 +13,6 @@ import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.items import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState -import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.PrimaryTabRow import androidx.compose.material3.Scaffold import androidx.compose.material3.Tab @@ -39,6 +38,7 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.compose.LifecycleEventEffect import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.afternote.core.ui.asString +import com.afternote.core.ui.loading.LoadingBody import com.afternote.core.ui.theme.AfternoteDesign import com.afternote.core.ui.theme.AfternoteTheme import com.afternote.core.ui.topbar.DetailTopBar @@ -63,7 +63,7 @@ import androidx.compose.foundation.lazy.grid.items as gridItems fun ReceiverMindRecordScreen( modifier: Modifier = Modifier, viewModel: ReceiverMindRecordViewModel = hiltViewModel(), - onBackClick: () -> Unit = {}, + onBackClick: () -> Unit, ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() var filterSheetVisible by remember { mutableStateOf(false) } @@ -94,7 +94,7 @@ fun ReceiverMindRecordScreen( Box(modifier = Modifier.padding(paddingValues)) { when (val state = uiState) { ReceiverMindRecordUiState.Loading -> { - LoadingBox() + LoadingBody() } is ReceiverMindRecordUiState.Error -> { @@ -236,13 +236,6 @@ private fun DiaryGrid( } } -@Composable -private fun LoadingBox() { - Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { - CircularProgressIndicator() - } -} - @Composable private fun ErrorBox( message: String, diff --git a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/DailyQuestionAnswerListScreen.kt b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/DailyQuestionAnswerListScreen.kt index 12030c62da..4f1f9a1310 100644 --- a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/DailyQuestionAnswerListScreen.kt +++ b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/DailyQuestionAnswerListScreen.kt @@ -9,7 +9,6 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items -import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -25,6 +24,7 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.compose.LifecycleEventEffect import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.afternote.core.ui.asString +import com.afternote.core.ui.loading.LoadingBody import com.afternote.core.ui.theme.AfternoteDesign import com.afternote.core.ui.theme.AfternoteTheme import com.afternote.feature.mindrecord.presentation.component.DailyCalendar @@ -50,7 +50,7 @@ fun DailyQuestionAnswerListScreen( onItemClick: (Long, YearMonth) -> Unit, modifier: Modifier = Modifier, isListView: Boolean = true, - onEditClick: (Long) -> Unit = {}, + onEditClick: (Long) -> Unit, viewModel: DailyQuestionListViewModel = hiltViewModel(), ) { // 갱신을 이 화면이 직접 건다. HomeScreen 이 VM 을 호이스팅해 대신 걸어 주면, 탭에 @@ -74,7 +74,7 @@ fun DailyQuestionAnswerListScreen( when (val state = uiState) { DailyQuestionListUiState.Loading -> { - LoadingBox(modifier) + LoadingBody(modifier) } is DailyQuestionListUiState.Error -> { @@ -121,10 +121,10 @@ private fun DailyQuestionListContent( modifier: Modifier = Modifier, todayQuestion: TodayQuestionUi? = null, /** 항목 탭 — 저장된 기록 본문을 여는 상세 화면 (#759). */ - onItemClick: (Long, YearMonth) -> Unit = { _, _ -> }, + onItemClick: (Long, YearMonth) -> Unit, /** «수정하기» — 정식 답변을 프리필한 작성 화면으로 (#582). */ - onEdit: (Long) -> Unit = {}, - onDelete: (Long) -> Unit = {}, + onEdit: (Long) -> Unit, + onDelete: (Long) -> Unit, ) { var yearMonth by remember { mutableStateOf(YearMonth.now()) } val onYearMonthChanged: (YearMonth) -> Unit = { yearMonth = it } @@ -211,13 +211,6 @@ private fun DailyQuestionListContent( } } -@Composable -private fun LoadingBox(modifier: Modifier = Modifier) { - Box(modifier = modifier.fillMaxSize(), contentAlignment = Alignment.Center) { - CircularProgressIndicator() - } -} - @Preview(showBackground = true) @Composable private fun DailyQuestionAnswerListScreenPreviewFalse() { @@ -226,6 +219,9 @@ private fun DailyQuestionAnswerListScreenPreviewFalse() { modifier = Modifier, isListView = false, answers = emptyList(), + onDelete = {}, + onEdit = {}, + onItemClick = { _, _ -> }, ) } } @@ -238,6 +234,9 @@ private fun DailyQuestionAnswerListScreenPreviewTrue() { modifier = Modifier, isListView = true, answers = emptyList(), + onDelete = {}, + onEdit = {}, + onItemClick = { _, _ -> }, ) } } diff --git a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/DailyQuestionWriteScreen.kt b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/DailyQuestionWriteScreen.kt index 67222ebb63..009162d7bc 100644 --- a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/DailyQuestionWriteScreen.kt +++ b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/DailyQuestionWriteScreen.kt @@ -43,9 +43,9 @@ private val TopBarDateFormatter = DateTimeFormatter.ofPattern("yyyy.MM.dd") @Composable fun DailyQuestionWriteScreen( modifier: Modifier = Modifier, - onSubmitSuccess: () -> Unit = {}, - onBackClick: () -> Unit = {}, - onDraftListClick: () -> Unit = {}, + onSubmitSuccess: () -> Unit, + onBackClick: () -> Unit, + onDraftListClick: () -> Unit, viewModel: DailyQuestionWriteViewModel = hiltViewModel(), ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() @@ -85,13 +85,13 @@ internal fun DailyQuestionWriteScreenContent( uiState: DailyQuestionWriteUiState, date: LocalDate, modifier: Modifier = Modifier, - onBackClick: () -> Unit = {}, - onSubmit: () -> Unit = {}, - onSaveDraft: () -> Unit = {}, - onDraftListClick: () -> Unit = {}, - onAnswerChanged: (String) -> Unit = {}, + onBackClick: () -> Unit, + onSubmit: () -> Unit, + onSaveDraft: () -> Unit, + onDraftListClick: () -> Unit, + onAnswerChanged: (String) -> Unit, onMediaPicked: suspend (String) -> String? = { null }, - onRetryResumeDraft: () -> Unit = {}, + onRetryResumeDraft: () -> Unit, ) { // 배너 접힘은 이 화면 안에서만 의미가 있는 표시 상태다 — Content 가 소유한다. var questionExpanded by remember { mutableStateOf(true) } diff --git a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/DiaryScreen.kt b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/DiaryScreen.kt index 5bd494e3d9..94bcdbd384 100644 --- a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/DiaryScreen.kt +++ b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/DiaryScreen.kt @@ -14,7 +14,6 @@ import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.staggeredgrid.LazyVerticalStaggeredGrid import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridCells import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridItemSpan -import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -33,6 +32,7 @@ import androidx.lifecycle.compose.LifecycleEventEffect import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.afternote.core.ui.AfternoteSectionHeader import com.afternote.core.ui.asString +import com.afternote.core.ui.loading.LoadingBody import com.afternote.core.ui.theme.AfternoteDesign import com.afternote.core.ui.theme.AfternoteTheme import com.afternote.feature.mindrecord.presentation.R @@ -67,7 +67,7 @@ fun DiaryScreen( * «수정하기» — 기록 ID 와 **보고 있는 달**. 달을 빼면 프리필이 이번 달 목록에서 그 * 기록을 찾다 실패하고, 빈 화면에서 저장하면 원본을 덮어쓸 수 있다 (#582 리뷰). */ - onEditClick: (Long, YearMonth) -> Unit = { _, _ -> }, + onEditClick: (Long, YearMonth) -> Unit, viewModel: DiaryListViewModel = hiltViewModel(), ) { // 갱신을 이 화면이 직접 건다. HomeScreen 이 VM 을 호이스팅해 대신 걸어 주면, 탭에 @@ -80,7 +80,7 @@ fun DiaryScreen( when (val state = uiState) { DiaryListUiState.Loading -> { - LoadingBox(modifier) + LoadingBody(modifier) } is DiaryListUiState.Error -> { @@ -134,11 +134,11 @@ internal fun DiaryListContent( monthDiaryCount: Int = 0, weeklyMoodEmoji: String? = null, /** 항목 탭 — 저장된 기록 본문을 여는 상세 화면 (#759). */ - onItemClick: (Long, YearMonth) -> Unit = { _, _ -> }, + onItemClick: (Long, YearMonth) -> Unit, /** «수정하기» — 기록 ID 와 이 화면이 보고 있는 달. 달은 여기서만 알 수 있다 (#582). */ - onEdit: (Long, YearMonth) -> Unit = { _, _ -> }, - onDelete: (Long) -> Unit = {}, - onYearMonthChanged: (YearMonth) -> Unit = {}, + onEdit: (Long, YearMonth) -> Unit, + onDelete: (Long) -> Unit, + onYearMonthChanged: (YearMonth) -> Unit, ) { // 기록이 없다고 조기 반환하지 않는다. 종전에는 빈 상태가 캘린더를 통째로 대체해 // 월 이동 버튼까지 사라졌고, 기록이 있는 달로 돌아갈 방법이 없었다 (#724). @@ -228,13 +228,6 @@ internal fun DiaryListContent( } } -@Composable -private fun LoadingBox(modifier: Modifier = Modifier) { - Box(modifier = modifier.fillMaxSize(), contentAlignment = Alignment.Center) { - CircularProgressIndicator() - } -} - @Preview(showBackground = true) @Composable private fun DiaryScreenPreviewTrue() { @@ -245,6 +238,10 @@ private fun DiaryScreenPreviewTrue() { diaries = emptyList(), // 프리뷰는 고정 월로 렌더한다 — YearMonth.now() 면 달이 바뀔 때마다 결과가 달라진다. yearMonth = PreviewYearMonth, + onDelete = {}, + onEdit = { _, _ -> }, + onItemClick = { _, _ -> }, + onYearMonthChanged = {}, ) } } @@ -258,6 +255,10 @@ private fun DiaryScreenPreviewFalse() { isListView = false, diaries = emptyList(), yearMonth = PreviewYearMonth, + onDelete = {}, + onEdit = { _, _ -> }, + onItemClick = { _, _ -> }, + onYearMonthChanged = {}, ) } } diff --git a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/DiaryWriteScreen.kt b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/DiaryWriteScreen.kt index b3259d8c71..3aee5ffee4 100644 --- a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/DiaryWriteScreen.kt +++ b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/DiaryWriteScreen.kt @@ -58,9 +58,9 @@ private val WriteDateFormatter = DateTimeFormatter.ofPattern("yyyy년 M월 d일" @Composable fun DiaryWriteScreen( modifier: Modifier = Modifier, - onSubmitSuccess: () -> Unit = {}, - onBackClick: () -> Unit = {}, - onDraftListClick: () -> Unit = {}, + onSubmitSuccess: () -> Unit, + onBackClick: () -> Unit, + onDraftListClick: () -> Unit, viewModel: DiaryWriteViewModel = hiltViewModel(), ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() @@ -117,14 +117,14 @@ fun DiaryWriteScreen( internal fun DiaryWriteScreenContent( uiState: DiaryWriteUiState, modifier: Modifier = Modifier, - onBackClick: () -> Unit = {}, - onSubmit: () -> Unit = {}, - onSaveDraft: () -> Unit = {}, - onDraftListClick: () -> Unit = {}, - onTitleChanged: (String) -> Unit = {}, - onContentChanged: (String) -> Unit = {}, - onMoodSelected: (TodayMood) -> Unit = {}, - onReceiverRowClick: () -> Unit = {}, + onBackClick: () -> Unit, + onSubmit: () -> Unit, + onSaveDraft: () -> Unit, + onDraftListClick: () -> Unit, + onTitleChanged: (String) -> Unit, + onContentChanged: (String) -> Unit, + onMoodSelected: (TodayMood) -> Unit, + onReceiverRowClick: () -> Unit, onMediaPicked: suspend (String) -> String? = { null }, ) { Scaffold( diff --git a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/DraftListScreen.kt b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/DraftListScreen.kt index edbfc7491f..85529a4b45 100644 --- a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/DraftListScreen.kt +++ b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/DraftListScreen.kt @@ -16,7 +16,6 @@ import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Scaffold import androidx.compose.material3.Text @@ -44,6 +43,7 @@ import com.afternote.core.ui.button.AfternoteButton import com.afternote.core.ui.button.AfternoteButtonType import com.afternote.core.ui.button.AfternoteCircularCheckbox import com.afternote.core.ui.button.CheckboxState +import com.afternote.core.ui.loading.LoadingBody import com.afternote.core.ui.theme.AfternoteDesign import com.afternote.core.ui.theme.AfternoteTheme import com.afternote.core.ui.topbar.DetailTopBar @@ -69,11 +69,11 @@ private const val DELETED_TOAST_DURATION_MS = 2_000L @Composable fun DraftListScreen( modifier: Modifier = Modifier, - onBackClick: () -> Unit = {}, + onBackClick: () -> Unit, /** 일기 draft 탭 → 이어쓰기. (draftId, 해당 달 `yyyy-MM`) 전달. */ - onDiaryDraftClick: (Long, String) -> Unit = { _, _ -> }, + onDiaryDraftClick: (Long, String) -> Unit, /** 데일리질문 draft 탭 → 이어쓰기. 당일이 지난 draft 는 이 경로로만 열 수 있다 (#770). */ - onDailyQuestionDraftClick: (Long) -> Unit = {}, + onDailyQuestionDraftClick: (Long) -> Unit, viewModel: DraftListViewModel = hiltViewModel(), ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() @@ -162,9 +162,7 @@ fun DraftListScreen( Box(modifier = Modifier.padding(paddingValues)) { when (val state = uiState) { DraftListUiState.Loading -> { - Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { - CircularProgressIndicator() - } + LoadingBody() } is DraftListUiState.Error -> { @@ -314,7 +312,7 @@ private fun DraftRow( selectionMode: Boolean, selected: Boolean, onToggleSelect: () -> Unit, - onClick: () -> Unit = {}, + onClick: () -> Unit, ) { Row( modifier = @@ -446,6 +444,7 @@ private fun DraftRowPreview() { selectionMode = true, selected = true, onToggleSelect = {}, + onClick = {}, ) AfternoteButton( text = "전체 삭제", diff --git a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/HomeScreen.kt b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/HomeScreen.kt index ca163dcd4d..db5f674a53 100644 --- a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/HomeScreen.kt +++ b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/HomeScreen.kt @@ -47,12 +47,12 @@ import com.afternote.feature.mindrecord.presentation.R as MindRecordR @Composable fun HomeScreen( modifier: Modifier = Modifier, - onWriteClick: (MindRecordCategoryUi) -> Unit = {}, + onWriteClick: (MindRecordCategoryUi) -> Unit, // 목록 항목 탭 → 상세(열람) 화면. (기록 ID, 일기 여부, 목록이 보고 있던 달) (#759). - onRecordClick: (Long, Boolean, YearMonth) -> Unit = { _, _, _ -> }, + onRecordClick: (Long, Boolean, YearMonth) -> Unit, // 목록의 «수정하기» → 프리필한 작성 화면 (#582). - onEditDailyQuestion: (Long) -> Unit = {}, - onEditDiary: (Long, YearMonth) -> Unit = { _, _ -> }, + onEditDailyQuestion: (Long) -> Unit, + onEditDiary: (Long, YearMonth) -> Unit, ) { // Figma 2757:16116 — 마음의 기록 탭은 데일리 질문 / 일기 / 주간리포트 3개 val categories = @@ -205,6 +205,11 @@ fun HomeScreen( @Composable private fun HomeScreenPreview() { AfternoteTheme { - HomeScreen() + HomeScreen( + onEditDailyQuestion = {}, + onEditDiary = { _, _ -> }, + onRecordClick = { _, _, _ -> }, + onWriteClick = {}, + ) } } diff --git a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/WeeklyReportScreen.kt b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/WeeklyReportScreen.kt index 37f0c5bb29..e4bc0bfeb7 100644 --- a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/WeeklyReportScreen.kt +++ b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/WeeklyReportScreen.kt @@ -9,7 +9,6 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Text import androidx.compose.material3.TextButton @@ -28,6 +27,7 @@ import androidx.lifecycle.compose.LifecycleEventEffect import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.afternote.core.ui.AfternoteSectionHeader import com.afternote.core.ui.asString +import com.afternote.core.ui.loading.LoadingBody import com.afternote.core.ui.theme.AfternoteDesign import com.afternote.core.ui.theme.AfternoteTheme import com.afternote.feature.mindrecord.domain.model.EmotionAnalysisStatus @@ -58,7 +58,7 @@ fun WeeklyReportScreen( when (val state = uiState) { WeeklyReportUiState.Loading -> { - LoadingBox(modifier) + LoadingBody(modifier) } is WeeklyReportUiState.Error -> { @@ -150,7 +150,17 @@ private fun WeeklyReportContent( Column(verticalArrangement = Arrangement.spacedBy(12.dp)) { AfternoteSectionHeader(title = "HISTORY") state.dailyQuestions.forEach { dailyQuestion -> - DailyQuestionListCard(answer = dailyQuestion) + // 주간 리포트는 읽기 전용 요약이다 — 편집·삭제는 데일리질문 목록의 몫이라 + // 여기서는 «더보기» 를 그리지 않는다 (#1540). + // 주간 리포트는 **읽기 전용 요약**이다 — 편집·삭제도, 카드 탭도 없다. + // 셋 다 `null` 이라 클릭 semantics 자체가 안 붙는다: no-op 을 넘기면 + // 스크린리더가 「버튼」으로 읽는데 눌러도 아무 일이 없다 (#1540 리뷰). + DailyQuestionListCard( + answer = dailyQuestion, + onClick = null, + onEdit = null, + onDelete = null, + ) } } } @@ -207,13 +217,6 @@ internal fun recordedSummaryHighlights( return ranges } -@Composable -private fun LoadingBox(modifier: Modifier = Modifier) { - Box(modifier = modifier.fillMaxSize(), contentAlignment = Alignment.Center) { - CircularProgressIndicator() - } -} - @Composable private fun ErrorBox( message: String, diff --git a/feature/mindrecord/presentation/src/main/res/values/strings.xml b/feature/mindrecord/presentation/src/main/res/values/strings.xml index 797121c564..76a13c5fde 100644 --- a/feature/mindrecord/presentation/src/main/res/values/strings.xml +++ b/feature/mindrecord/presentation/src/main/res/values/strings.xml @@ -85,14 +85,10 @@ 답변하러가기 - 주간 리포트 - 이번 주 나의 기록들을 확인해 보세요. 총 기록 이번 주 이번 달 주간 평균 기분 - 주간 평균 감정 - 😊 좋음 %1$d월 %2$d주차 리포트 11월 2주차 리포트 - 이번주는 가족과 함께하는 시간을 가장 많이 기록하셨네요. 일상의 소중함을 느끼는 한주였던 것 같아요. - 매일 꾸준히 기록하는 습관이 정말 멋져요! 나의 감정 키워드 diff --git a/feature/mindrecord/presentation/src/screenshotTest/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/DailyQuestionWriteScreenScreenshotTest.kt b/feature/mindrecord/presentation/src/screenshotTest/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/DailyQuestionWriteScreenScreenshotTest.kt index 3146f5b411..64d8591f49 100644 --- a/feature/mindrecord/presentation/src/screenshotTest/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/DailyQuestionWriteScreenScreenshotTest.kt +++ b/feature/mindrecord/presentation/src/screenshotTest/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/DailyQuestionWriteScreenScreenshotTest.kt @@ -25,6 +25,12 @@ internal fun dailyQuestionWriteScreenScreenshot() { uiState = dailyQuestionWriteScreenshotState(), date = SCREENSHOT_DATE, modifier = Modifier.fillMaxSize(), + onAnswerChanged = {}, + onBackClick = {}, + onDraftListClick = {}, + onRetryResumeDraft = {}, + onSaveDraft = {}, + onSubmit = {}, ) } } @@ -38,6 +44,12 @@ internal fun dailyQuestionWriteScreenCompactScreenshot() { uiState = dailyQuestionWriteScreenshotState(), date = SCREENSHOT_DATE, modifier = Modifier.fillMaxSize(), + onAnswerChanged = {}, + onBackClick = {}, + onDraftListClick = {}, + onRetryResumeDraft = {}, + onSaveDraft = {}, + onSubmit = {}, ) } } diff --git a/feature/mindrecord/presentation/src/screenshotTest/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/DiaryWriteScreenScreenshotTest.kt b/feature/mindrecord/presentation/src/screenshotTest/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/DiaryWriteScreenScreenshotTest.kt index b43307f8f5..ed96c843fb 100644 --- a/feature/mindrecord/presentation/src/screenshotTest/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/DiaryWriteScreenScreenshotTest.kt +++ b/feature/mindrecord/presentation/src/screenshotTest/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/DiaryWriteScreenScreenshotTest.kt @@ -25,6 +25,14 @@ internal fun diaryWriteScreenScreenshot() { DiaryWriteScreenContent( uiState = diaryWriteScreenshotState(), modifier = Modifier.fillMaxSize(), + onBackClick = {}, + onContentChanged = {}, + onDraftListClick = {}, + onMoodSelected = {}, + onReceiverRowClick = {}, + onSaveDraft = {}, + onSubmit = {}, + onTitleChanged = {}, ) } } @@ -37,6 +45,14 @@ internal fun diaryWriteScreenCompactScreenshot() { DiaryWriteScreenContent( uiState = diaryWriteScreenshotState(), modifier = Modifier.fillMaxSize(), + onBackClick = {}, + onContentChanged = {}, + onDraftListClick = {}, + onMoodSelected = {}, + onReceiverRowClick = {}, + onSaveDraft = {}, + onSubmit = {}, + onTitleChanged = {}, ) } } diff --git a/feature/mindrecord/presentation/src/test/kotlin/com/afternote/feature/mindrecord/presentation/MindRecordFlowTest.kt b/feature/mindrecord/presentation/src/test/kotlin/com/afternote/feature/mindrecord/presentation/MindRecordFlowTest.kt index 58315040b8..663804263a 100644 --- a/feature/mindrecord/presentation/src/test/kotlin/com/afternote/feature/mindrecord/presentation/MindRecordFlowTest.kt +++ b/feature/mindrecord/presentation/src/test/kotlin/com/afternote/feature/mindrecord/presentation/MindRecordFlowTest.kt @@ -58,6 +58,8 @@ class MindRecordFlowTest { DiaryWriteScreen( viewModel = viewModel, onSubmitSuccess = { successCalls += 1 }, + onBackClick = {}, + onDraftListClick = {}, ) } } @@ -98,7 +100,12 @@ class MindRecordFlowTest { val viewModel = diaryViewModel(FakeDiaryRepository()) composeRule.setContent { AfternoteTheme { - DiaryWriteScreen(viewModel = viewModel) + DiaryWriteScreen( + viewModel = viewModel, + onBackClick = {}, + onDraftListClick = {}, + onSubmitSuccess = {}, + ) } } @@ -140,7 +147,12 @@ class MindRecordFlowTest { // ViewModel 사이 결선이 검증되지 않아, 계측 호출을 지워도 통과한다 (#964 리뷰). composeRule.setContent { AfternoteTheme { - DailyQuestionWriteScreen(viewModel = viewModel, onSubmitSuccess = { }) + DailyQuestionWriteScreen( + viewModel = viewModel, + onSubmitSuccess = { }, + onBackClick = {}, + onDraftListClick = {}, + ) } } composeRule.waitUntil(timeoutMillis = 5_000) { !viewModel.uiState.value.isQuestionLoading } diff --git a/feature/mindrecord/presentation/src/test/kotlin/com/afternote/feature/mindrecord/presentation/MindRecordLifecycleTest.kt b/feature/mindrecord/presentation/src/test/kotlin/com/afternote/feature/mindrecord/presentation/MindRecordLifecycleTest.kt index 3bd5ae81ec..2342829708 100644 --- a/feature/mindrecord/presentation/src/test/kotlin/com/afternote/feature/mindrecord/presentation/MindRecordLifecycleTest.kt +++ b/feature/mindrecord/presentation/src/test/kotlin/com/afternote/feature/mindrecord/presentation/MindRecordLifecycleTest.kt @@ -88,7 +88,11 @@ class MindRecordLifecycleTest { composeRule.setContent { AfternoteTheme { - DiaryScreen(viewModel = viewModel, onItemClick = { _, _ -> }) + DiaryScreen( + viewModel = viewModel, + onItemClick = { _, _ -> }, + onEditClick = { _, _ -> }, + ) } } @@ -162,7 +166,12 @@ class MindRecordLifecycleTest { composeRule.setContent { AfternoteTheme { - DraftListScreen(viewModel = viewModel) + DraftListScreen( + viewModel = viewModel, + onBackClick = {}, + onDailyQuestionDraftClick = {}, + onDiaryDraftClick = { _, _ -> }, + ) } } @@ -301,7 +310,10 @@ class MindRecordLifecycleTest { composeRule.setContent { AfternoteTheme { - ReceiverMindRecordScreen(viewModel = viewModel) + ReceiverMindRecordScreen( + viewModel = viewModel, + onBackClick = {}, + ) } } composeRule.onNodeWithText("질문 범위 최신").assertIsDisplayed() diff --git a/feature/mindrecord/presentation/src/test/kotlin/com/afternote/feature/mindrecord/presentation/component/MediaSheetMigrationTest.kt b/feature/mindrecord/presentation/src/test/kotlin/com/afternote/feature/mindrecord/presentation/component/MediaSheetMigrationTest.kt index 08c491ff74..ea2cabe567 100644 --- a/feature/mindrecord/presentation/src/test/kotlin/com/afternote/feature/mindrecord/presentation/component/MediaSheetMigrationTest.kt +++ b/feature/mindrecord/presentation/src/test/kotlin/com/afternote/feature/mindrecord/presentation/component/MediaSheetMigrationTest.kt @@ -37,7 +37,7 @@ class MediaSheetMigrationTest { @Test fun `툴바 미디어 버튼이 core 정본 시트를 연다`() { - composeRule.setContent { AfternoteTheme { WriteTextField() } } + composeRule.setContent { AfternoteTheme { WriteTextField(onSaveDraftClick = {}, onDraftCountClick = {}) } } val context = composeRule.activity openMediaSheet() @@ -62,7 +62,7 @@ class MediaSheetMigrationTest { */ @Test fun `링크 항목은 링크 입력 시트로 이어진다`() { - composeRule.setContent { AfternoteTheme { WriteTextField() } } + composeRule.setContent { AfternoteTheme { WriteTextField(onSaveDraftClick = {}, onDraftCountClick = {}) } } val context = composeRule.activity openMediaSheet() diff --git a/feature/mindrecord/presentation/src/test/kotlin/com/afternote/feature/mindrecord/presentation/component/RecordActionAffordanceTest.kt b/feature/mindrecord/presentation/src/test/kotlin/com/afternote/feature/mindrecord/presentation/component/RecordActionAffordanceTest.kt new file mode 100644 index 0000000000..b9324c05e6 --- /dev/null +++ b/feature/mindrecord/presentation/src/test/kotlin/com/afternote/feature/mindrecord/presentation/component/RecordActionAffordanceTest.kt @@ -0,0 +1,110 @@ +package com.afternote.feature.mindrecord.presentation.component + +import androidx.activity.ComponentActivity +import androidx.compose.ui.test.assertCountEquals +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.hasClickAction +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onNodeWithContentDescription +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import com.afternote.core.ui.theme.AfternoteTheme +import com.afternote.feature.mindrecord.presentation.R +import com.afternote.feature.mindrecord.presentation.model.DailyQuestion +import org.junit.Assert.assertEquals +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import java.time.LocalDate + +/** + * «더보기» 는 실제로 동작할 때만 그린다 (#1540). + * + * 종전에는 `onEdit`·`onDelete` 가 `= {}` 디폴트라, 핸들러를 넘기지 않은 화면에서도 메뉴가 + * 뜨고 «수정»·«삭제» 를 눌러도 아무 일이 없었다. 실제로 주간 리포트 HISTORY 가 그 상태였다 + * (`WeeklyReportScreen` 이 `DailyQuestionListCard(answer = …)` 만 넘기고 있었다). + * + * 디폴트를 걷어내 컴파일이 배선을 강제하게 했고, 상호작용이 없는 자리는 `null` 로 **버튼 + * 자체를 숨긴다.** 「눌러도 아무 일 없는 버튼」을 그리지 않는 것이 이 가드의 계약이다 + * (#582 · #618 · #722 · #777 전례). + */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [35]) +class RecordActionAffordanceTest { + @get:Rule + val composeRule = createAndroidComposeRule() + + private val answer = + DailyQuestion( + title = "오늘 하루, 누구에게 가장 고마웠나요?", + content = "아무 말 없이 곁을 지켜주는 사람.", + date = LocalDate.of(2026, 8, 30), + ) + + @Test + fun `핸들러가 없으면 더보기를 그리지 않는다`() { + composeRule.setContent { + AfternoteTheme { + DailyQuestionListCard( + answer = answer, + onEdit = null, + onDelete = null, + onClick = {}, + ) + } + } + + composeRule + .onNodeWithContentDescription(moreMenuLabel()) + .assertDoesNotExist() + } + + @Test + fun `핸들러가 있으면 더보기를 그린다`() { + composeRule.setContent { + AfternoteTheme { + DailyQuestionListCard( + answer = answer, + onEdit = {}, + onDelete = {}, + onClick = {}, + ) + } + } + + composeRule + .onNodeWithContentDescription(moreMenuLabel()) + .assertIsDisplayed() + } + + @Test + fun `onClick 이 없으면 카드에 클릭 semantics 를 붙이지 않는다`() { + // no-op 을 넘기면 `Role.Button` 이 그대로 실려 스크린리더가 「버튼」으로 읽는데 눌러도 + // 아무 일이 없다 — 주간 리포트 HISTORY 가 그 상태였다 (#1540 리뷰). + composeRule.setContent { + AfternoteTheme { + DailyQuestionListCard(answer = answer, onClick = null, onEdit = null, onDelete = null) + } + } + + composeRule.onAllNodes(hasClickAction()).assertCountEquals(0) + } + + @Test + fun `onClick 이 있으면 카드가 눌린다`() { + var clicks = 0 + composeRule.setContent { + AfternoteTheme { + DailyQuestionListCard(answer = answer, onClick = { clicks += 1 }, onEdit = null, onDelete = null) + } + } + + composeRule.onAllNodes(hasClickAction()).assertCountEquals(1) + composeRule.onNodeWithText(answer.title).performClick() + assertEquals("카드 탭이 전달되지 않았다", 1, clicks) + } + + private fun moreMenuLabel(): String = composeRule.activity.getString(R.string.mindrecord_more_menu_cd) +} diff --git a/feature/mindrecord/presentation/src/test/kotlin/com/afternote/feature/mindrecord/presentation/component/WeeklyCardFontScaleTest.kt b/feature/mindrecord/presentation/src/test/kotlin/com/afternote/feature/mindrecord/presentation/component/WeeklyCardFontScaleTest.kt index 7b0bb648aa..b69193b8c2 100644 --- a/feature/mindrecord/presentation/src/test/kotlin/com/afternote/feature/mindrecord/presentation/component/WeeklyCardFontScaleTest.kt +++ b/feature/mindrecord/presentation/src/test/kotlin/com/afternote/feature/mindrecord/presentation/component/WeeklyCardFontScaleTest.kt @@ -81,7 +81,7 @@ class WeeklyCardFontScaleTest { CompositionLocalProvider( LocalDensity provides Density(density = base.density, fontScale = fontScale), ) { - AfternoteTheme { WeeklyReportReviewCard() } + AfternoteTheme { WeeklyReportReviewCard(onWeekSelect = {}) } } } } diff --git a/feature/mindrecord/presentation/src/test/kotlin/com/afternote/feature/mindrecord/presentation/component/WriteTextFieldReseedTest.kt b/feature/mindrecord/presentation/src/test/kotlin/com/afternote/feature/mindrecord/presentation/component/WriteTextFieldReseedTest.kt index 6f4d51566c..2d9d8b0de6 100644 --- a/feature/mindrecord/presentation/src/test/kotlin/com/afternote/feature/mindrecord/presentation/component/WriteTextFieldReseedTest.kt +++ b/feature/mindrecord/presentation/src/test/kotlin/com/afternote/feature/mindrecord/presentation/component/WriteTextFieldReseedTest.kt @@ -32,7 +32,13 @@ class WriteTextFieldReseedTest { fun `나중에 도착한 본문이 에디터에 실린다`() { var content by mutableStateOf(null) composeRule.setContent { - AfternoteTheme { WriteTextField(value = content) } + AfternoteTheme { + WriteTextField( + value = content, + onDraftCountClick = {}, + onSaveDraftClick = {}, + ) + } } composeRule.runOnIdle { content = "

서버에서 도착한 임시저장 본문

" } @@ -48,7 +54,12 @@ class WriteTextFieldReseedTest { var changes = 0 composeRule.setContent { AfternoteTheme { - WriteTextField(value = content, onValueChange = { changes += 1 }) + WriteTextField( + value = content, + onValueChange = { changes += 1 }, + onDraftCountClick = {}, + onSaveDraftClick = {}, + ) } } composeRule.waitForIdle() diff --git a/feature/mindrecord/presentation/src/test/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/RecordListMonthTest.kt b/feature/mindrecord/presentation/src/test/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/RecordListMonthTest.kt index 5693eb8937..bccfb7b983 100644 --- a/feature/mindrecord/presentation/src/test/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/RecordListMonthTest.kt +++ b/feature/mindrecord/presentation/src/test/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/RecordListMonthTest.kt @@ -51,10 +51,14 @@ class RecordListMonthTest { ), ), onItemClick = { id, month -> clicked = id to month }, + onDelete = {}, + onEdit = { _, _ -> }, ) } } + // 목록은 캘린더가 먼저 오는 LazyColumn 이라 기록 카드가 화면 밖에서 시작할 수 있다. + // 스크롤 위치에 기대면 캘린더 높이가 조금만 달라져도 「노드가 없다」로 깨진다 (#1700). composeRule .onNode(hasScrollToNodeAction()) .performScrollToNode(hasText("지난달 기록")) diff --git a/konsist/src/test/kotlin/com/afternote/konsist/NoOpCallbackDefaultKonsistTest.kt b/konsist/src/test/kotlin/com/afternote/konsist/NoOpCallbackDefaultKonsistTest.kt index f0ba672233..14b0e40811 100644 --- a/konsist/src/test/kotlin/com/afternote/konsist/NoOpCallbackDefaultKonsistTest.kt +++ b/konsist/src/test/kotlin/com/afternote/konsist/NoOpCallbackDefaultKonsistTest.kt @@ -28,7 +28,7 @@ import org.junit.Test * * ### [LEGACY_NO_OP_DEFAULT_FILES] * 가드 도입 시점(#1388)에 남아 있던 잔여 파일. 모듈 담당별 후속 PR 이 청소하며 목록에서 뺀다. - * afternote(#1388 본체) · receiver 는 청소 완료로 빠졌고, 남은 것은 mindrecord·home(#1540) · timeletter(#1541) 몫이다. + * afternote(#1388 본체) · receiver · **mindrecord·home(#1540)** 은 청소 완료로 빠졌고, 남은 것은 timeletter(#1541) 몫이다. * 목록에 있는 파일은 위반이 **있어도 없어도 통과**한다(관대 판정) — 파일을 청소하는 PR 과 * 목록을 갱신하는 PR 의 머지 순서가 develop 을 red 로 만들지 않게 하기 위해서다 * ([ResponseDtoContractKonsistTest] 의 #933 전례와 같은 구조). 이미 청소된 항목이 목록에 @@ -137,31 +137,11 @@ class NoOpCallbackDefaultKonsistTest { val WHITESPACE = Regex("""\s""") - /** home — #1388 모듈 몫 후속 PR 이 청소한다. */ - private val HOME = - setOf( - "feature/home/presentation/WeeklySummaryGrid.kt", - ) + /** home — #1540 에서 청소 완료. */ + private val HOME = emptySet() - /** mindrecord — #1388 모듈 몫 후속 PR 이 청소한다. */ - private val MINDRECORD = - setOf( - "feature/mindrecord/presentation/component/DailyQuestionListCard.kt", - "feature/mindrecord/presentation/component/DiaryCard.kt", - "feature/mindrecord/presentation/component/DiaryComponent.kt", - "feature/mindrecord/presentation/component/KeyBoardToolBar.kt", - "feature/mindrecord/presentation/component/MemoriesCard.kt", - "feature/mindrecord/presentation/component/TodayQuestionCard.kt", - "feature/mindrecord/presentation/component/WeeklyReportReviewCard.kt", - "feature/mindrecord/presentation/component/WriteTextField.kt", - "feature/mindrecord/presentation/screen/receiver/ReceiverMindRecordScreen.kt", - "feature/mindrecord/presentation/screen/sender/DailyQuestionAnswerListScreen.kt", - "feature/mindrecord/presentation/screen/sender/DailyQuestionWriteScreen.kt", - "feature/mindrecord/presentation/screen/sender/DiaryScreen.kt", - "feature/mindrecord/presentation/screen/sender/DiaryWriteScreen.kt", - "feature/mindrecord/presentation/screen/sender/DraftListScreen.kt", - "feature/mindrecord/presentation/screen/sender/HomeScreen.kt", - ) + /** mindrecord — #1540 에서 청소 완료. */ + private val MINDRECORD = emptySet() /** timeletter — #1388 모듈 몫 후속 PR 이 청소한다 (TimeLetterWriteScreen 은 #778 과 조정). */ private val TIMELETTER =