@@ -20,7 +20,9 @@ import com.ninecraft.booket.core.ui.component.FooterState
2020import com.ninecraft.booket.feature.screens.BookDetailScreen
2121import com.ninecraft.booket.feature.screens.LoginScreen
2222import com.ninecraft.booket.feature.screens.RecordDetailScreen
23+ import com.ninecraft.booket.feature.screens.RecordEditScreen
2324import com.ninecraft.booket.feature.screens.RecordScreen
25+ import com.ninecraft.booket.feature.screens.arguments.RecordEditArgs
2426import com.orhanobut.logger.Logger
2527import com.slack.circuit.codegen.annotations.CircuitInject
2628import com.slack.circuit.retained.rememberRetained
@@ -71,57 +73,62 @@ class BookDetailPresenter @AssistedInject constructor(
7173 var currentBookStatus by rememberRetained { mutableStateOf(BookStatus .READING ) }
7274 var selectedBookStatus by rememberRetained { mutableStateOf(BookStatus .READING ) }
7375 var currentRecordSort by rememberRetained { mutableStateOf(RecordSort .PAGE_NUMBER_ASC ) }
76+ var selectedRecordInfo by rememberRetained { mutableStateOf(ReadingRecordModel ()) }
7477 var isBookUpdateBottomSheetVisible by rememberRetained { mutableStateOf(false ) }
7578 var isRecordSortBottomSheetVisible by rememberRetained { mutableStateOf(false ) }
79+ var isRecordMenuBottomSheetVisible by rememberRetained { mutableStateOf(false ) }
80+ var isRecordDeleteDialogVisible by rememberRetained { mutableStateOf(false ) }
7681 var sideEffect by rememberRetained { mutableStateOf<BookDetailSideEffect ?>(null ) }
7782
7883 @Suppress(" TooGenericExceptionCaught" )
79- suspend fun initialLoad () {
84+ fun initialLoad () {
8085 uiState = UiState .Loading
8186
82- try {
83- coroutineScope {
84- val bookDetailDef = async { bookRepository.getBookDetail(screen.isbn13).getOrThrow() }
85- val seedsDef = async { bookRepository.getSeedsStats(screen.userBookId).getOrThrow() }
86- val readingRecordsDef = async {
87- recordRepository.getReadingRecords(
88- userBookId = screen.userBookId,
89- sort = currentRecordSort.value,
90- page = START_INDEX ,
91- size = PAGE_SIZE ,
92- ).getOrThrow()
93- }
94- val detail = bookDetailDef.await()
95- val seeds = seedsDef.await()
96- val records = readingRecordsDef.await()
87+ scope.launch {
88+ try {
89+ coroutineScope {
90+ val bookDetailDeferred = async { bookRepository.getBookDetail(screen.isbn13).getOrThrow() }
91+ val seedsDeferred = async { bookRepository.getSeedsStats(screen.userBookId).getOrThrow() }
92+ val readingRecordsDeferred = async {
93+ recordRepository.getReadingRecords(
94+ userBookId = screen.userBookId,
95+ sort = currentRecordSort.value,
96+ page = START_INDEX ,
97+ size = PAGE_SIZE ,
98+ ).getOrThrow()
99+ }
100+ val detail = bookDetailDeferred.await()
101+ val seeds = seedsDeferred.await()
102+ val records = readingRecordsDeferred.await()
97103
98- bookDetail = detail
99- currentBookStatus = BookStatus .fromValue(detail.userBookStatus) ? : BookStatus .BEFORE_READING
100- selectedBookStatus = currentBookStatus
101- seedsStates = seeds.categories.toImmutableList()
102- readingRecords = records.readingRecords.toPersistentList()
103- readingRecordsTotalCount = records.totalResults
104+ bookDetail = detail
105+ currentBookStatus = BookStatus .fromValue(detail.userBookStatus) ? : BookStatus .BEFORE_READING
106+ selectedBookStatus = currentBookStatus
107+ seedsStates = seeds.categories.toImmutableList()
108+ readingRecords = records.readingRecords.toPersistentList()
109+ readingRecordsTotalCount = records.totalResults
104110
105- isLastPage = records.lastPage
106- currentStartIndex = START_INDEX
111+ isLastPage = records.lastPage
112+ currentStartIndex = START_INDEX
107113
108- uiState = UiState .Success
109- }
110- } catch (e: Throwable ) {
111- uiState = UiState .Error (e)
114+ uiState = UiState .Success
115+ }
116+ } catch (e: Throwable ) {
117+ uiState = UiState .Error (e)
112118
113- val handleErrorMessage = { message: String ->
114- Logger .e(message)
115- sideEffect = BookDetailSideEffect .ShowToast (message)
116- }
119+ val handleErrorMessage = { message: String ->
120+ Logger .e(message)
121+ sideEffect = BookDetailSideEffect .ShowToast (message)
122+ }
117123
118- handleException(
119- exception = e,
120- onError = handleErrorMessage,
121- onLoginRequired = {
122- navigator.resetRoot(LoginScreen )
123- },
124- )
124+ handleException(
125+ exception = e,
126+ onError = handleErrorMessage,
127+ onLoginRequired = {
128+ navigator.resetRoot(LoginScreen )
129+ },
130+ )
131+ }
125132 }
126133 }
127134
@@ -182,6 +189,29 @@ class BookDetailPresenter @AssistedInject constructor(
182189 }
183190 }
184191
192+ fun deleteRecord (readingRecordId : String , onSuccess : () -> Unit ) {
193+ scope.launch {
194+ recordRepository.deleteRecord(readingRecordId = readingRecordId)
195+ .onSuccess {
196+ onSuccess()
197+ }
198+ .onFailure { exception ->
199+ val handleErrorMessage = { message: String ->
200+ Logger .e(message)
201+ sideEffect = BookDetailSideEffect .ShowToast (message)
202+ }
203+
204+ handleException(
205+ exception = exception,
206+ onError = handleErrorMessage,
207+ onLoginRequired = {
208+ navigator.resetRoot(LoginScreen )
209+ },
210+ )
211+ }
212+ }
213+ }
214+
185215 LaunchedEffect (Unit ) {
186216 initialLoad()
187217 }
@@ -230,6 +260,55 @@ class BookDetailPresenter @AssistedInject constructor(
230260 isRecordSortBottomSheetVisible = false
231261 }
232262
263+ is BookDetailUiEvent .OnRecordMenuClick -> {
264+ selectedRecordInfo = event.selectedRecordInfo
265+ isRecordMenuBottomSheetVisible = true
266+ }
267+
268+ is BookDetailUiEvent .OnRecordMenuBottomSheetDismiss -> {
269+ isRecordMenuBottomSheetVisible = false
270+ }
271+
272+ is BookDetailUiEvent .OnRecordDeleteDialogDismiss -> {
273+ isRecordDeleteDialogVisible = false
274+ }
275+
276+ is BookDetailUiEvent .OnEditRecordClick -> {
277+ isRecordMenuBottomSheetVisible = false
278+ navigator.goTo(
279+ RecordEditScreen (
280+ RecordEditArgs (
281+ id = selectedRecordInfo.id,
282+ pageNumber = selectedRecordInfo.pageNumber,
283+ quote = selectedRecordInfo.quote,
284+ review = selectedRecordInfo.review,
285+ emotionTags = selectedRecordInfo.emotionTags,
286+ bookTitle = selectedRecordInfo.bookTitle,
287+ bookPublisher = selectedRecordInfo.bookPublisher,
288+ bookCoverImageUrl = selectedRecordInfo.bookCoverImageUrl,
289+ author = selectedRecordInfo.author,
290+ ),
291+ ),
292+ )
293+ }
294+
295+ is BookDetailUiEvent .OnDeleteRecordClick -> {
296+ isRecordMenuBottomSheetVisible = false
297+ isRecordDeleteDialogVisible = true
298+ }
299+
300+ is BookDetailUiEvent .OnDelete -> {
301+ isRecordDeleteDialogVisible = false
302+ deleteRecord(
303+ readingRecordId = selectedRecordInfo.id,
304+ onSuccess = {
305+ readingRecords = readingRecords
306+ .filterNot { it.id == selectedRecordInfo.id }
307+ .toPersistentList()
308+ },
309+ )
310+ }
311+
233312 is BookDetailUiEvent .OnRecordItemClick -> {
234313 navigator.goTo(RecordDetailScreen (event.recordId))
235314 }
@@ -260,6 +339,9 @@ class BookDetailPresenter @AssistedInject constructor(
260339 currentBookStatus = currentBookStatus,
261340 selectedBookStatus = selectedBookStatus,
262341 currentRecordSort = currentRecordSort,
342+ selectedRecordInfo = selectedRecordInfo,
343+ isRecordMenuBottomSheetVisible = isRecordMenuBottomSheetVisible,
344+ isRecordDeleteDialogVisible = isRecordDeleteDialogVisible,
263345 sideEffect = sideEffect,
264346 eventSink = ::handleEvent,
265347 )
0 commit comments