Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
Expand All @@ -16,6 +18,7 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
Expand All @@ -24,6 +27,11 @@ import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import com.airbnb.lottie.compose.LottieAnimation
import com.airbnb.lottie.compose.LottieCompositionSpec
import com.airbnb.lottie.compose.LottieConstants
import com.airbnb.lottie.compose.animateLottieCompositionAsState
import com.airbnb.lottie.compose.rememberLottieComposition
import com.cherrish.android.R
import com.cherrish.android.core.common.extension.collectLatestSideEffect
import com.cherrish.android.core.common.extension.noRippleClickable
Expand Down Expand Up @@ -61,6 +69,14 @@ private fun ChallengeLoadingScreen(
onClick: () -> Unit,
modifier: Modifier = Modifier
) {
val composition by rememberLottieComposition(
LottieCompositionSpec.RawRes(R.raw.lt_challenge_loading)
)
val progress by animateLottieCompositionAsState(
composition,
iterations = LottieConstants.IterateForever,
isPlaying = true
)
Column(
modifier = modifier
.fillMaxSize()
Expand Down Expand Up @@ -106,12 +122,17 @@ private fun ChallengeLoadingScreen(
style = CherrishTheme.typography.title1SB18
)

Spacer(modifier = Modifier.height(60.dp))
Spacer(modifier = Modifier.height(80.dp))

Image(
painter = painterResource(id = R.drawable.img_challenge_loading),
contentDescription = null,
modifier = Modifier.size(150.dp)
LottieAnimation(
composition = composition,
progress = { progress },
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 105.dp)
.aspectRatio(130f / 154f)
.align(Alignment.CenterHorizontally)
.noRippleClickable(onClick = onClick)
)

Spacer(modifier = Modifier.height(80.dp))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ private fun MyPageScreen(
)

HorizontalDivider(
color = CherrishTheme.colors.gray100,
color = CherrishTheme.colors.gray200,
thickness = 10.dp
)

Expand All @@ -94,7 +94,7 @@ private fun MyPageScreen(
Spacer(Modifier.weight(weight = 120f))

HorizontalDivider(
color = CherrishTheme.colors.gray100,
color = CherrishTheme.colors.gray200,
thickness = 10.dp
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,36 @@
package com.cherrish.android.presentation.splash

import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.compose.LifecycleEventEffect
import com.airbnb.lottie.compose.LottieAnimation
import com.airbnb.lottie.compose.LottieCompositionSpec
import com.airbnb.lottie.compose.LottieConstants
import com.airbnb.lottie.compose.animateLottieCompositionAsState
import com.airbnb.lottie.compose.rememberLottieComposition
import com.cherrish.android.R
import com.cherrish.android.core.common.extension.collectLatestSideEffect
import com.cherrish.android.core.designsystem.theme.CherrishTheme
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

@Composable
fun SplashRoute(
Expand All @@ -33,20 +39,19 @@ fun SplashRoute(
paddingValues: PaddingValues,
viewModel: SplashViewModel = hiltViewModel()
) {
LaunchedEffect(Unit) {
viewModel.isAutoLoginCheck()
val scope = rememberCoroutineScope()

LifecycleEventEffect(Lifecycle.Event.ON_START) {
scope.launch {
delay(3000)
viewModel.isAutoLoginCheck()
}
Comment on lines +42 to +48
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n app/src/main/java/com/cherrish/android/presentation/splash/SplashScreen.kt

Repository: TEAM-Cherrish/Cherrish-Android

Length of output: 4725


🏁 Script executed:

# SplashViewModel과 isAutoLoginCheck() 메서드 확인하여 
# 중복 호출 시 부작용 검증
fd -e kt -path "*presentation/splash*" | head -20

Repository: TEAM-Cherrish/Cherrish-Android

Length of output: 242


🏁 Script executed:

find . -name "SplashViewModel.kt" -type f

Repository: TEAM-Cherrish/Cherrish-Android

Length of output: 153


🏁 Script executed:

cat -n ./app/src/main/java/com/cherrish/android/presentation/splash/SplashViewModel.kt

Repository: TEAM-Cherrish/Cherrish-Android

Length of output: 1412


ON_START 반복 호출로 인한 지연 작업 중복 실행 위험

액티비티가 백그라운드/포그라운드를 전환할 때마다 ON_START 이벤트가 발생하므로, LifecycleEventEffect 블록이 반복 실행됩니다. 이 과정에서 scope.launch로 생성한 지연 코루틴이 누적되어 isAutoLoginCheck()가 중복 호출될 수 있으며, 이는 중복된 side effect 발생 및 반복 네비게이션으로 이어집니다.

단일 실행을 보장하려면 LaunchedEffect(Unit)으로 변경하세요. 컴포지션 생성 시에만 1회 실행되므로 ON_START 반복 호출과 무관하게 3초 후 자동 로그인 확인이 정확히 1회만 실행됩니다.

🔧 수정 예시
-import androidx.compose.runtime.rememberCoroutineScope
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.compose.LifecycleEventEffect
+import androidx.compose.runtime.LaunchedEffect
 
-    val scope = rememberCoroutineScope()
-
-    LifecycleEventEffect(Lifecycle.Event.ON_START) {
-        scope.launch {
-            delay(3000)
-            viewModel.isAutoLoginCheck()
-        }
-    }
+    LaunchedEffect(Unit) {
+        delay(3000)
+        viewModel.isAutoLoginCheck()
+    }
🤖 Prompt for AI Agents
In `@app/src/main/java/com/cherrish/android/presentation/splash/SplashScreen.kt`
around lines 42 - 48, The current use of LifecycleEventEffect with scope.launch
causes the delay coroutine to run every ON_START and can duplicate calls to
viewModel.isAutoLoginCheck(); replace the LifecycleEventEffect +
rememberCoroutineScope+/scope.launch pattern with a single LaunchedEffect(Unit)
that performs delay(3000) and then calls viewModel.isAutoLoginCheck(), and
remove the now-unused rememberCoroutineScope() to ensure the auto-login check
runs exactly once after composition.

}

viewModel.sideEffect.collectLatestSideEffect { sideEffect ->
delay(3000)

when (sideEffect) {
SplashSideEffect.NavigateToOnboarding -> {
navigateToOnboarding()
}
SplashSideEffect.NavigateToHome -> {
navigateToHome()
}
SplashSideEffect.NavigateToOnboarding -> navigateToOnboarding()
SplashSideEffect.NavigateToHome -> navigateToHome()
}
}

Expand All @@ -60,6 +65,15 @@ private fun SplashScreen(
paddingValues: PaddingValues,
modifier: Modifier = Modifier
) {
val composition by rememberLottieComposition(
LottieCompositionSpec.RawRes(R.raw.lt_challenge_loading)
)
val progress by animateLottieCompositionAsState(
composition,
iterations = LottieConstants.IterateForever,
isPlaying = true
)

val gradationColors = listOf(CherrishTheme.colors.gradation, CherrishTheme.colors.gradation2)

Column(
Expand All @@ -77,19 +91,18 @@ private fun SplashScreen(
) {
Spacer(modifier = Modifier.weight(283f))

Image(
painter = painterResource(id = R.drawable.ic_app_logo),
contentDescription = null,
modifier = Modifier.size(width = 114.dp, height = 100.dp)
LottieAnimation(
composition = composition,
progress = { progress },
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 105.dp)
.aspectRatio(130f / 154f)
.align(Alignment.CenterHorizontally)
)

Spacer(modifier = Modifier.height(14.dp))

Image(
imageVector = ImageVector.vectorResource(id = R.drawable.ic_app_logo_title),
contentDescription = null
)

Spacer(modifier = Modifier.weight(298f))
}
}
Expand Down
Loading
Loading