From 54a9d1afa15daa092c3f96e7c96acd70a4751236 Mon Sep 17 00:00:00 2001 From: Yu Jin Date: Tue, 3 Mar 2026 11:01:19 +0900 Subject: [PATCH 1/4] fix(review): Handle null or invalid MenuType gracefully in ReviewComposeActivity to prevent crashes --- .../cafeteria/review/ReviewComposeActivity.kt | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/ReviewComposeActivity.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/ReviewComposeActivity.kt index 23f8eb9fd..eed5a5be9 100644 --- a/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/ReviewComposeActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/ReviewComposeActivity.kt @@ -4,6 +4,7 @@ import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.navigation.compose.rememberNavController +import com.eatssu.android.presentation.cafeteria.review.ReviewNav import com.eatssu.common.enums.MenuType import com.eatssu.design_system.theme.EatssuTheme import dagger.hilt.android.AndroidEntryPoint @@ -13,7 +14,7 @@ import kotlin.properties.Delegates @AndroidEntryPoint class ReviewComposeActivity : ComponentActivity() { - private lateinit var menuType: String + private var menuType: String? = null private var itemId by Delegates.notNull() private lateinit var itemName: String @@ -23,20 +24,29 @@ class ReviewComposeActivity : ComponentActivity() { EatssuTheme { val navHostController = rememberNavController() - ReviewNav( - navHostController = navHostController, - menuType = MenuType.valueOf(menuType), - menuName = itemName, - id = itemId, - onExit = { finish() } - ) + val parsedMenuType = runCatching { + if (menuType.isNullOrBlank()) null else MenuType.valueOf(menuType!!) + }.getOrNull() + + parsedMenuType?.let { type -> + ReviewNav( + navHostController = navHostController, + menuType = type, + menuName = itemName, + id = itemId, + onExit = { finish() } + ) + } ?: run { + Timber.e("Invalid or null MenuType received: \$menuType") + finish() + } } } getIntents() } private fun getIntents() { //todo 추후 변경 - menuType = intent.getStringExtra("menuType").toString() + menuType = intent.getStringExtra("menuType") itemId = intent.getLongExtra("itemId", 0) itemName = intent.getStringExtra("itemName").toString().replace(Regex("[\\[\\]]"), "") From e2c9e695a173f25dfe20ff3813f8d0cc253836da Mon Sep 17 00:00:00 2001 From: Yu Jin Date: Tue, 3 Mar 2026 11:32:45 +0900 Subject: [PATCH 2/4] feat(review): Add ErrorScreen with Preview and Crashlytics logging for MenuType parsing failure --- .../cafeteria/review/ReviewComposeActivity.kt | 48 ++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/ReviewComposeActivity.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/ReviewComposeActivity.kt index eed5a5be9..a9775ea0f 100644 --- a/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/ReviewComposeActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/ReviewComposeActivity.kt @@ -3,9 +3,20 @@ package com.eatssu.android.presentation.cafeteria.review import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent +import androidx.compose.foundation.layout.* +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp import androidx.navigation.compose.rememberNavController import com.eatssu.android.presentation.cafeteria.review.ReviewNav import com.eatssu.common.enums.MenuType +import com.google.firebase.crashlytics.FirebaseCrashlytics import com.eatssu.design_system.theme.EatssuTheme import dagger.hilt.android.AndroidEntryPoint import timber.log.Timber @@ -26,6 +37,11 @@ class ReviewComposeActivity : ComponentActivity() { val parsedMenuType = runCatching { if (menuType.isNullOrBlank()) null else MenuType.valueOf(menuType!!) + }.onFailure { exception -> + Timber.e(exception, "Failed to parse MenuType: \$menuType") + FirebaseCrashlytics.getInstance().recordException( + IllegalArgumentException("Invalid MenuType '\$menuType' for itemId \$itemId. Original exception: \${exception.message}", exception) + ) }.getOrNull() parsedMenuType?.let { type -> @@ -38,7 +54,9 @@ class ReviewComposeActivity : ComponentActivity() { ) } ?: run { Timber.e("Invalid or null MenuType received: \$menuType") - finish() + ErrorScreen( + onBackClick = { finish() } + ) } } } @@ -52,4 +70,32 @@ class ReviewComposeActivity : ComponentActivity() { Timber.d("메뉴는 $itemName $menuType $itemId") } + + @Composable + private fun ErrorScreen(onBackClick: () -> Unit) { + Column( + modifier = Modifier.fillMaxSize().padding(16.dp), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = "메뉴 정보를 불러오는데 실패했습니다.\n다시 시도해주세요.", + textAlign = TextAlign.Center, + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurface + ) + Spacer(modifier = Modifier.height(16.dp)) + Button(onClick = onBackClick) { + Text(text = "뒤로가기") + } + } + } + + @Preview(showBackground = true) + @Composable + private fun ErrorScreenPreview() { + EatssuTheme { + ErrorScreen(onBackClick = {}) + } + } } \ No newline at end of file From 9d07eda1d7a85e333e8d2761c35805ce65ae9529 Mon Sep 17 00:00:00 2001 From: Yu Jin Date: Tue, 3 Mar 2026 11:50:49 +0900 Subject: [PATCH 3/4] fix(review): Move getIntents() before setContent to prevent null MenuType during initial Compose rendering --- .../cafeteria/review/ReviewComposeActivity.kt | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/ReviewComposeActivity.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/ReviewComposeActivity.kt index a9775ea0f..015281dde 100644 --- a/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/ReviewComposeActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/ReviewComposeActivity.kt @@ -3,21 +3,25 @@ package com.eatssu.android.presentation.cafeteria.review import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent -import androidx.compose.foundation.layout.* -import androidx.compose.material3.* +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Button +import androidx.compose.material3.MaterialTheme +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.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.navigation.compose.rememberNavController -import com.eatssu.android.presentation.cafeteria.review.ReviewNav import com.eatssu.common.enums.MenuType -import com.google.firebase.crashlytics.FirebaseCrashlytics import com.eatssu.design_system.theme.EatssuTheme +import com.google.firebase.crashlytics.FirebaseCrashlytics import dagger.hilt.android.AndroidEntryPoint import timber.log.Timber import kotlin.properties.Delegates @@ -31,6 +35,8 @@ class ReviewComposeActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + getIntents() // 컴포즈 화면 그리기 전에 호출 + setContent { EatssuTheme { val navHostController = rememberNavController() @@ -60,7 +66,6 @@ class ReviewComposeActivity : ComponentActivity() { } } } - getIntents() } private fun getIntents() { //todo 추후 변경 From 602064f8be5c8aee039e2891fd55e08dfbfd1146 Mon Sep 17 00:00:00 2001 From: PeraSite Date: Tue, 3 Mar 2026 14:51:45 +0900 Subject: [PATCH 4/4] =?UTF-8?q?refactor:=20enum=20=EA=B3=84=EC=82=B0=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cafeteria/review/ReviewComposeActivity.kt | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/ReviewComposeActivity.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/ReviewComposeActivity.kt index 015281dde..30ceb6a2a 100644 --- a/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/ReviewComposeActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/ReviewComposeActivity.kt @@ -40,15 +40,7 @@ class ReviewComposeActivity : ComponentActivity() { setContent { EatssuTheme { val navHostController = rememberNavController() - - val parsedMenuType = runCatching { - if (menuType.isNullOrBlank()) null else MenuType.valueOf(menuType!!) - }.onFailure { exception -> - Timber.e(exception, "Failed to parse MenuType: \$menuType") - FirebaseCrashlytics.getInstance().recordException( - IllegalArgumentException("Invalid MenuType '\$menuType' for itemId \$itemId. Original exception: \${exception.message}", exception) - ) - }.getOrNull() + val parsedMenuType = MenuType.entries.find { it.name == menuType } parsedMenuType?.let { type -> ReviewNav( @@ -59,7 +51,7 @@ class ReviewComposeActivity : ComponentActivity() { onExit = { finish() } ) } ?: run { - Timber.e("Invalid or null MenuType received: \$menuType") + Timber.e("Invalid or null MenuType received: $menuType") ErrorScreen( onBackClick = { finish() } )