@@ -8,7 +8,9 @@ import androidx.compose.runtime.mutableStateOf
88import androidx.compose.runtime.rememberCoroutineScope
99import androidx.compose.runtime.setValue
1010import com.ninecraft.booket.core.common.constants.BookStatus
11+ import com.ninecraft.booket.core.common.constants.ErrorScope
1112import com.ninecraft.booket.core.common.utils.handleException
13+ import com.ninecraft.booket.core.common.utils.postErrorDialog
1214import com.ninecraft.booket.core.data.api.repository.BookRepository
1315import com.ninecraft.booket.core.data.api.repository.RecordRepository
1416import com.ninecraft.booket.core.model.BookDetailModel
@@ -32,6 +34,9 @@ import kotlinx.collections.immutable.ImmutableList
3234import kotlinx.collections.immutable.persistentListOf
3335import kotlinx.collections.immutable.toImmutableList
3436import kotlinx.collections.immutable.toPersistentList
37+ import kotlinx.coroutines.CancellationException
38+ import kotlinx.coroutines.async
39+ import kotlinx.coroutines.coroutineScope
3540import kotlinx.coroutines.launch
3641import java.time.LocalDateTime
3742
@@ -69,50 +74,48 @@ class BookDetailPresenter @AssistedInject constructor(
6974 var isRecordSortBottomSheetVisible by rememberRetained { mutableStateOf(false ) }
7075 var sideEffect by rememberRetained { mutableStateOf<BookDetailSideEffect ?>(null ) }
7176
72- fun getSeedsStats () {
73- scope.launch {
74- bookRepository.getSeedsStats(screen.userBookId)
75- .onSuccess { result ->
76- seedsStates = result.categories.toImmutableList()
77- }
78- .onFailure { exception ->
79- val handleErrorMessage = { message: String ->
80- Logger .e(message)
81- sideEffect = BookDetailSideEffect .ShowToast (message)
82- }
77+ suspend fun initialLoad () {
78+ uiState = UiState .Loading
8379
84- handleException(
85- exception = exception,
86- onError = handleErrorMessage,
87- onLoginRequired = {
88- navigator.resetRoot(LoginScreen )
89- },
90- )
80+ try {
81+ coroutineScope {
82+ val bookDetailDef = async { bookRepository.getBookDetail(screen.isbn13).getOrThrow() }
83+ val seedsDef = async { bookRepository.getSeedsStats(screen.userBookId).getOrThrow() }
84+ val readingRecordsDef = async {
85+ recordRepository.getReadingRecords(
86+ userBookId = screen.userBookId,
87+ sort = currentRecordSort.value,
88+ page = START_INDEX ,
89+ size = PAGE_SIZE ,
90+ ).getOrThrow()
9191 }
92- }
93- }
92+ val detail = bookDetailDef.await()
93+ val seeds = seedsDef.await()
94+ val records = readingRecordsDef.await()
9495
95- fun getBookDetail () {
96- scope.launch {
97- bookRepository.getBookDetail(screen.isbn13)
98- .onSuccess { result ->
99- bookDetail = result
100- currentBookStatus = BookStatus .fromValue(result.userBookStatus) ? : BookStatus .BEFORE_READING
101- }
102- .onFailure { exception ->
103- val handleErrorMessage = { message: String ->
104- Logger .e(message)
105- sideEffect = BookDetailSideEffect .ShowToast (message)
106- }
96+ bookDetail = detail
97+ seedsStates = seeds.categories.toImmutableList()
98+ readingRecords = records.content.toPersistentList()
10799
108- handleException(
109- exception = exception,
110- onError = handleErrorMessage,
111- onLoginRequired = {
112- navigator.resetRoot(LoginScreen )
113- },
114- )
115- }
100+ uiState = UiState .Success
101+ }
102+ } catch (ce: CancellationException ) {
103+ throw ce
104+ } catch (e: Throwable ) {
105+ uiState = UiState .Error (e)
106+
107+ val handleErrorMessage = { message: String ->
108+ Logger .e(message)
109+ sideEffect = BookDetailSideEffect .ShowToast (message)
110+ }
111+
112+ handleException(
113+ exception = e,
114+ onError = handleErrorMessage,
115+ onLoginRequired = {
116+ navigator.resetRoot(LoginScreen )
117+ },
118+ )
116119 }
117120 }
118121
@@ -125,6 +128,11 @@ class BookDetailPresenter @AssistedInject constructor(
125128 isBookUpdateBottomSheetVisible = false
126129 }
127130 .onFailure { exception ->
131+ postErrorDialog(
132+ errorScope = ErrorScope .BOOK_REGISTER ,
133+ exception = exception,
134+ )
135+
128136 val handleErrorMessage = { message: String ->
129137 Logger .e(message)
130138 sideEffect = BookDetailSideEffect .ShowToast (message)
@@ -141,50 +149,35 @@ class BookDetailPresenter @AssistedInject constructor(
141149 }
142150 }
143151
144- fun getReadingRecords (startIndex : Int = START_INDEX ) {
152+ fun loadMoreReadingRecords (startIndex : Int ) {
153+ // 초기 페이지 로드는 initialLoad()에서 담당하므로 무시
154+ if (startIndex == START_INDEX || isLastPage) {
155+ return
156+ }
157+
145158 scope.launch {
146- if (startIndex == START_INDEX ) {
147- uiState = UiState .Loading
148- } else {
149- footerState = FooterState .Loading
150- }
159+ footerState = FooterState .Loading
151160
152161 recordRepository.getReadingRecords(
153162 userBookId = screen.userBookId,
154163 sort = currentRecordSort.value,
155164 page = startIndex,
156165 size = PAGE_SIZE ,
157166 ).onSuccess { result ->
158- readingRecords = if (startIndex == START_INDEX ) {
159- result.content.toPersistentList()
160- } else {
161- (readingRecords + result.content).toPersistentList()
162- }
163-
167+ readingRecords = (readingRecords + result.content).toPersistentList()
164168 currentStartIndex = startIndex
165169 isLastPage = result.content.size < PAGE_SIZE
166-
167- if (startIndex == START_INDEX ) {
168- uiState = UiState .Success
169- } else {
170- footerState = if (isLastPage) FooterState .End else FooterState .Idle
171- }
170+ footerState = if (isLastPage) FooterState .End else FooterState .Idle
172171 }.onFailure { exception ->
173172 Logger .d(exception)
174173 val errorMessage = exception.message ? : " 알 수 없는 오류가 발생했습니다."
175- if (startIndex == START_INDEX ) {
176- uiState = UiState .Error (errorMessage)
177- } else {
178- footerState = FooterState .Error (errorMessage)
179- }
174+ footerState = FooterState .Error (errorMessage)
180175 }
181176 }
182177 }
183178
184179 LaunchedEffect (Unit ) {
185- getSeedsStats()
186- getBookDetail()
187- getReadingRecords()
180+ initialLoad()
188181 }
189182
190183 fun handleEvent (event : BookDetailUiEvent ) {
@@ -237,7 +230,13 @@ class BookDetailPresenter @AssistedInject constructor(
237230
238231 is BookDetailUiEvent .OnLoadMore -> {
239232 if (uiState != UiState .Loading && footerState !is FooterState .Loading && ! isLastPage) {
240- getReadingRecords(startIndex = currentStartIndex + 1 )
233+ loadMoreReadingRecords(startIndex = currentStartIndex + 1 )
234+ }
235+ }
236+
237+ is BookDetailUiEvent .OnRetryClick -> {
238+ scope.launch {
239+ initialLoad()
241240 }
242241 }
243242 }
0 commit comments