Skip to content

Commit b3dd082

Browse files
committed
[BOOK-161] feat: 상세 정보 화면에서 도서 상태 변경 로직 임시 구현
1 parent 5abbd4e commit b3dd082

File tree

8 files changed

+157
-6
lines changed

8 files changed

+157
-6
lines changed

feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/BookDetailPresenter.kt

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,97 @@
11
package com.ninecraft.booket.feature.detail
22

33
import androidx.compose.runtime.Composable
4+
import androidx.compose.runtime.getValue
5+
import androidx.compose.runtime.mutableStateOf
6+
import androidx.compose.runtime.rememberCoroutineScope
7+
import androidx.compose.runtime.setValue
8+
import com.ninecraft.booket.core.common.utils.handleException
9+
import com.ninecraft.booket.core.data.api.repository.BookRepository
410
import com.ninecraft.booket.feature.screens.BookDetailScreen
11+
import com.ninecraft.booket.feature.screens.LoginScreen
12+
import com.orhanobut.logger.Logger
513
import com.slack.circuit.codegen.annotations.CircuitInject
14+
import com.slack.circuit.retained.rememberRetained
615
import com.slack.circuit.runtime.Navigator
716
import com.slack.circuit.runtime.presenter.Presenter
817
import dagger.assisted.Assisted
918
import dagger.assisted.AssistedFactory
1019
import dagger.assisted.AssistedInject
1120
import dagger.hilt.android.components.ActivityRetainedComponent
21+
import kotlinx.coroutines.launch
1222

1323
class BookDetailPresenter @AssistedInject constructor(
14-
@Assisted val navigator: Navigator,
24+
@Assisted private val screen: BookDetailScreen,
25+
@Assisted private val navigator: Navigator,
26+
private val repository: BookRepository,
1527
) : Presenter<BookDetailUiState> {
1628

1729
@Composable
1830
override fun present(): BookDetailUiState {
31+
val scope = rememberCoroutineScope()
32+
33+
var sideEffect by rememberRetained { mutableStateOf<BookDetailSideEffect?>(null) }
34+
35+
fun upsertBook(bookIsbn: String, bookStatus: String) {
36+
scope.launch {
37+
repository.upsertBook(bookIsbn, bookStatus)
38+
.onSuccess {
39+
sideEffect = BookDetailSideEffect.ShowToast("성공")
40+
}
41+
.onFailure { exception ->
42+
val handleErrorMessage = { message: String ->
43+
Logger.e(message)
44+
sideEffect = BookDetailSideEffect.ShowToast(message)
45+
}
46+
47+
handleException(
48+
exception = exception,
49+
onError = handleErrorMessage,
50+
onLoginRequired = {
51+
navigator.resetRoot(LoginScreen)
52+
},
53+
)
54+
}
55+
}
56+
}
57+
1958
fun handleEvent(event: BookDetailUiEvent) {
2059
when (event) {
60+
BookDetailUiEvent.InitSideEffect -> {
61+
sideEffect = null
62+
}
63+
2164
BookDetailUiEvent.OnBackClicked -> {
2265
navigator.pop()
2366
}
67+
68+
BookDetailUiEvent.OnBeforeReadingClick -> {
69+
upsertBook(screen.isbn, "BEFORE_READING")
70+
}
71+
72+
BookDetailUiEvent.OnReadingClick -> {
73+
upsertBook(screen.isbn, "READING")
74+
}
75+
76+
BookDetailUiEvent.OnCompletedClick -> {
77+
upsertBook(screen.isbn, "COMPLETED")
78+
}
2479
}
2580
}
2681

2782
return BookDetailUiState(
83+
sideEffect = sideEffect,
2884
eventSink = ::handleEvent,
2985
)
3086
}
3187

3288
@CircuitInject(BookDetailScreen::class, ActivityRetainedComponent::class)
3389
@AssistedFactory
3490
fun interface Factory {
35-
fun create(navigator: Navigator): BookDetailPresenter
91+
fun create(
92+
screen: BookDetailScreen,
93+
navigator: Navigator,
94+
): BookDetailPresenter
3695
}
3796
}
3897

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.ninecraft.booket.feature.detail
2+
3+
import android.widget.Toast
4+
import androidx.compose.runtime.Composable
5+
import androidx.compose.ui.platform.LocalContext
6+
import com.skydoves.compose.effects.RememberedEffect
7+
8+
@Composable
9+
internal fun HandleBookDetailSideEffects(
10+
state: BookDetailUiState,
11+
eventSink: (BookDetailUiEvent) -> Unit,
12+
) {
13+
val context = LocalContext.current
14+
15+
RememberedEffect(state.sideEffect) {
16+
when (state.sideEffect) {
17+
is BookDetailSideEffect.ShowToast -> {
18+
Toast.makeText(context, state.sideEffect.message, Toast.LENGTH_SHORT).show()
19+
}
20+
21+
null -> {}
22+
}
23+
24+
if (state.sideEffect != null) {
25+
eventSink(BookDetailUiEvent.InitSideEffect)
26+
}
27+
}
28+
}

feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/BookDetailUi.kt

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
package com.ninecraft.booket.feature.detail
22

3+
import androidx.compose.foundation.layout.Arrangement
4+
import androidx.compose.foundation.layout.Box
5+
import androidx.compose.foundation.layout.Row
6+
import androidx.compose.foundation.layout.fillMaxSize
37
import androidx.compose.runtime.Composable
8+
import androidx.compose.ui.Alignment
49
import androidx.compose.ui.Modifier
510
import com.ninecraft.booket.core.designsystem.ComponentPreview
611
import com.ninecraft.booket.core.designsystem.component.appbar.ReedBackTopAppBar
12+
import com.ninecraft.booket.core.designsystem.component.button.ReedButton
13+
import com.ninecraft.booket.core.designsystem.component.button.ReedButtonColorStyle
14+
import com.ninecraft.booket.core.designsystem.component.button.largeButtonStyle
715
import com.ninecraft.booket.core.designsystem.theme.ReedTheme
816
import com.ninecraft.booket.core.ui.component.ReedFullScreen
917
import com.ninecraft.booket.feature.screens.BookDetailScreen
@@ -16,13 +24,53 @@ fun BookDetail(
1624
state: BookDetailUiState,
1725
modifier: Modifier = Modifier,
1826
) {
27+
HandleBookDetailSideEffects(
28+
state = state,
29+
eventSink = state.eventSink,
30+
)
31+
1932
ReedFullScreen(modifier = modifier) {
2033
ReedBackTopAppBar(
2134
title = "도서 상세 정보",
2235
onBackClick = {
2336
state.eventSink(BookDetailUiEvent.OnBackClicked)
2437
},
2538
)
39+
40+
Box(
41+
modifier = Modifier.fillMaxSize(),
42+
contentAlignment = Alignment.Center,
43+
) {
44+
Row(
45+
verticalAlignment = Alignment.CenterVertically,
46+
horizontalArrangement = Arrangement.spacedBy(ReedTheme.spacing.spacing4),
47+
) {
48+
ReedButton(
49+
onClick = {
50+
state.eventSink(BookDetailUiEvent.OnBeforeReadingClick)
51+
},
52+
sizeStyle = largeButtonStyle,
53+
colorStyle = ReedButtonColorStyle.PRIMARY,
54+
text = "읽기 전",
55+
)
56+
ReedButton(
57+
onClick = {
58+
state.eventSink(BookDetailUiEvent.OnReadingClick)
59+
},
60+
sizeStyle = largeButtonStyle,
61+
colorStyle = ReedButtonColorStyle.PRIMARY,
62+
text = "읽는 중",
63+
)
64+
ReedButton(
65+
onClick = {
66+
state.eventSink(BookDetailUiEvent.OnCompletedClick)
67+
},
68+
sizeStyle = largeButtonStyle,
69+
colorStyle = ReedButtonColorStyle.PRIMARY,
70+
text = "독서 완료",
71+
)
72+
}
73+
}
2674
}
2775
}
2876

feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/BookDetailUiState.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,24 @@ package com.ninecraft.booket.feature.detail
22

33
import com.slack.circuit.runtime.CircuitUiEvent
44
import com.slack.circuit.runtime.CircuitUiState
5+
import java.util.UUID
56

67
data class BookDetailUiState(
8+
val sideEffect: BookDetailSideEffect? = null,
79
val eventSink: (BookDetailUiEvent) -> Unit,
810
) : CircuitUiState
911

12+
sealed interface BookDetailSideEffect {
13+
data class ShowToast(
14+
val message: String,
15+
private val key: String = UUID.randomUUID().toString(),
16+
) : BookDetailSideEffect
17+
}
18+
1019
sealed interface BookDetailUiEvent : CircuitUiEvent {
20+
data object InitSideEffect : BookDetailUiEvent
1121
data object OnBackClicked : BookDetailUiEvent
22+
data object OnBeforeReadingClick : BookDetailUiEvent
23+
data object OnReadingClick : BookDetailUiEvent
24+
data object OnCompletedClick : BookDetailUiEvent
1225
}

feature/library/src/main/kotlin/com/ninecraft/booket/feature/library/LibraryPresenter.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import androidx.compose.runtime.setValue
1010
import com.ninecraft.booket.core.data.api.repository.BookRepository
1111
import com.ninecraft.booket.core.model.LibraryBookSummaryModel
1212
import com.ninecraft.booket.core.ui.component.FooterState
13+
import com.ninecraft.booket.feature.screens.BookDetailScreen
1314
import com.ninecraft.booket.feature.screens.LibraryScreen
1415
import com.ninecraft.booket.feature.screens.SettingsScreen
1516
import com.orhanobut.logger.Logger
@@ -113,7 +114,7 @@ class LibraryPresenter @AssistedInject constructor(
113114
}
114115

115116
is LibraryUiEvent.OnBookClick -> {
116-
// TODO: 상세 화면으로 이동
117+
navigator.goTo(BookDetailScreen(isbn = event.isbn))
117118
}
118119

119120
is LibraryUiEvent.OnLoadMore -> {

feature/library/src/main/kotlin/com/ninecraft/booket/feature/library/LibraryUi.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,9 @@ internal fun LibraryContent(
108108
items(state.books) {
109109
LibraryBookItem(
110110
book = it,
111-
onBookClick = {},
111+
onBookClick = {
112+
state.eventSink(LibraryUiEvent.OnBookClick(it.bookIsbn))
113+
},
112114
)
113115
Box(
114116
modifier = modifier

feature/library/src/main/kotlin/com/ninecraft/booket/feature/library/LibraryUiState.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ sealed interface LibrarySideEffect {
3333
sealed interface LibraryUiEvent : CircuitUiEvent {
3434
data object InitSideEffect : LibraryUiEvent
3535
data object OnSettingsClick : LibraryUiEvent
36-
data object OnBookClick : LibraryUiEvent
36+
data class OnBookClick(val isbn: String) : LibraryUiEvent
3737
data object OnLoadMore : LibraryUiEvent
3838
data object OnRetryClick : LibraryUiEvent
3939
data class OnFilterClick(val filterOption: LibraryFilterOption) : LibraryUiEvent

feature/screens/src/main/kotlin/com/ninecraft/booket/feature/screens/Screens.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,4 @@ data class WebViewScreen(
3838
) : ReedScreen(name = "WebView()")
3939

4040
@Parcelize
41-
data object BookDetailScreen : ReedScreen(name = "BookDetail()")
41+
data class BookDetailScreen(val isbn: String) : ReedScreen(name = "BookDetail()")

0 commit comments

Comments
 (0)