Skip to content

Commit b881fb0

Browse files
authored
[Fix] 오프라인 진입 제어 + 로그인 프로세스 수정 (#217)
1 parent 3c2b1d0 commit b881fb0

7 files changed

Lines changed: 39 additions & 81 deletions

File tree

app/src/main/java/com/pomonyang/mohanyang/MainActivity.kt

Lines changed: 25 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import androidx.compose.ui.Modifier
2020
import androidx.compose.ui.platform.LocalContext
2121
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
2222
import androidx.lifecycle.compose.collectAsStateWithLifecycle
23-
import androidx.lifecycle.lifecycleScope
2423
import androidx.localbroadcastmanager.content.LocalBroadcastManager
2524
import androidx.navigation.compose.rememberNavController
2625
import androidx.startup.AppInitializer
@@ -41,7 +40,6 @@ import com.pomonyang.mohanyang.presentation.util.MnNotificationManager
4140
import com.pomonyang.mohanyang.presentation.util.MohanyangEventLogger
4241
import com.pomonyang.mohanyang.presentation.util.collectWithLifecycle
4342
import com.pomonyang.mohanyang.ui.MohaNyangApp
44-
import com.pomonyang.mohanyang.ui.MohaNyangAppState
4543
import com.pomonyang.mohanyang.ui.rememberMohaNyangAppState
4644
import dagger.hilt.android.AndroidEntryPoint
4745
import javax.inject.Inject
@@ -64,33 +62,19 @@ class MainActivity : ComponentActivity() {
6462

6563
private var keepSplashOnScreen = true
6664

65+
private var splashTime = 0L
66+
6767
override fun onCreate(savedInstanceState: Bundle?) {
6868
handleSplashScreen()
6969
super.onCreate(savedInstanceState)
70-
70+
viewModel.handleEvent(MainEvent.Init)
7171
configureAppStartup()
7272

7373
setContent {
7474
val activity = (LocalContext.current as? Activity)
75-
7675
val state by viewModel.state.collectAsStateWithLifecycle()
77-
val coroutineScope = rememberCoroutineScope()
78-
79-
val mohaNyangAppState = rememberMohaNyangAppState(
80-
isNewUser = viewModel.checkIfNewUser(),
81-
networkMonitor = networkMonitor,
82-
coroutineScope = coroutineScope,
83-
navHostController = rememberNavController().apply {
84-
NavigationViewTrackingEffect(navController = this)
85-
},
86-
)
87-
8876
var showDialog by remember { mutableStateOf(false) }
8977

90-
LaunchedEffect(Unit) {
91-
viewModel.handleEvent(MainEvent.Init)
92-
}
93-
9478
viewModel.effects.collectWithLifecycle { effect ->
9579
when (effect) {
9680
MainEffect.ShowDialog -> {
@@ -125,7 +109,6 @@ class MainActivity : ComponentActivity() {
125109
AppScreen(
126110
modifier = Modifier,
127111
viewState = state,
128-
mohaNyangAppState = mohaNyangAppState,
129112
eventLogger = eventLogger,
130113
)
131114
}
@@ -137,9 +120,19 @@ class MainActivity : ComponentActivity() {
137120
fun AppScreen(
138121
modifier: Modifier,
139122
viewState: MainState,
140-
mohaNyangAppState: MohaNyangAppState,
141123
eventLogger: MohanyangEventLogger,
142124
) {
125+
LaunchedEffect(viewState.isDataFetched) {
126+
if (viewState.isDataFetched) {
127+
val loadDuration = System.currentTimeMillis() - splashTime
128+
val loadRemainTime = (SPLASH_DELAY - loadDuration).coerceAtLeast(0)
129+
if (loadRemainTime > 0) {
130+
delay(loadRemainTime)
131+
}
132+
keepSplashOnScreen = false
133+
}
134+
}
135+
143136
when {
144137
viewState.isInternalError -> ServerErrorScreen(onClickNavigateToHome = { })
145138
viewState.isInvalidError ->
@@ -149,11 +142,17 @@ class MainActivity : ComponentActivity() {
149142
)
150143

151144
viewState.isLoading -> LoadingScreen(modifier = modifier)
152-
else -> {
153-
MohaNyangApp(
154-
mohaNyangAppState = mohaNyangAppState,
155-
logger = eventLogger,
145+
viewState.isDataFetched -> {
146+
val coroutineScope = rememberCoroutineScope()
147+
val mohaNyangAppState = rememberMohaNyangAppState(
148+
isNewUser = viewState.isNewUser!!,
149+
networkMonitor = networkMonitor,
150+
coroutineScope = coroutineScope,
151+
navHostController = rememberNavController().apply {
152+
NavigationViewTrackingEffect(navController = this)
153+
},
156154
)
155+
MohaNyangApp(mohaNyangAppState = mohaNyangAppState, logger = eventLogger)
157156
}
158157
}
159158
}
@@ -178,11 +177,8 @@ class MainActivity : ComponentActivity() {
178177
}
179178

180179
private fun handleSplashScreen() {
180+
splashTime = System.currentTimeMillis()
181181
installSplashScreen().setKeepOnScreenCondition { keepSplashOnScreen }
182-
lifecycleScope.launch {
183-
delay(SPLASH_DELAY)
184-
keepSplashOnScreen = false
185-
}
186182
}
187183

188184
override fun onResume() {

app/src/main/java/com/pomonyang/mohanyang/MainElements.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ data class MainState(
99
override val isInternalError: Boolean = false,
1010
override val isInvalidError: Boolean = false,
1111
override val lastRequestAction: MainEvent? = null,
12-
) : NetworkViewState()
12+
val isNewUser: Boolean? = null,
13+
) : NetworkViewState() {
14+
val isDataFetched = isLoading.not() && isNewUser != null
15+
}
1316

1417
sealed interface MainEvent : ViewEvent {
1518
data object Init : MainEvent

app/src/main/java/com/pomonyang/mohanyang/MainViewModel.kt

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,14 +97,16 @@ class MainViewModel @Inject constructor(
9797
private fun onOnline() = scope.launch {
9898
fetchFcmToken()
9999
fetchUserInfo().onSuccess {
100-
setupUserAndNavigate(it.isNewUser())
100+
val isNewUser = it.isNewUser()
101+
updateState { copy(isNewUser = isNewUser) }
102+
setupUserAndNavigate(isNewUser)
101103
}.getOrThrow()
102104
}
103105

104106
// 오프라인 상태일 때 실행할 초기화 로직
105107
private fun onOffline() = scope.launch {
106-
val isNewUser = checkIfNewUser()
107-
setupUserAndNavigate(isNewUser)
108+
pomodoroTimerRepository.savePomodoroCacheData()
109+
setEffect(MainEffect.ShowDialog)
108110
}
109111

110112
private suspend fun setupUserAndNavigate(isNewUser: Boolean) {
@@ -116,8 +118,6 @@ class MainViewModel @Inject constructor(
116118
}
117119
}
118120

119-
fun checkIfNewUser() = userRepository.isNewUser()
120-
121121
private suspend fun fetchUserInfo(): Result<UserInfoResponse> = runCatching {
122122
getTokenByDeviceIdUseCase().getOrThrow()
123123
val userInfo = userRepository.fetchMyInfo().getOrThrow()
@@ -129,8 +129,10 @@ class MainViewModel @Inject constructor(
129129
if (!networkMonitor.isConnected) return
130130
scope.launch {
131131
val userInfo = fetchUserInfo().getOrThrow()
132+
val isNewUser = userInfo.isNewUser()
133+
updateState { copy(isNewUser = isNewUser) }
134+
setupUserAndNavigate(isNewUser)
132135
setEffect(MainEffect.DismissDialog)
133-
setupUserAndNavigate(userInfo.isNewUser())
134136
}
135137
}
136138

data/src/main/java/com/pomonyang/mohanyang/data/repository/user/UserRepository.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import java.time.LocalDate
66

77
interface UserRepository {
88
suspend fun getDeviceId(): String
9-
fun isNewUser(): Boolean
109
suspend fun login(deviceId: String): Result<TokenResponse>
1110
suspend fun saveToken(accessToken: String, refreshToken: String)
1211
suspend fun fetchMyInfo(): Result<UserInfoResponse>

data/src/main/java/com/pomonyang/mohanyang/data/repository/user/UserRepositoryImpl.kt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import java.time.LocalDate
1111
import java.time.LocalDateTime
1212
import java.time.ZonedDateTime
1313
import javax.inject.Inject
14-
import kotlinx.coroutines.runBlocking
1514

1615
internal class UserRepositoryImpl @Inject constructor(
1716
private val deviceLocalDataStore: DeviceIdLocalDataSource,
@@ -22,8 +21,6 @@ internal class UserRepositoryImpl @Inject constructor(
2221
) : UserRepository {
2322
override suspend fun getDeviceId() = deviceLocalDataStore.getDeviceId()
2423

25-
override fun isNewUser(): Boolean = runBlocking { tokenLocalDataSource.getAccessToken().isEmpty() || userLocalDataSource.getUserInfo().isNewUser() }
26-
2724
override suspend fun login(deviceId: String) = authService.getTokenByDeviceId(TokenRequest(deviceId))
2825

2926
override suspend fun saveToken(accessToken: String, refreshToken: String) {

presentation/src/main/java/com/pomonyang/mohanyang/presentation/screen/onboarding/guide/OnboardingGuideScreen.kt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,6 @@ internal fun OnboardingGuideRoute(
5252
modifier: Modifier = Modifier,
5353
onboardingViewModel: OnboardingGuideViewModel = hiltViewModel(),
5454
) {
55-
LaunchedEffect(Unit) {
56-
onboardingViewModel.handleEvent(OnboardingGuideEvent.Init)
57-
}
58-
5955
OnboardingGuideScreen(
6056
modifier = modifier,
6157
onHomeClick = onStartClick,
Lines changed: 2 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,14 @@
11
package com.pomonyang.mohanyang.presentation.screen.onboarding.guide
22

3-
import androidx.lifecycle.viewModelScope
43
import com.pomonyang.mohanyang.data.repository.user.UserRepository
54
import com.pomonyang.mohanyang.presentation.base.BaseViewModel
65
import com.pomonyang.mohanyang.presentation.base.ViewEvent
76
import com.pomonyang.mohanyang.presentation.base.ViewSideEffect
87
import com.pomonyang.mohanyang.presentation.base.ViewState
98
import dagger.hilt.android.lifecycle.HiltViewModel
109
import javax.inject.Inject
11-
import kotlinx.coroutines.launch
12-
import timber.log.Timber
1310

14-
sealed class OnboardingGuideSideEffect : ViewSideEffect {
15-
data object NavigateToHome : OnboardingGuideSideEffect()
16-
}
11+
sealed class OnboardingGuideSideEffect : ViewSideEffect
1712

1813
sealed class OnboardingGuideEvent : ViewEvent {
1914
data object Init : OnboardingGuideEvent()
@@ -28,35 +23,5 @@ class OnboardingGuideViewModel @Inject constructor(
2823

2924
override fun setInitialState(): OnboardingGuideUiState = OnboardingGuideUiState(isNewUser = true)
3025

31-
override fun handleEvent(event: OnboardingGuideEvent) {
32-
when (event) {
33-
is OnboardingGuideEvent.Init -> {
34-
login()
35-
}
36-
}
37-
}
38-
39-
private fun login() {
40-
viewModelScope.launch {
41-
if (userRepository.isNewUser()) {
42-
getTokenByDeviceId()
43-
}
44-
45-
setEffect(OnboardingGuideSideEffect.NavigateToHome)
46-
}
47-
}
48-
49-
private suspend fun getTokenByDeviceId() {
50-
val deviceId = userRepository.getDeviceId()
51-
if (deviceId.isNotEmpty()) {
52-
userRepository.login(deviceId).onSuccess {
53-
userRepository.saveToken(
54-
accessToken = it.accessToken,
55-
refreshToken = it.refreshToken,
56-
)
57-
}.onFailure {
58-
Timber.e("token fail: $it")
59-
}
60-
}
61-
}
26+
override fun handleEvent(event: OnboardingGuideEvent) {}
6227
}

0 commit comments

Comments
 (0)