Skip to content

Commit f302cab

Browse files
authored
Merge pull request #55 from Nexters/feature/detail-screen-note-FD-252
[FD-252] 상세 화면 디자인 개선
2 parents b8b7387 + dcc4b69 commit f302cab

18 files changed

Lines changed: 414 additions & 52 deletions

File tree

core/common/src/main/res/values/strings.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
<string name="home_button_select">선택하기</string>
5959

6060
<!-- Detail -->
61-
<string name="detail_food_analyze">귀찮은 입력은 AI가 대신하고 있어요..</string>
61+
<string name="detail_food_analyze">귀찮은 입력은 AI가 대신하고 있어요...</string>
6262

6363
<!-- Calendar -->
6464
<string name="calendar">캘린더</string>

core/ui/src/main/java/com/nexters/fooddiary/core/ui/food/FoodImageCard.kt

Lines changed: 83 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import androidx.compose.foundation.background
55
import androidx.compose.foundation.border
66
import androidx.compose.foundation.layout.Arrangement
77
import androidx.compose.foundation.layout.Box
8+
import androidx.compose.foundation.layout.Column
89
import androidx.compose.foundation.layout.Row
910
import androidx.compose.foundation.layout.defaultMinSize
1011
import androidx.compose.foundation.layout.fillMaxSize
@@ -15,6 +16,7 @@ import androidx.compose.material3.Text
1516
import androidx.compose.runtime.Composable
1617
import androidx.compose.ui.Alignment
1718
import androidx.compose.ui.Modifier
19+
import androidx.compose.ui.draw.blur
1820
import androidx.compose.ui.draw.clip
1921
import androidx.compose.ui.draw.drawBehind
2022
import androidx.compose.ui.geometry.CornerRadius
@@ -28,6 +30,7 @@ import androidx.compose.ui.platform.LocalInspectionMode
2830
import androidx.compose.ui.res.painterResource
2931
import androidx.compose.ui.res.stringResource
3032
import androidx.compose.ui.text.font.FontWeight
33+
import androidx.compose.ui.text.style.TextAlign
3134
import androidx.compose.ui.tooling.preview.Preview
3235
import androidx.compose.ui.unit.dp
3336
import coil3.compose.AsyncImage
@@ -99,6 +102,11 @@ fun FoodImageCard(
99102
locationText = state.locationText,
100103
)
101104
}
105+
is FoodImageState.Processing -> {
106+
FoodImageProcessingCard(
107+
imageUrl = imageUrl,
108+
)
109+
}
102110
is FoodImageState.Pending -> {
103111
FoodImagePending(
104112
modifier = Modifier.fillMaxSize(),
@@ -115,6 +123,8 @@ private fun TagChip(
115123
textColor: Color,
116124
modifier: Modifier = Modifier
117125
) {
126+
if (text.isBlank()) return
127+
118128
Box(
119129
modifier = modifier
120130
.defaultMinSize(minHeight = 18.dp)
@@ -158,22 +168,68 @@ private fun FoodImage(
158168
}
159169

160170
// 상단: 시간 + 위치 태그
161-
Row(
171+
if (timeText.isNotBlank() || locationText.isNotBlank()) {
172+
Row(
173+
modifier = Modifier
174+
.align(Alignment.TopStart)
175+
.padding(10.dp),
176+
horizontalArrangement = Arrangement.spacedBy(6.dp),
177+
verticalAlignment = Alignment.CenterVertically
178+
) {
179+
TagChip(
180+
text = timeText,
181+
backgroundColor = TimeLocationBg,
182+
textColor = White,
183+
)
184+
TagChip(
185+
text = locationText,
186+
backgroundColor = TimeLocationBg,
187+
textColor = White,
188+
)
189+
}
190+
}
191+
}
192+
}
193+
194+
@Composable
195+
private fun FoodImageProcessingCard(
196+
imageUrl: String,
197+
) {
198+
Box(modifier = Modifier.fillMaxSize()) {
199+
AsyncImage(
200+
model = imageUrl,
201+
contentDescription = "Food image processing",
202+
contentScale = ContentScale.Crop,
203+
placeholder = previewPlaceholder(),
204+
error = previewPlaceholder(),
205+
modifier = Modifier
206+
.fillMaxSize()
207+
.blur(20.dp),
208+
)
209+
210+
Box(
162211
modifier = Modifier
163-
.align(Alignment.TopStart)
164-
.padding(10.dp),
165-
horizontalArrangement = Arrangement.spacedBy(6.dp),
166-
verticalAlignment = Alignment.CenterVertically
212+
.fillMaxSize()
213+
.background(Color.Black.copy(alpha = 0.35f))
214+
)
215+
216+
Column(
217+
modifier = Modifier
218+
.align(Alignment.Center)
219+
.padding(horizontal = 24.dp),
220+
horizontalAlignment = Alignment.CenterHorizontally,
221+
verticalArrangement = Arrangement.spacedBy(12.dp),
167222
) {
168-
TagChip(
169-
text = timeText,
170-
backgroundColor = TimeLocationBg,
171-
textColor = White,
223+
Image(
224+
painter = painterResource(drawable.ic_img_analysis_processing),
225+
contentDescription = null,
226+
modifier = Modifier.size(155.dp, 158.dp),
172227
)
173-
TagChip(
174-
text = locationText,
175-
backgroundColor = TimeLocationBg,
176-
textColor = White,
228+
Text(
229+
text = stringResource(string.detail_food_analyze),
230+
style = AppTypography.p12,
231+
color = White,
232+
textAlign = TextAlign.Center,
177233
)
178234
}
179235
}
@@ -233,6 +289,20 @@ private fun FoodImageReadyPreview() {
233289
)
234290
}
235291

292+
@Preview(
293+
name = "Processing State",
294+
showBackground = true,
295+
backgroundColor = 0xFF191821
296+
)
297+
@Composable
298+
private fun FoodImageProcessingPreview() {
299+
FoodImageCard(
300+
imageUrl = "https://picsum.photos/300",
301+
state = FoodImageState.Processing,
302+
modifier = Modifier.size(300.dp)
303+
)
304+
}
305+
236306
@Preview(
237307
name = "Pending State",
238308
showBackground = true,

core/ui/src/main/java/com/nexters/fooddiary/core/ui/food/FoodImageState.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,7 @@ sealed interface FoodImageState {
77
val locationText: String, // 마포구
88
) : FoodImageState
99

10+
data object Processing : FoodImageState // AI 분석 진행 중 (이미지 블러 + 오버레이)
11+
1012
data object Pending : FoodImageState // AI 분석 중 상태
1113
}

core/ui/src/main/java/com/nexters/fooddiary/core/ui/theme/AppTypography.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ object AppTypography {
5858
fontFamily = PretendardFontFamily,
5959
fontWeight = FontWeight.Normal,
6060
fontSize = 12.sp,
61-
lineHeight = 12.sp,
61+
lineHeight = 15.6.sp,
6262
letterSpacing = 0.sp,
6363
)
6464
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="10dp"
3+
android:height="10dp"
4+
android:viewportWidth="10"
5+
android:viewportHeight="10">
6+
<path
7+
android:pathData="M3.937,0.76C4.273,-0.223 5.63,-0.252 6.029,0.671L6.062,0.76L6.515,2.085C6.619,2.389 6.787,2.667 7.007,2.901C7.228,3.134 7.496,3.318 7.793,3.439L7.915,3.485L9.24,3.937C10.222,4.273 10.252,5.63 9.33,6.029L9.24,6.062L7.915,6.515C7.611,6.619 7.333,6.787 7.099,7.007C6.866,7.228 6.682,7.496 6.561,7.793L6.515,7.914L6.063,9.24C5.727,10.222 4.369,10.252 3.972,9.33L3.937,9.24L3.485,7.915C3.381,7.611 3.213,7.333 2.993,7.099C2.772,6.866 2.504,6.682 2.207,6.561L2.085,6.515L0.76,6.063C-0.223,5.727 -0.252,4.369 0.671,3.972L0.76,3.937L2.085,3.485C2.389,3.381 2.667,3.213 2.901,2.993C3.134,2.772 3.318,2.504 3.439,2.207L3.485,2.085L3.937,0.76Z"
8+
android:fillColor="#FE670E"/>
9+
</vector>
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="180dp"
3+
android:height="180dp"
4+
android:viewportWidth="180"
5+
android:viewportHeight="180">
6+
<path
7+
android:pathData="M31.79,149.1V65.08C31.79,64.02 31.37,63 30.62,62.25L12.2,43.84C10.61,42.25 9.82,40.04 10.03,37.77C10.21,35.93 11.03,34.2 12.35,32.87L24.28,20.94C25.77,19.45 27.82,18.6 29.9,18.6C31.98,18.6 33.82,19.38 35.24,20.8L41.11,26.67C41.86,27.42 42.88,27.84 43.94,27.84H144.77C146.98,27.84 148.77,29.63 148.77,31.84V155.72C148.77,157.93 146.98,159.72 144.77,159.72H35.79C33.58,159.72 31.79,157.93 31.79,155.72V149.1Z"
8+
android:fillColor="#ffffff"/>
9+
<path
10+
android:pathData="M140.13,34.49H40.44C39.33,34.49 38.44,35.39 38.44,36.49V151.07C38.44,152.18 39.33,153.07 40.44,153.07H140.13C141.24,153.07 142.13,152.18 142.13,151.07V36.49C142.13,35.39 141.24,34.49 140.13,34.49Z"
11+
android:strokeWidth="2"
12+
android:fillColor="#FE670E"
13+
android:strokeColor="#030000"/>
14+
<path
15+
android:pathData="M109.52,57.72C107.56,57.05 107.5,54.33 109.34,53.54L109.52,53.47L112.17,52.57C112.78,52.36 113.34,52.02 113.8,51.58C114.27,51.14 114.64,50.6 114.88,50.01L114.97,49.77L115.88,47.12C116.55,45.15 119.26,45.09 120.06,46.94L120.13,47.12L121.03,49.77C121.24,50.37 121.57,50.93 122.02,51.4C122.46,51.86 122.99,52.23 123.59,52.47L123.83,52.57L126.48,53.47C128.45,54.14 128.51,56.86 126.66,57.65L126.48,57.72L123.83,58.63C123.22,58.83 122.67,59.17 122.2,59.61C121.73,60.05 121.36,60.59 121.12,61.18L121.03,61.42L120.13,64.07C119.46,66.04 116.74,66.1 115.94,64.25L115.88,64.07L114.97,61.42C114.76,60.82 114.43,60.26 113.99,59.79C113.54,59.33 113.01,58.96 112.42,58.72L112.17,58.63L109.52,57.72Z"
16+
android:fillColor="#ffffff"/>
17+
<path
18+
android:pathData="M54.33,65.26H98.85C99.58,65.26 100.18,64.66 100.18,63.93C100.18,63.19 99.58,62.6 98.85,62.6L54.33,62.6C53.6,62.6 53,63.19 53,63.93C53,64.66 53.6,65.26 54.33,65.26Z"
19+
android:fillColor="#ffffff"/>
20+
<path
21+
android:pathData="M54.39,84.83L126.18,84.83C126.92,84.83 127.51,84.23 127.51,83.5C127.51,82.77 126.92,82.17 126.18,82.17L54.39,82.17C53.66,82.17 53.06,82.77 53.06,83.5C53.06,84.23 53.66,84.83 54.39,84.83Z"
22+
android:fillColor="#ffffff"/>
23+
<path
24+
android:pathData="M54.39,101.78L126.18,101.78C126.92,101.78 127.51,101.19 127.51,100.45C127.51,99.72 126.92,99.12 126.18,99.12L54.39,99.12C53.66,99.12 53.06,99.72 53.06,100.45C53.06,101.19 53.66,101.78 54.39,101.78Z"
25+
android:fillColor="#ffffff"/>
26+
<path
27+
android:pathData="M54.19,136.67H125.98C126.71,136.67 127.31,136.07 127.31,135.34C127.31,134.61 126.71,134.01 125.98,134.01H54.19C53.46,134.01 52.86,134.61 52.86,135.34C52.86,136.07 53.46,136.67 54.19,136.67Z"
28+
android:fillColor="#ffffff"/>
29+
<path
30+
android:pathData="M16.9,39.14L107.4,129.64C107.48,129.72 107.59,129.78 107.69,129.82L125.18,134.6C125.68,134.73 126.13,134.28 125.99,133.78L121.21,116.3C121.18,116.18 121.13,116.08 121.04,116L30.55,25.5C30.15,25.1 29.46,25.17 28.98,25.64L17.05,37.58C16.57,38.05 16.51,38.75 16.9,39.14Z"
31+
android:strokeWidth="2"
32+
android:fillColor="#FE670E"
33+
android:strokeColor="#030000"/>
34+
<path
35+
android:pathData="M39.95,34.91L26.31,48.55L16.9,39.14C16.51,38.74 16.57,38.05 17.05,37.57L28.98,25.64C29.46,25.17 30.15,25.1 30.55,25.5L39.96,34.91H39.95Z"
36+
android:strokeWidth="2"
37+
android:fillColor="#ffffff"
38+
android:strokeColor="#030000"/>
39+
<path
40+
android:pathData="M49.75,54.1L93.28,97.63"
41+
android:strokeWidth="2"
42+
android:fillColor="#00000000"
43+
android:strokeColor="#030000"
44+
android:strokeLineCap="round"/>
45+
<path
46+
android:pathData="M120.07,116.91L108.32,128.67C107.93,129.05 108.15,129.72 108.7,129.8L117.01,132.02C117.21,132.04 117.42,131.98 117.57,131.83L123.22,126.17C123.37,126.03 123.44,125.82 123.41,125.61L121.19,117.31C121.11,116.76 120.45,116.54 120.06,116.93L120.07,116.91Z"
47+
android:strokeWidth="2"
48+
android:fillColor="#ffffff"
49+
android:strokeColor="#030000"/>
50+
<path
51+
android:pathData="M39,98.1L107,130.6L76,99.1L39,81.6V98.1Z"
52+
android:fillColor="#030000"/>
53+
</vector>

data/src/main/java/com/nexters/fooddiary/data/mapper/DiaryMapper.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class DiaryMapper @Inject constructor() {
2020
createdAt = diary.createdAt,
2121
restaurantName = diary.restaurantName,
2222
category = diary.category,
23+
note = diary.note,
2324
location = diary.roadAddress,
2425
tags = diary.tags,
2526
coverPhotoUrl = diary.coverPhotoUrl,
@@ -44,13 +45,15 @@ class DiaryMapper @Inject constructor() {
4445
DiaryMealTypeResponse.BREAKFAST -> MealType.BREAKFAST
4546
DiaryMealTypeResponse.LUNCH -> MealType.LUNCH
4647
DiaryMealTypeResponse.DINNER -> MealType.DINNER
48+
DiaryMealTypeResponse.SNACK -> MealType.SNACK
4749
}
4850
}
4951

5052
private fun DiaryAnalysisStatusResponse.toDomain(): AnalysisStatus {
5153
return when (this) {
5254
DiaryAnalysisStatusResponse.DONE -> AnalysisStatus.DONE
5355
DiaryAnalysisStatusResponse.PROCESSING -> AnalysisStatus.PROCESSING
56+
DiaryAnalysisStatusResponse.FAILED -> AnalysisStatus.FAILED
5457
}
5558
}
5659
}

data/src/main/java/com/nexters/fooddiary/data/remote/diary/model/DiaryDetailResponse.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ enum class DiaryMealTypeResponse {
5757

5858
@SerialName("dinner")
5959
DINNER,
60+
61+
@SerialName("snack")
62+
SNACK,
6063
}
6164

6265
@Serializable
@@ -66,4 +69,7 @@ enum class DiaryAnalysisStatusResponse {
6669

6770
@SerialName("processing")
6871
PROCESSING,
72+
73+
@SerialName("failed")
74+
FAILED,
6975
}

data/src/main/java/com/nexters/fooddiary/data/remote/diary/model/DiaryPhoto.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,4 @@ data class DiaryPhoto(
99
val photoId: Long,
1010
@SerialName("image_url")
1111
val imageUrl: String,
12-
@SerialName("analysis_status")
13-
val analysisStatus: DiaryAnalysisStatusResponse,
1412
)

data/src/main/java/com/nexters/fooddiary/data/repository/DiaryRepositoryImpl.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import com.nexters.fooddiary.domain.model.DiaryDetail
66
import com.nexters.fooddiary.domain.model.DiaryEntry
77
import com.nexters.fooddiary.domain.repository.DiaryRepository
88
import java.time.LocalDate
9+
import java.time.LocalDateTime
910
import java.time.YearMonth
1011
import javax.inject.Inject
1112
import javax.inject.Named
@@ -24,7 +25,7 @@ class DiaryRepositoryImpl @Inject constructor(
2425
testMode = isDebug,
2526
)
2627
val diaries = response.diaries.filter { diary ->
27-
diary.diaryDate == requestedDate
28+
LocalDateTime.parse(diary.diaryDate).toLocalDate() == date
2829
}
2930

3031
return DiaryDetail(
@@ -42,7 +43,7 @@ class DiaryRepositoryImpl @Inject constructor(
4243
testMode = isDebug,
4344
)
4445
return response.diaries
45-
.groupBy { LocalDate.parse(it.diaryDate) }
46+
.groupBy { diary -> LocalDateTime.parse(diary.diaryDate).toLocalDate() }
4647
.mapValues { (_, list) -> diaryMapper.toDomainDiaryEntries(list).first() }
4748
}
4849

0 commit comments

Comments
 (0)