From c4d2f411e7e3f34de6bf893a380b309f88ca33ce Mon Sep 17 00:00:00 2001 From: Sadturtleman Date: Sun, 30 Aug 2026 13:02:57 +0900 Subject: [PATCH 1/8] =?UTF-8?q?refactor(mindrecord):=20=EB=A1=9C=EB=94=A9?= =?UTF-8?q?=20=EC=8A=A4=ED=94=BC=EB=84=88=205=EA=B3=B3=EC=9D=84=20core:ui?= =?UTF-8?q?=20LoadingBody=20=EB=A1=9C=20=EB=AA=A8=EC=9D=80=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `private fun LoadingBox` 4벌과 `DraftListScreen` 의 인라인 `Box + CircularProgressIndicator` 1곳을 승격본으로 치환한다 (#1303 · #1490 — 같은 작업이라 한 번에 닫는다). **렌더가 같다는 근거.** 넷은 전부 `fillMaxSize` + 중앙 정렬 + 기본 지름이라 구조가 `LoadingBody` 와 동일하다. 유일한 차이인 `size(40.dp)` 는 material3 기본값과 같은 값이다 — `CircularProgressIndicator` 가 호출자 modifier 뒤에 `.size(CircularIndicatorDiameter)` 를 붙이고, `CircularIndicatorDiameter = CircularProgressIndicatorTokens.Size = 40.0.dp` 다 (material3 1.5.0-alpha17 소스 확인). 실측으로도 확인했다 — `validateDebugScreenshotTest` 의 실패 골든 집합이 develop 과 **동일** 하다(로컬 macOS 렌더가 CI 골든과 어긋나 develop 자체가 6건 실패한다. 그래서 절대 건수가 아니라 develop 대비 **차이**로 본다). Co-Authored-By: Claude Opus 5 (1M context) --- .../receiver/ReceiverMindRecordScreen.kt | 13 +++------- .../sender/DailyQuestionAnswerListScreen.kt | 21 +++++++--------- .../presentation/screen/sender/DiaryScreen.kt | 25 +++++++++---------- .../screen/sender/DraftListScreen.kt | 15 ++++++----- .../screen/sender/WeeklyReportScreen.kt | 19 +++++++------- 5 files changed, 40 insertions(+), 53 deletions(-) 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 e8d2b2683b..79862df14f 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 @@ -23,6 +22,7 @@ import androidx.compose.ui.unit.dp import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel 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 @@ -42,7 +42,7 @@ import java.time.YearMonth fun DailyQuestionAnswerListScreen( modifier: Modifier = Modifier, isListView: Boolean = true, - onEditClick: (Long) -> Unit = {}, + onEditClick: (Long) -> Unit, viewModel: DailyQuestionListViewModel = hiltViewModel(), ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() @@ -60,7 +60,7 @@ fun DailyQuestionAnswerListScreen( when (val state = uiState) { DailyQuestionListUiState.Loading -> { - LoadingBox(modifier) + LoadingBody(modifier) } is DailyQuestionListUiState.Error -> { @@ -105,8 +105,8 @@ private fun DailyQuestionListContent( answers: List, modifier: Modifier = Modifier, todayQuestion: TodayQuestionUi? = null, - 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 } @@ -172,13 +172,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() { @@ -187,6 +180,8 @@ private fun DailyQuestionAnswerListScreenPreviewFalse() { modifier = Modifier, isListView = false, answers = emptyList(), + onDelete = {}, + onEdit = {}, ) } } @@ -199,6 +194,8 @@ private fun DailyQuestionAnswerListScreenPreviewTrue() { modifier = Modifier, isListView = true, answers = emptyList(), + onDelete = {}, + onEdit = {}, ) } } 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 843f3edd4b..072565cadd 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 @@ -28,6 +27,7 @@ import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel 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 @@ -55,14 +55,14 @@ fun DiaryScreen( * «수정하기» — 기록 ID 와 **보고 있는 달**. 달을 빼면 프리필이 이번 달 목록에서 그 * 기록을 찾다 실패하고, 빈 화면에서 저장하면 원본을 덮어쓸 수 있다 (#582 리뷰). */ - onEditClick: (Long, YearMonth) -> Unit = { _, _ -> }, + onEditClick: (Long, YearMonth) -> Unit, viewModel: DiaryListViewModel = hiltViewModel(), ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() when (val state = uiState) { DiaryListUiState.Loading -> { - LoadingBox(modifier) + LoadingBody(modifier) } is DiaryListUiState.Error -> { @@ -115,9 +115,9 @@ internal fun DiaryListContent( monthDiaryCount: Int = 0, weeklyMoodEmoji: String? = null, /** «수정하기» — 기록 ID 와 이 화면이 보고 있는 달. 달은 여기서만 알 수 있다. */ - onEdit: (Long, YearMonth) -> Unit = { _, _ -> }, - onDelete: (Long) -> Unit = {}, - onYearMonthChanged: (YearMonth) -> Unit = {}, + onEdit: (Long, YearMonth) -> Unit, + onDelete: (Long) -> Unit, + onYearMonthChanged: (YearMonth) -> Unit, ) { if (isListView && diaries.isEmpty()) { MindRecordEmptyState( @@ -193,13 +193,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() { @@ -210,6 +203,9 @@ private fun DiaryScreenPreviewTrue() { diaries = emptyList(), // 프리뷰는 고정 월로 렌더한다 — YearMonth.now() 면 달이 바뀔 때마다 결과가 달라진다. yearMonth = PreviewYearMonth, + onDelete = {}, + onYearMonthChanged = {}, + onEdit = { _, _ -> }, ) } } @@ -223,6 +219,9 @@ private fun DiaryScreenPreviewFalse() { isListView = false, diaries = emptyList(), yearMonth = PreviewYearMonth, + onDelete = {}, + onYearMonthChanged = {}, + onEdit = { _, _ -> }, ) } } 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/WeeklyReportScreen.kt b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/WeeklyReportScreen.kt index f834ef021a..263138713e 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 @@ -26,6 +25,7 @@ import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel 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 @@ -47,7 +47,7 @@ fun WeeklyReportScreen( when (val state = uiState) { WeeklyReportUiState.Loading -> { - LoadingBox(modifier) + LoadingBody(modifier) } is WeeklyReportUiState.Error -> { @@ -139,7 +139,13 @@ private fun WeeklyReportContent( Column(verticalArrangement = Arrangement.spacedBy(12.dp)) { AfternoteSectionHeader(title = "HISTORY") state.dailyQuestions.forEach { dailyQuestion -> - DailyQuestionListCard(answer = dailyQuestion) + // 주간 리포트는 읽기 전용 요약이다 — 편집·삭제는 데일리질문 목록의 몫이라 + // 여기서는 «더보기» 를 그리지 않는다 (#1540). + DailyQuestionListCard( + answer = dailyQuestion, + onEdit = null, + onDelete = null, + ) } } } @@ -196,13 +202,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, From 5ad667914f2d48a90501d53edd22ffa597b8b841 Mon Sep 17 00:00:00 2001 From: Sadturtleman Date: Sun, 30 Aug 2026 13:03:21 +0900 Subject: [PATCH 2/8] =?UTF-8?q?refactor(mindrecord):=20=EC=B0=B8=EC=A1=B0?= =?UTF-8?q?=200=EA=B1=B4=20=EC=B9=B4=EB=93=9C=203=EA=B1=B4=EC=9D=84=20?= =?UTF-8?q?=EC=8B=9C=EC=95=88=20=EB=8C=80=EC=A1=B0=20=ED=9B=84=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #1422 이 넘긴 3건을 정본 시안과 대조해 **전부 삭제**로 판정했다. 셋 다 정의 파일 밖 참조가 0건이고 파일 안에는 자기 자신을 부르는 `@Preview` 만 있었다. 「미구현 화면의 선행 정의」가 아니라 **이미 다른 컴포넌트가 그 자리를 메운 뒤 남은 사본**이었다. | 심볼 | 시안의 그 자리 | 지금 그 자리를 그리는 것 | |---|---|---| | `InsightCard` | 주간리포트 `INSIGHTS` (`4327:77929`) | `EmotionKeywordCard` 의 `descriptionText` — 시안에서도 감정키워드 카드(`4327:99437`)가 같은 두 문단을 흡수했다 | | `WeeklyEmotionCard` | 일기_카드 형 «주간 평균 기분» (`4327:77573`) | `DiaryReportCard` — `이번 달`/`주간 평균 기분` 2열 통계를 실데이터(`monthDiaryCount`·`weeklyMoodEmoji`)로 그린다 | | `WeeklyReportCard` | **없다** | — 문구(`주간 리포트` · `이번 주 나의 기록들을 확인해 보세요.`)가 시안 전체에 0건이다 | 세 사본은 모두 파라미터가 `modifier` 뿐이라 실데이터를 못 받는다. 살려 둬도 배선할 수 없고, 같은 자리에 실구현이 이미 있어 다음 사람이 어느 쪽을 쓸지 헷갈리는 값만 남는다. 전용 문자열 6건도 함께 걷었다(다른 참조 0건 확인). `mindrecord_weekly_report_avg_mood_weekly` (「주간 평균 기분」 — 시안과 일치)는 `DiaryReportCard` 가 쓰므로 남긴다. 이 세 Preview 의 screenshot 골든은 없다. Co-Authored-By: Claude Opus 5 (1M context) --- .../presentation/component/InsightCard.kt | 67 ----------- .../component/WeeklyEmotionCard.kt | 60 ---------- .../component/WeeklyReportCard.kt | 106 ------------------ .../src/main/res/values/strings.xml | 6 - 4 files changed, 239 deletions(-) delete mode 100644 feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/InsightCard.kt delete mode 100644 feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/WeeklyEmotionCard.kt delete mode 100644 feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/WeeklyReportCard.kt 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/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/res/values/strings.xml b/feature/mindrecord/presentation/src/main/res/values/strings.xml index 3961b5779b..cb1c9f05fe 100644 --- a/feature/mindrecord/presentation/src/main/res/values/strings.xml +++ b/feature/mindrecord/presentation/src/main/res/values/strings.xml @@ -84,14 +84,10 @@ 답변하러가기 - 주간 리포트 - 이번 주 나의 기록들을 확인해 보세요. 총 기록 이번 주 이번 달 주간 평균 기분 - 주간 평균 감정 - 😊 좋음 %1$d월 %2$d주차 리포트 11월 2주차 리포트 - 이번주는 가족과 함께하는 시간을 가장 많이 기록하셨네요. 일상의 소중함을 느끼는 한주였던 것 같아요. - 매일 꾸준히 기록하는 습관이 정말 멋져요! 나의 감정 키워드 From 20b6d41a632d959c4a166f480dad9d0946d1dd72 Mon Sep 17 00:00:00 2001 From: Sadturtleman Date: Sun, 30 Aug 2026 13:03:57 +0900 Subject: [PATCH 3/8] =?UTF-8?q?refactor(mindrecord,home):=20no-op=20?= =?UTF-8?q?=EC=BD=9C=EB=B0=B1=20=EB=94=94=ED=8F=B4=ED=8A=B8=2050=EA=B1=B4?= =?UTF-8?q?=EC=9D=84=20=EA=B1=B7=EA=B3=A0=20=EA=B0=80=EB=A0=A4=EC=A0=B8=20?= =?UTF-8?q?=EC=9E=88=EB=8D=98=20=EB=B0=B0=EC=84=A0=20=EB=88=84=EB=9D=BD=20?= =?UTF-8?q?2=EA=B1=B4=EC=9D=84=20=EA=B3=A0=EC=B9=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `onXxx: (...) -> Unit = {}` 는 배선을 빠뜨려도 컴파일이 통과해 조용히 no-op 이 된다 (#1540). mindrecord 47 + home 3 = **50건을 전부 걷었다.** main 소스 잔여 0건이다. ## 디폴트가 실제로 결함을 가리고 있었다 이슈가 「디폴트가 가려 온 결함이 있는지 확인」을 완료 조건에 뒀다. 걷어내자 컴파일러가 **실호출부 2곳**을 드러냈다. 둘 다 버튼이 보이는데 눌러도 아무 일이 없던 자리다. **(1) `WriteTextField` → `TextStyleToolbar`** — `onLinkClick`·`onTypeClick` 미전달. 링크 아이콘과 «T» 버튼이 그려지는데 핸들러가 없었다. 같은 파일 `BottomToolbar` 가 같은 두 버튼을 갖고 있어 그 배선을 그대로 가져왔다(스타일 툴바가 하단 툴바를 덮으므로 같은 affordance 를 유지해야 한다). **(2) `WeeklyReportScreen` HISTORY → `DailyQuestionListCard`** — `onEdit`·`onDelete` 미전달. «더보기» 메뉴가 뜨고 수정·삭제가 전부 no-op 이었다. `DailyQuestionListCard` 를 nullable 핸들러로 재모델링해 **핸들러가 없으면 메뉴 자체를 그리지 않게** 했고, 읽기 전용 요약인 주간 리포트는 `null` 을 명시한다. #1540 이 든 처방 그대로다. 가드: `RecordActionAffordanceTest` 2건. 역검증 — 항상 그리도록 되돌리면 FAILED. ## 나머지 - 프리뷰·screenshotTest·unit test 호출부 30곳은 `{}` 를 명시로 바꿨다(디폴트와 동작 동일). - `{ _, _ -> }` 꼴 4건은 첫 정규식이 놓쳤고 `NoOpCallbackDefaultKonsistTest` 가 잡아 함께 걷었다. - 그 konsist 허용목록에서 mindrecord·home 항목 16개를 비웠다 — 남겨 두면 **다음 위반이 그 자리에 숨는다.** 이제 이 두 모듈은 신규 유입이 곧바로 red 다. timeletter(#1541) 만 남는다. - 스크린샷 골든: 실패 집합이 develop 과 동일(새로 틀어진 것 0건). 판단이 들어간 (2) 의 근거는 `docs/qa/assumptions.md` 에 적었다. Co-Authored-By: Claude Opus 5 (1M context) --- docs/qa/assumptions.md | 28 ++++++++ .../home/presentation/WeeklySummaryGrid.kt | 12 ++-- .../component/DailyQuestionListCard.kt | 69 +++++++++++-------- .../presentation/component/DiaryCard.kt | 8 ++- .../presentation/component/DiaryComponent.kt | 8 ++- .../presentation/component/KeyBoardToolBar.kt | 10 +-- .../presentation/component/MemoriesCard.kt | 7 +- .../component/TodayQuestionCard.kt | 4 +- .../component/WeeklyReportReviewCard.kt | 6 +- .../presentation/component/WriteTextField.kt | 14 +++- .../screen/sender/DailyQuestionWriteScreen.kt | 18 ++--- .../screen/sender/DiaryWriteScreen.kt | 22 +++--- .../presentation/screen/sender/HomeScreen.kt | 12 ++-- .../DailyQuestionWriteScreenScreenshotTest.kt | 12 ++++ .../sender/DiaryWriteScreenScreenshotTest.kt | 16 +++++ .../presentation/MindRecordFlowTest.kt | 16 ++++- .../presentation/MindRecordLifecycleTest.kt | 17 ++++- .../component/RecordActionAffordanceTest.kt | 68 ++++++++++++++++++ .../component/WriteTextFieldReseedTest.kt | 15 +++- .../konsist/NoOpCallbackDefaultKonsistTest.kt | 30 ++------ 20 files changed, 286 insertions(+), 106 deletions(-) create mode 100644 feature/mindrecord/presentation/src/test/kotlin/com/afternote/feature/mindrecord/presentation/component/RecordActionAffordanceTest.kt diff --git a/docs/qa/assumptions.md b/docs/qa/assumptions.md index ef4b1b7da4..f9d19592e9 100644 --- a/docs/qa/assumptions.md +++ b/docs/qa/assumptions.md @@ -390,3 +390,31 @@ navigate 대상 한 줄. **뒤집을 때**: 검색은 `filterEditorServiceOptions` 함수 하나, 후보 노출은 `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 로 열려 있다). 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 8bb11cef7f..ef4f9afabb 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 @@ -37,9 +37,9 @@ fun WeeklySummaryGrid( recordedCount: Int = 7, recentRecordDate: String = "26.02.01", recentRecordTitle: String = "최근 기록 제목최근 기록 제목...", - onImageClick: () -> Unit = {}, - onCountCardClick: () -> Unit = {}, - onRecentRecordClick: () -> Unit = {}, + onImageClick: () -> Unit, + onCountCardClick: () -> Unit, + onRecentRecordClick: () -> Unit, ) { BoxWithConstraints(modifier = modifier.fillMaxWidth()) { val gap = 8.dp @@ -167,6 +167,10 @@ fun WeeklySummaryGrid( @Composable private fun WeeklySummaryGridPreview() { AfternoteTheme { - WeeklySummaryGrid() + WeeklySummaryGrid( + onImageClick = {}, + onCountCardClick = {}, + onRecentRecordClick = {}, + ) } } 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 bd53ed0d89..eec52f0e71 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,8 +50,8 @@ private val DateFormatter = DateTimeFormatter.ofPattern("yyyy.MM.dd") fun DailyQuestionListCard( answer: DailyQuestion, modifier: Modifier = Modifier, - onEdit: () -> Unit = {}, - onDelete: () -> Unit = {}, + onEdit: (() -> Unit)?, + onDelete: (() -> Unit)?, ) { OutlinedCard( colors = @@ -74,8 +74,8 @@ fun DailyQuestionListCard( @Composable private fun TextCardContent( answer: DailyQuestion, - onEdit: () -> Unit, - onDelete: () -> Unit, + onEdit: (() -> Unit)?, + onDelete: (() -> Unit)?, ) { Column( modifier = Modifier.padding(16.dp), @@ -104,8 +104,8 @@ private fun TextCardContent( @Composable private fun ThumbnailCardContent( answer: DailyQuestion, - onEdit: () -> Unit, - onDelete: () -> Unit, + onEdit: (() -> Unit)?, + onDelete: (() -> Unit)?, ) { Row( modifier = Modifier.padding(12.dp), @@ -147,8 +147,8 @@ private fun ThumbnailCardContent( @Composable private fun CardHeaderRow( date: LocalDate, - onEdit: () -> Unit, - onDelete: () -> Unit, + onEdit: (() -> Unit)?, + onDelete: (() -> Unit)?, ) { var menuExpanded by remember { mutableStateOf(false) } @@ -170,28 +170,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() + }, + ) + } } } } @@ -208,6 +215,8 @@ private fun DailyQuestionCardPreview() { content = "아무 말 없이 그저 나의 곁을 지켜주는 아내가 고맙다.", date = LocalDate.now(), ), + onDelete = {}, + onEdit = {}, ) } } @@ -224,6 +233,8 @@ private fun DailyQuestionCardWithImagePreview() { date = LocalDate.now(), imageUrl = "https://example.com/image.jpg", ), + 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 4cd2138d84..eb5af4634f 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 @@ -52,8 +52,8 @@ private val DateFormatter = DateTimeFormatter.ofPattern("yyyy.MM.dd") fun DiaryCard( diary: DailyDiary, modifier: Modifier = Modifier, - onEdit: () -> Unit = {}, - onDelete: () -> Unit = {}, + onEdit: () -> Unit, + onDelete: () -> Unit, ) { var menuExpanded by remember { mutableStateOf(false) } @@ -186,6 +186,8 @@ private fun DiaryCardPreview() { emotion = "😊", imageUrl = "https://example.com/image.jpg", ), + onDelete = {}, + onEdit = {}, ) } } @@ -202,6 +204,8 @@ private fun DiaryCardNoImagePreview() { date = LocalDate.now(), emotion = "😊", ), + 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 77125b84df..84c5b993b7 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 @@ -50,8 +50,8 @@ private val DateFormatter = DateTimeFormatter.ofPattern("yyyy.MM.dd") fun DiaryComponent( diary: DailyDiary, modifier: Modifier = Modifier, - onEdit: () -> Unit = {}, - onDelete: () -> Unit = {}, + onEdit: () -> Unit, + onDelete: () -> Unit, ) { var menuExpanded by remember { mutableStateOf(false) } @@ -169,6 +169,8 @@ private fun DiaryComponentPreview() { emotion = "😊", imageUrl = "https://example.com/image.jpg", ), + onDelete = {}, + onEdit = {}, ) } } @@ -185,6 +187,8 @@ private fun DiaryComponentNoImagePreview() { date = LocalDate.now(), emotion = "😊", ), + onDelete = {}, + onEdit = {}, ) } } 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 cd3da5582d..086a9fcf10 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, ) { @@ -130,8 +130,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/MemoriesCard.kt b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/MemoriesCard.kt index 5ae919d2ac..c404a75a94 100644 --- a/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/MemoriesCard.kt +++ b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/MemoriesCard.kt @@ -55,7 +55,7 @@ fun MemoriesCard( modifier: Modifier = Modifier, question: String? = null, answer: String? = null, - onReadAgainClick: () -> Unit = {}, + onReadAgainClick: () -> Unit, ) { val cardShape = RoundedCornerShape(8.dp) val buttonShape = RoundedCornerShape(20.dp) @@ -154,6 +154,7 @@ private fun MemoriesCardPreview() { MemoriesCard( question = "내 인생에서 가장 소중했던 순간은?", answer = "아이가 태어났을 때...", + onReadAgainClick = {}, ) } } @@ -163,6 +164,8 @@ private fun MemoriesCardPreview() { @Composable private fun MemoriesCardEmptyPreview() { AfternoteTheme { - MemoriesCard() + MemoriesCard( + onReadAgainClick = {}, + ) } } 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/WeeklyReportReviewCard.kt b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/component/WeeklyReportReviewCard.kt index fe1af8b9d1..5ef943a8da 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( @@ -214,6 +214,8 @@ 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 a64e0d6622..a5503747fd 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 @@ -70,8 +70,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 을 반환하는 업로더 @@ -275,6 +275,11 @@ fun WriteTextField( onTextStyleChange = { type -> keepEditorFocus { state.addSpanStyle(type.toSpanStyle()) } }, + // **하단 툴바와 같은 배선이다.** 스타일 툴바가 열리면 하단 툴바를 덮으므로 + // 같은 두 affordance(링크·«T»)를 그대로 갖는다. 종전에는 두 인자를 넘기지 + // 않아 no-op 디폴트가 먹었고, **눌러도 아무 일이 없는 버튼 두 개**였다 (#1540). + onLinkClick = { sheet = KeyboardSheet.MediaSelect }, + onTypeClick = { showTextStyleToolbar = !showTextStyleToolbar }, ) } @@ -358,7 +363,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/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/DiaryWriteScreen.kt b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/DiaryWriteScreen.kt index 7f72ff0a8c..c69287903b 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/HomeScreen.kt b/feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/screen/sender/HomeScreen.kt index ebf1252990..653243467f 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 @@ -51,9 +51,9 @@ fun HomeScreen( // 마음의 기록 탭 진입마다 요약 조회가 한 번 나간다. 대신 탭을 열면 스피너 없이 즉시 보이는 // 프리페치가 되므로 트레이드오프를 받아들인다. weeklyReportViewModel: WeeklyReportViewModel = hiltViewModel(), - onWriteClick: (MindRecordCategoryUi) -> Unit = {}, - onEditDailyQuestion: (Long) -> Unit = {}, - onEditDiary: (Long, YearMonth) -> Unit = { _, _ -> }, + onWriteClick: (MindRecordCategoryUi) -> Unit, + onEditDailyQuestion: (Long) -> Unit, + onEditDiary: (Long, YearMonth) -> Unit, ) { // Figma 2757:16116 — 마음의 기록 탭은 데일리 질문 / 일기 / 주간리포트 3개 val categories = @@ -210,6 +210,10 @@ fun HomeScreen( @Composable private fun HomeScreenPreview() { AfternoteTheme { - HomeScreen() + HomeScreen( + onEditDailyQuestion = {}, + onWriteClick = {}, + onEditDiary = { _, _ -> }, + ) } } 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 2290395309..0b211619ca 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 @@ -87,7 +87,10 @@ class MindRecordLifecycleTest { composeRule.setContent { AfternoteTheme { - DiaryScreen(viewModel = viewModel) + DiaryScreen( + viewModel = viewModel, + onEditClick = { _, _ -> }, + ) } } @@ -161,7 +164,12 @@ class MindRecordLifecycleTest { composeRule.setContent { AfternoteTheme { - DraftListScreen(viewModel = viewModel) + DraftListScreen( + viewModel = viewModel, + onBackClick = {}, + onDailyQuestionDraftClick = {}, + onDiaryDraftClick = { _, _ -> }, + ) } } @@ -300,7 +308,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/RecordActionAffordanceTest.kt b/feature/mindrecord/presentation/src/test/kotlin/com/afternote/feature/mindrecord/presentation/component/RecordActionAffordanceTest.kt new file mode 100644 index 0000000000..426ce34d41 --- /dev/null +++ b/feature/mindrecord/presentation/src/test/kotlin/com/afternote/feature/mindrecord/presentation/component/RecordActionAffordanceTest.kt @@ -0,0 +1,68 @@ +package com.afternote.feature.mindrecord.presentation.component + +import androidx.activity.ComponentActivity +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onNodeWithContentDescription +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.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) + } + } + + composeRule + .onNodeWithContentDescription(moreMenuLabel()) + .assertDoesNotExist() + } + + @Test + fun `핸들러가 있으면 더보기를 그린다`() { + composeRule.setContent { + AfternoteTheme { + DailyQuestionListCard(answer = answer, onEdit = {}, onDelete = {}) + } + } + + composeRule + .onNodeWithContentDescription(moreMenuLabel()) + .assertIsDisplayed() + } + + 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/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/konsist/src/test/kotlin/com/afternote/konsist/NoOpCallbackDefaultKonsistTest.kt b/konsist/src/test/kotlin/com/afternote/konsist/NoOpCallbackDefaultKonsistTest.kt index bdb4fedc0e..8ff2627b34 100644 --- a/konsist/src/test/kotlin/com/afternote/konsist/NoOpCallbackDefaultKonsistTest.kt +++ b/konsist/src/test/kotlin/com/afternote/konsist/NoOpCallbackDefaultKonsistTest.kt @@ -29,7 +29,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 전례와 같은 구조). 이미 청소된 항목이 목록에 @@ -139,31 +139,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 = From dbb5741668c38ddf09fd899d94371476c92c9843 Mon Sep 17 00:00:00 2001 From: Sadturtleman Date: Mon, 31 Aug 2026 11:40:06 +0900 Subject: [PATCH 4/8] =?UTF-8?q?fix(test):=20=EA=B3=84=EC=B8=A1=C2=B7screen?= =?UTF-8?q?shotTest=20=ED=98=B8=EC=B6=9C=EB=B6=80=EC=97=90=EB=8F=84=20?= =?UTF-8?q?=EA=B1=B7=EC=96=B4=EB=82=B8=20=EB=94=94=ED=8F=B4=ED=8A=B8?= =?UTF-8?q?=EB=A5=BC=20=EB=AA=85=EC=8B=9C=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 앞 커밋이 `:feature:mindrecord:presentation` 과 `:feature:home:presentation` 의 main·test 소스만 컴파일해 두 소스셋을 빠뜨렸다. CI 가 두 갈래로 잡았다. | 잡 | 원인 | |---|---| | `Unit Test / Run Unit Tests` | `:app:compileDebugAndroidTestKotlin` — 계측 2파일 7곳 | | `Screenshot / Validate Compose Preview Screenshots` | `:feature:home:presentation:compileDebugScreenshotTestKotlin` — `WeeklySummaryGridScreenshotTest` 1곳 | home 의 screenshotTest 가 컴파일되지 않아 그 모듈은 **골든을 한 장도 렌더하지 못했다** — 아티팩트에 home 파일이 0건인 것이 그 흔적이다. 픽셀 차이가 아니었다. > mindrecord 쪽은 CI 가 렌더한 11장이 레포 골든과 **바이트 동일**했다. 로딩 통합이 렌더를 > 바꾸지 않는다는 주장이 CI 환경에서도 확인된 셈이다. `TimeLetterMindRecordCompletionAndroidTest` 의 `onEditClick` 은 `DailyQuestionAnswerListScreen` 쪽이라 `(Long) -> Unit` 이다 — 일괄 치환이 `{ _, _ -> }` 를 넣어 한 번 더 깨졌고 실인자로 고쳤다. 같은 이름이 화면마다 arity 가 다르다. 이번엔 이 변경을 참조할 수 있는 **9개 소스셋 전부**를 컴파일해 확인했다 (app main·unitTest·androidTest / mindrecord·home 의 main·unitTest·screenshotTest). Co-Authored-By: Claude Opus 5 (1M context) --- .../DailyQuestionResumeFailureAndroidTest.kt | 14 ++++++++++++-- .../TimeLetterMindRecordCompletionAndroidTest.kt | 16 ++++++++++++++-- .../WeeklySummaryGridScreenshotTest.kt | 7 ++++++- 3 files changed, 32 insertions(+), 5 deletions(-) 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 42086d8f88..9e0b4ee539 100644 --- a/app/src/androidTest/java/com/afternote/afternote_fe/TimeLetterMindRecordCompletionAndroidTest.kt +++ b/app/src/androidTest/java/com/afternote/afternote_fe/TimeLetterMindRecordCompletionAndroidTest.kt @@ -367,7 +367,10 @@ class TimeLetterMindRecordCompletionAndroidTest { composeRule.setContent { AfternoteTheme { - DailyQuestionAnswerListScreen(viewModel = activeViewModel) + DailyQuestionAnswerListScreen( + viewModel = activeViewModel, + onEditClick = {}, + ) } } @@ -427,7 +430,10 @@ class TimeLetterMindRecordCompletionAndroidTest { val activeWriteViewModel = writeViewModel AfternoteTheme { if (activeWriteViewModel == null) { - DailyQuestionAnswerListScreen(viewModel = listViewModel) + DailyQuestionAnswerListScreen( + viewModel = listViewModel, + onEditClick = {}, + ) } else { DailyQuestionWriteScreen( viewModel = activeWriteViewModel, @@ -436,6 +442,8 @@ class TimeLetterMindRecordCompletionAndroidTest { writeViewModel = null listViewModel.refreshOnReturn() }, + onBackClick = {}, + onDraftListClick = {}, ) } } @@ -545,11 +553,15 @@ class TimeLetterMindRecordCompletionAndroidTest { errorReporter = FakeErrorReporter(), ) }, + onBackClick = {}, + onDailyQuestionDraftClick = {}, ) } else { DiaryWriteScreen( viewModel = activeWriteViewModel, onSubmitSuccess = { submitSuccessCalls += 1 }, + onBackClick = {}, + onDraftListClick = {}, ) } } 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 5b4461d3dd..dd9f3c9965 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(modifier = Modifier.padding(16.dp)) + WeeklySummaryGrid( + modifier = Modifier.padding(16.dp), + onImageClick = {}, + onCountCardClick = {}, + onRecentRecordClick = {}, + ) } } From ea3755eb18dbb365e2443c3c5f0ec8008975ac39 Mon Sep 17 00:00:00 2001 From: Sadturtleman Date: Tue, 1 Sep 2026 14:20:07 +0900 Subject: [PATCH 5/8] =?UTF-8?q?fix(mindrecord):=20=EC=9D=BD=EA=B8=B0=20?= =?UTF-8?q?=EC=A0=84=EC=9A=A9=20=EC=B9=B4=EB=93=9C=EC=97=90=20=ED=81=B4?= =?UTF-8?q?=EB=A6=AD=20semantics=20=EB=A5=BC=20=EB=B6=99=EC=9D=B4=EC=A7=80?= =?UTF-8?q?=20=EC=95=8A=EB=8A=94=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 리뷰 지적이 맞다. 디폴트를 걷어낸 대신 **같은 no-op 을 호출부에 명시**해 둔 자리가 남아 있었다. `DailyQuestionListCard` 는 `onClick` 에 항상 `Role.Button` clickable 을 붙인다. 주간 리포트 HISTORY 는 읽기 전용인데 `onClick = {}` 를 넘겨, **스크린리더가 「버튼」으로 읽는데 눌러도 아무 일이 없었다.** #1540 이 없애려던 「눌러도 아무 일 없는 버튼」이 형태만 바꿔 남은 셈이다. `onClick` 을 nullable 로 바꿔 **`null` 이면 clickable 자체를 안 붙인다** — `onEdit`·`onDelete` 와 같은 처방이다. 주간 리포트는 셋 다 `null` 이라 클릭 semantics 가 없다. 가드 2건(양방향): onClick 이 없으면 카드에 클릭 semantics 를 붙이지 않는다 → hasClickAction 노드 0 onClick 이 있으면 카드가 눌린다 → 노드 1 + 콜백 1회 역검증: 항상 clickable 로 되돌리면 앞쪽 FAILED. > `RecordListMonthTest` 1건이 실패하지만 develop 을 그대로 체크아웃해도 같은 1건이 실패한다 > (`Failed to inject touch input`). 이 PR 과 무관하다. Co-Authored-By: Claude Opus 5 (1M context) --- .../component/DailyQuestionListCard.kt | 13 ++++++-- .../screen/sender/WeeklyReportScreen.kt | 5 ++- .../component/RecordActionAffordanceTest.kt | 32 +++++++++++++++++++ 3 files changed, 47 insertions(+), 3 deletions(-) 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 c1fa3b8761..75fa313f29 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 @@ -51,7 +51,13 @@ fun DailyQuestionListCard( answer: DailyQuestion, modifier: Modifier = Modifier, /** 카드 전체 탭 — 저장된 기록 본문을 여는 상세 화면으로 간다 (#759). */ - onClick: () -> Unit, + /** + * 카드 전체 탭. **`null` 이면 클릭 자체를 붙이지 않는다** (#1540 리뷰). + * + * no-op 을 넘기면 `Role.Button` 이 그대로 실려 스크린리더가 「버튼」으로 읽는데 눌러도 + * 아무 일이 없다 — 읽기 전용으로 쓰는 자리(주간 리포트 HISTORY)가 그랬다. + */ + onClick: (() -> Unit)?, onEdit: (() -> Unit)?, onDelete: (() -> Unit)?, ) { @@ -62,7 +68,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) 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 d2c7d9b667..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 @@ -152,11 +152,14 @@ private fun WeeklyReportContent( state.dailyQuestions.forEach { dailyQuestion -> // 주간 리포트는 읽기 전용 요약이다 — 편집·삭제는 데일리질문 목록의 몫이라 // 여기서는 «더보기» 를 그리지 않는다 (#1540). + // 주간 리포트는 **읽기 전용 요약**이다 — 편집·삭제도, 카드 탭도 없다. + // 셋 다 `null` 이라 클릭 semantics 자체가 안 붙는다: no-op 을 넘기면 + // 스크린리더가 「버튼」으로 읽는데 눌러도 아무 일이 없다 (#1540 리뷰). DailyQuestionListCard( answer = dailyQuestion, + onClick = null, onEdit = null, onDelete = null, - onClick = {}, ) } } 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 index dbb121660b..b9324c05e6 100644 --- 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 @@ -1,12 +1,17 @@ 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 @@ -74,5 +79,32 @@ class RecordActionAffordanceTest { .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) } From 4951c6eaeaf3810ba039b1f0c366a5ba94e1ef99 Mon Sep 17 00:00:00 2001 From: Sadturtleman Date: Tue, 1 Sep 2026 20:05:57 +0900 Subject: [PATCH 6/8] =?UTF-8?q?style(mindrecord):=20=ED=8C=8C=EB=9D=BC?= =?UTF-8?q?=EB=AF=B8=ED=84=B0=20KDoc=20=EC=9D=B4=20=EB=91=90=20=EA=B2=B9?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=82=A8=EC=9D=80=20=EA=B2=83=EC=9D=84=20?= =?UTF-8?q?=ED=95=A9=EC=B9=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit nullable 로 바꾸며 새 KDoc 을 넣고 옛 것을 안 지워, 파라미터 하나에 KDoc 이 둘이 됐다 (`standard:no-consecutive-comments`). 두 문장을 한 KDoc 으로 합쳤다. `ktlintFormat` 은 이 규칙을 자동 교정하지 못한다 — 포맷만 돌리고 `ktlintCheck` 를 안 돌려 로컬에서 못 봤다. 이번엔 저장소 전체 `ktlintCheck` 로 확인했다. Co-Authored-By: Claude Opus 5 (1M context) --- .../presentation/component/DailyQuestionListCard.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 75fa313f29..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,9 +50,10 @@ private val DateFormatter = DateTimeFormatter.ofPattern("yyyy.MM.dd") fun DailyQuestionListCard( answer: DailyQuestion, modifier: Modifier = Modifier, - /** 카드 전체 탭 — 저장된 기록 본문을 여는 상세 화면으로 간다 (#759). */ /** - * 카드 전체 탭. **`null` 이면 클릭 자체를 붙이지 않는다** (#1540 리뷰). + * 카드 전체 탭 — 저장된 기록 본문을 여는 상세 화면으로 간다 (#759). + * + * **`null` 이면 클릭 자체를 붙이지 않는다** (#1540 리뷰). * * no-op 을 넘기면 `Role.Button` 이 그대로 실려 스크린리더가 「버튼」으로 읽는데 눌러도 * 아무 일이 없다 — 읽기 전용으로 쓰는 자리(주간 리포트 HISTORY)가 그랬다. From fbd69a15dd24cff6b434a97e08c0d0dd763aa96c Mon Sep 17 00:00:00 2001 From: Sadturtleman Date: Tue, 1 Sep 2026 20:20:14 +0900 Subject: [PATCH 7/8] =?UTF-8?q?test(mindrecord):=20=EB=AA=A9=EB=A1=9D=20?= =?UTF-8?q?=ED=95=AD=EB=AA=A9=EA=B9=8C=EC=A7=80=20=EC=8A=A4=ED=81=AC?= =?UTF-8?q?=EB=A1=A4=ED=95=9C=20=EB=92=A4=20=EB=88=8C=EB=9F=AC=20=EB=8B=AC?= =?UTF-8?q?=20=EC=A0=84=EB=8B=AC=EC=9D=84=20=EA=B2=80=EC=A6=9D=ED=95=9C?= =?UTF-8?q?=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `RecordListMonthTest > 카드를 누르면 보고 있는 달이 함께 전달된다` 가 이 브랜치에서 `Failed to inject touch input … There are no existing nodes` 로 깨졌다. **이 PR 이 원인이다.** 앞선 커밋·댓글에서 「develop 에서도 실패하는 기존 건」이라고 적었는데 틀렸다 — 그때 `git stash` 로 비교한 것이 develop 이 아니라 이 브랜치의 커밋 상태였다. 격리 실행으로 다시 재면 develop 6회 전부 통과, 이 브랜치 3회 전부 실패다. 원인은 클릭이 아니라 **합성 범위**다. 목록은 캘린더가 먼저 오는 LazyColumn 이고 테스트 창은 320×470px 라, 기록 카드가 보이는 영역 밖이면 아예 합성되지 않아 노드가 없다. 스크롤 위치에 기대고 있던 테스트라 이 PR 의 레이아웃 높이 변화에 그대로 걸렸다. 이 테스트가 보려는 것은 «누르면 무엇이 넘어가는가» 이므로 항목까지 스크롤해 놓고 누른다. 높이가 또 달라져도 깨지지 않는다. 3회 연속 통과를 확인했다. Co-Authored-By: Claude Opus 5 (1M context) --- .../presentation/screen/sender/RecordListMonthTest.kt | 7 +++++++ 1 file changed, 7 insertions(+) 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 84c99db613..1683d49ae8 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 @@ -1,9 +1,12 @@ package com.afternote.feature.mindrecord.presentation.screen.sender import androidx.activity.ComponentActivity +import androidx.compose.ui.test.hasScrollToNodeAction +import androidx.compose.ui.test.hasText import androidx.compose.ui.test.junit4.createAndroidComposeRule import androidx.compose.ui.test.onAllNodesWithText import androidx.compose.ui.test.performClick +import androidx.compose.ui.test.performScrollToNode import com.afternote.core.ui.theme.AfternoteTheme import com.afternote.feature.mindrecord.presentation.model.DailyDiary import org.junit.Assert.assertEquals @@ -54,6 +57,10 @@ class RecordListMonthTest { } } + // 목록은 캘린더가 먼저 오는 LazyColumn 이라 기록 카드가 화면 밖에서 시작할 수 있다. + // 스크롤 위치에 기대면 캘린더 높이가 조금만 달라져도 「노드가 없다」로 깨진다 — + // 이 테스트가 보려는 것은 «누르면 무엇이 넘어가는가» 이므로 항목까지 스크롤해 놓고 누른다. + composeRule.onNode(hasScrollToNodeAction()).performScrollToNode(hasText("지난달 기록")) composeRule.onAllNodesWithText("지난달 기록")[0].performClick() assertEquals(11L to lastMonth, clicked) From 3948c01f58169327a2b335a80bd59223284372fc Mon Sep 17 00:00:00 2001 From: Sadturtleman Date: Thu, 3 Sep 2026 20:51:35 +0900 Subject: [PATCH 8/8] =?UTF-8?q?test(mindrecord):=20develop=20=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EC=98=A8=20=ED=98=B8=EC=B6=9C=EB=B6=80=EC=97=90?= =?UTF-8?q?=EB=8F=84=20=EA=B1=B7=EC=96=B4=EB=82=B8=20=EB=94=94=ED=8F=B4?= =?UTF-8?q?=ED=8A=B8=EB=A5=BC=20=EB=AA=85=EC=8B=9C=ED=95=9C=EB=8B=A4=20(#1?= =?UTF-8?q?540)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 이 PR 이 no-op 디폴트를 걷는 동안 develop 에 새 테스트가 들어와, 병합 뒤 그쪽이 디폴트에 기대 컴파일이 깨졌다. WriteTextField 두 곳과 WeeklyReportReviewCard 한 곳에 인자를 채운다. MemoriesCard 의 onReadAgainClick 은 develop 판(nullable)을 택했다 — 이 PR 의 «no-op 디폴트 제거» 의도를 포함하면서 CTA 부재까지 표현한다 (#793). Co-Authored-By: Claude Opus 5 (1M context) --- .../presentation/component/MediaSheetMigrationTest.kt | 4 ++-- .../presentation/component/WeeklyCardFontScaleTest.kt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) 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/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 = {}) } } } }