Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 @@ -17,6 +17,7 @@ import com.ruleup.ui.error.userFacingMessage
import com.ruleup.ui.mvi.MviViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import java.time.LocalDate
import java.time.OffsetDateTime
Expand Down Expand Up @@ -113,10 +114,13 @@ class ProfileEditViewModel
dispatch(ProfileEditReducerEvent.Loading)
viewModelScope.launch {
runCatching {
val profileDeferred = async { profileRepository.getProfile() }
// 마스터 조회 실패는 기본 상한(6)으로 흡수한다.
val catalogDeferred = async { runCatching { profileRepository.getCategories() }.getOrNull() }
profileDeferred.await() to catalogDeferred.await()
// coroutineScope 없이 launch 에 바로 async 를 걸면 getProfile 실패가 launch 까지 무너뜨려 크래시한다.
coroutineScope {
val profileDeferred = async { profileRepository.getProfile() }
// 마스터 조회 실패는 기본 상한(6)으로 흡수한다.
val catalogDeferred = async { runCatching { profileRepository.getCategories() }.getOrNull() }
profileDeferred.await() to catalogDeferred.await()
}
}.onSuccess { (profile, catalog) ->
dispatch(
ProfileEditReducerEvent.Loaded(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,20 +93,20 @@ class SettingsViewModel

private fun load() {
viewModelScope.launch {
// 넷은 서로 독립이라 함께 던진다.
val loaded =
// 다섯은 서로 독립이라 함께 던진다.
val (loaded, seenAnswers) =
coroutineScope {
val a = async { runCatching { accountRepository.getAgreements() }.getOrNull() }
val s = async { runCatching { accountRepository.getSanctions() }.getOrNull() }
val p = async { runCatching { profileRepository.getMyProfile() }.getOrNull() }
val i = async { runCatching { inquiryRepository.getInquiries() }.getOrNull() }
SettingsLoad(a.await(), s.await(), p.await(), i.await())
val seen = async { runCatching { inquiryReadStore.seenAnswers() }.getOrDefault(emptyMap()) }
SettingsLoad(a.await(), s.await(), p.await(), i.await()) to seen.await()
}
if (loaded.isEmpty) {
dispatch(SettingsReducerEvent.LoadFinished)
return@launch
}
val seenAnswers = runCatching { inquiryReadStore.seenAnswers() }.getOrDefault(emptyMap())
dispatch(
SettingsReducerEvent.Loaded(
provider =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import com.ruleup.profile.domain.repository.MyPageRepository
import com.ruleup.ui.mvi.MviViewModel
import com.ruleup.ui.mvi.NoEffect
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import javax.inject.Inject

Expand Down Expand Up @@ -66,8 +68,12 @@ class MyTierHistoryViewModel
if (currentState.history != null || currentState.changes.isNotEmpty()) return
dispatch(MyTierHistoryReducerEvent.Loading)
viewModelScope.launch {
val history = runCatching { myPageRepository.getTierHistory() }.getOrNull()
val changes = runCatching { myPageRepository.getScoreChanges() }
val (history, changes) =
coroutineScope {
val history = async { runCatching { myPageRepository.getTierHistory() }.getOrNull() }
val changes = async { runCatching { myPageRepository.getScoreChanges() } }
history.await() to changes.await()
}

changes
.onSuccess { dispatch(loaded(history, it)) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import kotlin.test.AfterTest
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNotNull
import kotlin.test.assertTrue

/** 프로필 편집. */
Expand Down Expand Up @@ -54,6 +56,17 @@ class ProfileEditViewModelTest {
assertTrue(viewModel.uiState.value.maxSelectable > 0)
}

@Test
fun `프로필 조회가 실패하면 크래시 없이 오류를 보여준다`() =
runTest {
val viewModel = viewModel(repo(loadProfile = { throw IllegalStateException("서버 오류") }))

viewModel.onIntent(ProfileEditIntent.Load)

assertNotNull(viewModel.uiState.value.errorMessage)
assertFalse(viewModel.uiState.value.isLoading)
}

@Test
fun `바꾼 게 없으면 저장하지 않는다`() =
runTest {
Expand Down Expand Up @@ -350,14 +363,15 @@ class ProfileEditViewModelTest {
}

private fun repo(
loadProfile: (() -> Profile)? = null,
categories: (() -> com.ruleup.profile.domain.entity.CategoryCatalog)? = { catalog() },
checkNickname: ((String) -> NicknameCheck)? = { NicknameCheck(valid = true, available = true, reason = null) },
updateProfile: (() -> Profile)? = { profile() },
imageUrl: String? = null,
uploadImage: ((String) -> String)? = { "https://example.com/new.jpg" },
deleteImage: () -> Unit = {},
) = FakeProfileRepository(
profile = { profile().let { it.copy(user = it.user.copy(profileImageUrl = imageUrl)) } },
profile = loadProfile ?: { profile().let { it.copy(user = it.user.copy(profileImageUrl = imageUrl)) } },
categories = categories,
checkNickname = checkNickname,
updateProfile = updateProfile,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import com.ruleup.support.domain.repository.InquiryRepository
import com.ruleup.ui.mvi.MviViewModel
import com.ruleup.ui.mvi.NoEffect
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import javax.inject.Inject

Expand Down Expand Up @@ -51,12 +53,15 @@ class InquiryListViewModel
private fun load() {
dispatch(InquiryListReducerEvent.Loading)
viewModelScope.launch {
runCatching { inquiryRepository.getInquiries() }
.onSuccess { items ->
runCatching {
coroutineScope {
// 기록을 못 읽으면 전부 새 답변으로 보인다. 목록을 막을 일은 아니다
val seen = runCatching { inquiryReadStore.seenAnswers() }.getOrDefault(emptyMap())
dispatch(InquiryListReducerEvent.Loaded(items, seen))
}.onFailure { dispatch(InquiryListReducerEvent.Failed(it.userMessage())) }
val seen = async { runCatching { inquiryReadStore.seenAnswers() }.getOrDefault(emptyMap()) }
inquiryRepository.getInquiries() to seen.await()
}
}.onSuccess { (items, seen) ->
dispatch(InquiryListReducerEvent.Loaded(items, seen))
}.onFailure { dispatch(InquiryListReducerEvent.Failed(it.userMessage())) }
}
}
}
Expand Down
Loading