Skip to content

Commit 1cbdcc5

Browse files
committed
[BOOK-188] feat: 도서 상세 화면 클릭 이벤트 연동
1 parent 0d74a87 commit 1cbdcc5

7 files changed

Lines changed: 137 additions & 22 deletions

File tree

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

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ import androidx.compose.runtime.getValue
55
import androidx.compose.runtime.mutableStateOf
66
import androidx.compose.runtime.rememberCoroutineScope
77
import androidx.compose.runtime.setValue
8+
import com.ninecraft.booket.core.common.constants.BookStatus
89
import com.ninecraft.booket.core.common.utils.handleException
910
import com.ninecraft.booket.core.data.api.repository.BookRepository
1011
import com.ninecraft.booket.feature.screens.BookDetailScreen
1112
import com.ninecraft.booket.feature.screens.LoginScreen
1213
import com.ninecraft.booket.feature.screens.RecordDetailScreen
14+
import com.ninecraft.booket.feature.screens.RecordScreen
1315
import com.orhanobut.logger.Logger
1416
import com.slack.circuit.codegen.annotations.CircuitInject
1517
import com.slack.circuit.retained.rememberRetained
@@ -31,6 +33,10 @@ class BookDetailPresenter @AssistedInject constructor(
3133
override fun present(): BookDetailUiState {
3234
val scope = rememberCoroutineScope()
3335

36+
var isBookUpdateBottomSheetVisible by rememberRetained { mutableStateOf(false) }
37+
var isRecordSortBottomSheetVisible by rememberRetained { mutableStateOf(false) }
38+
var currentBookStatus by rememberRetained { mutableStateOf(BookStatus.READING) }
39+
var currentRecordSort by rememberRetained { mutableStateOf(RecordSort.PAGE_ASCENDING) }
3440
var sideEffect by rememberRetained { mutableStateOf<BookDetailSideEffect?>(null) }
3541

3642
fun upsertBook(bookIsbn: String, bookStatus: String) {
@@ -62,20 +68,41 @@ class BookDetailPresenter @AssistedInject constructor(
6268
sideEffect = null
6369
}
6470

65-
is BookDetailUiEvent.OnBackClicked -> {
71+
is BookDetailUiEvent.OnBackClick -> {
6672
navigator.pop()
6773
}
6874

69-
is BookDetailUiEvent.OnBeforeReadingClick -> {
70-
upsertBook(screen.isbn, "BEFORE_READING")
75+
is BookDetailUiEvent.OnBookStatusButtonClick -> {
76+
isBookUpdateBottomSheetVisible = true
7177
}
7278

73-
is BookDetailUiEvent.OnReadingClick -> {
74-
upsertBook(screen.isbn, "READING")
79+
is BookDetailUiEvent.OnRegisterRecordButtonClick -> {
80+
navigator.goTo(RecordScreen(""))
7581
}
7682

77-
is BookDetailUiEvent.OnCompletedClick -> {
78-
upsertBook(screen.isbn, "COMPLETED")
83+
is BookDetailUiEvent.OnRecordSortButtonClick -> {
84+
isRecordSortBottomSheetVisible = true
85+
}
86+
87+
is BookDetailUiEvent.OnBookUpdateBottomSheetDismiss -> {
88+
isBookUpdateBottomSheetVisible = false
89+
}
90+
91+
is BookDetailUiEvent.OnBookStatusItemSelected -> {
92+
currentBookStatus = event.bookStatus
93+
}
94+
95+
is BookDetailUiEvent.OnBookStatusUpdateButtonClick -> {
96+
upsertBook(screen.isbn, currentBookStatus.value)
97+
}
98+
99+
is BookDetailUiEvent.OnRecordSortBottomSheetDismiss -> {
100+
isRecordSortBottomSheetVisible = false
101+
}
102+
103+
is BookDetailUiEvent.OnRecordSortItemSelected -> {
104+
currentRecordSort = event.sortType
105+
isRecordSortBottomSheetVisible = false
79106
}
80107

81108
is BookDetailUiEvent.OnRecordItemClick -> {
@@ -85,6 +112,10 @@ class BookDetailPresenter @AssistedInject constructor(
85112
}
86113

87114
return BookDetailUiState(
115+
isBookUpdateBottomSheetVisible = isBookUpdateBottomSheetVisible,
116+
isRecordSortBottomSheetVisible = isRecordSortBottomSheetVisible,
117+
currentBookStatus = currentBookStatus,
118+
currentRecordSort = currentRecordSort,
88119
sideEffect = sideEffect,
89120
eventSink = ::handleEvent,
90121
)

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

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,13 @@ import androidx.compose.foundation.layout.width
1212
import androidx.compose.foundation.rememberScrollState
1313
import androidx.compose.foundation.shape.RoundedCornerShape
1414
import androidx.compose.foundation.verticalScroll
15+
import androidx.compose.material3.ExperimentalMaterial3Api
1516
import androidx.compose.material3.Icon
1617
import androidx.compose.material3.Text
1718
import androidx.compose.material3.VerticalDivider
19+
import androidx.compose.material3.rememberModalBottomSheetState
1820
import androidx.compose.runtime.Composable
21+
import androidx.compose.runtime.rememberCoroutineScope
1922
import androidx.compose.ui.Alignment
2023
import androidx.compose.ui.Modifier
2124
import androidx.compose.ui.draw.clip
@@ -24,6 +27,7 @@ import androidx.compose.ui.res.painterResource
2427
import androidx.compose.ui.res.vectorResource
2528
import androidx.compose.ui.text.style.TextOverflow
2629
import androidx.compose.ui.unit.dp
30+
import com.ninecraft.booket.core.common.constants.BookStatus
2731
import com.ninecraft.booket.core.designsystem.ComponentPreview
2832
import com.ninecraft.booket.core.designsystem.component.NetworkImage
2933
import com.ninecraft.booket.core.designsystem.component.ReedDivider
@@ -33,19 +37,28 @@ import com.ninecraft.booket.core.designsystem.component.button.largeButtonStyle
3337
import com.ninecraft.booket.core.designsystem.theme.ReedTheme
3438
import com.ninecraft.booket.core.ui.component.ReedBackTopAppBar
3539
import com.ninecraft.booket.core.ui.component.ReedFullScreen
40+
import com.ninecraft.booket.feature.detail.book.component.BookUpdateBottomSheet
3641
import com.ninecraft.booket.feature.detail.book.component.CollectedSeed
42+
import com.ninecraft.booket.feature.detail.book.component.RecordSortBottomSheet
3743
import com.ninecraft.booket.feature.detail.book.component.RecordsCollection
3844
import com.ninecraft.booket.feature.screens.BookDetailScreen
3945
import com.slack.circuit.codegen.annotations.CircuitInject
4046
import dagger.hilt.android.components.ActivityRetainedComponent
47+
import kotlinx.collections.immutable.toImmutableList
48+
import kotlinx.coroutines.launch
4149
import com.ninecraft.booket.core.designsystem.R as designR
4250

51+
@OptIn(ExperimentalMaterial3Api::class)
4352
@CircuitInject(BookDetailScreen::class, ActivityRetainedComponent::class)
4453
@Composable
4554
internal fun BookDetailUi(
4655
state: BookDetailUiState,
4756
modifier: Modifier = Modifier,
4857
) {
58+
val bookUpdateBottomSheetState = rememberModalBottomSheetState()
59+
val recordSortBottomSheetState = rememberModalBottomSheetState()
60+
val coroutineScope = rememberCoroutineScope()
61+
4962
HandleBookDetailSideEffects(
5063
state = state,
5164
eventSink = state.eventSink,
@@ -55,11 +68,54 @@ internal fun BookDetailUi(
5568
ReedBackTopAppBar(
5669
title = "",
5770
onBackClick = {
58-
state.eventSink(BookDetailUiEvent.OnBackClicked)
71+
state.eventSink(BookDetailUiEvent.OnBackClick)
5972
},
6073
)
6174
BookDetailContent(state = state)
6275
}
76+
77+
if (state.isBookUpdateBottomSheetVisible) {
78+
BookUpdateBottomSheet(
79+
onDismissRequest = {
80+
state.eventSink(BookDetailUiEvent.OnBookUpdateBottomSheetDismiss)
81+
},
82+
sheetState = bookUpdateBottomSheetState,
83+
onCloseButtonClick = {
84+
coroutineScope.launch {
85+
bookUpdateBottomSheetState.hide()
86+
state.eventSink(BookDetailUiEvent.OnBookUpdateBottomSheetDismiss)
87+
}
88+
},
89+
bookStatuses = BookStatus.entries.toTypedArray().toImmutableList(),
90+
currentBookStatus = state.currentBookStatus,
91+
onItemSelected = {
92+
state.eventSink(BookDetailUiEvent.OnBookStatusItemSelected(it))
93+
},
94+
onBookUpdateButtonClick = {
95+
state.eventSink(BookDetailUiEvent.OnBookStatusUpdateButtonClick)
96+
},
97+
)
98+
}
99+
100+
if (state.isRecordSortBottomSheetVisible) {
101+
RecordSortBottomSheet(
102+
onDismissRequest = {
103+
state.eventSink(BookDetailUiEvent.OnRecordSortBottomSheetDismiss)
104+
},
105+
sheetState = recordSortBottomSheetState,
106+
onCloseButtonClick = {
107+
coroutineScope.launch {
108+
recordSortBottomSheetState.hide()
109+
state.eventSink(BookDetailUiEvent.OnRecordSortBottomSheetDismiss)
110+
}
111+
},
112+
recordSortItems = RecordSort.entries.toTypedArray().toImmutableList(),
113+
currentRecordSort = state.currentRecordSort,
114+
onItemSelected = {
115+
state.eventSink(BookDetailUiEvent.OnRecordSortItemSelected(it))
116+
},
117+
)
118+
}
63119
}
64120

65121
@Composable
@@ -142,7 +198,9 @@ internal fun BookDetailContent(
142198
.padding(horizontal = ReedTheme.spacing.spacing5),
143199
) {
144200
ReedButton(
145-
onClick = {},
201+
onClick = {
202+
state.eventSink(BookDetailUiEvent.OnBookStatusButtonClick)
203+
},
146204
text = "읽는 중",
147205
sizeStyle = largeButtonStyle,
148206
colorStyle = ReedButtonColorStyle.SECONDARY,
@@ -157,7 +215,9 @@ internal fun BookDetailContent(
157215
)
158216
Spacer(modifier = Modifier.width(ReedTheme.spacing.spacing2))
159217
ReedButton(
160-
onClick = {},
218+
onClick = {
219+
state.eventSink(BookDetailUiEvent.OnRegisterRecordButtonClick)
220+
},
161221
text = "독서 기록 추가",
162222
sizeStyle = largeButtonStyle,
163223
colorStyle = ReedButtonColorStyle.PRIMARY,

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

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.ninecraft.booket.feature.detail.book
22

33
import com.ninecraft.booket.core.common.R
4+
import com.ninecraft.booket.core.common.constants.BookStatus
45
import com.ninecraft.booket.core.model.Emotion
56
import com.ninecraft.booket.core.model.EmotionModel
67
import com.ninecraft.booket.core.model.RecordRegisterModel
@@ -11,6 +12,8 @@ import kotlinx.collections.immutable.persistentListOf
1112
import java.util.UUID
1213

1314
data class BookDetailUiState(
15+
val isBookUpdateBottomSheetVisible: Boolean = false,
16+
val isRecordSortBottomSheetVisible: Boolean = false,
1417
val emotionList: ImmutableList<EmotionModel> = persistentListOf(
1518
EmotionModel(
1619
type = Emotion.WARM,
@@ -29,6 +32,7 @@ data class BookDetailUiState(
2932
count = 2,
3033
),
3134
),
35+
val currentBookStatus: BookStatus = BookStatus.BEFORE_READING,
3236
val currentRecordSort: RecordSort = RecordSort.PAGE_ASCENDING,
3337
val recordCollections: ImmutableList<RecordRegisterModel> = persistentListOf(
3438
RecordRegisterModel(
@@ -69,10 +73,15 @@ sealed interface BookDetailSideEffect {
6973

7074
sealed interface BookDetailUiEvent : CircuitUiEvent {
7175
data object InitSideEffect : BookDetailUiEvent
72-
data object OnBackClicked : BookDetailUiEvent
73-
data object OnBeforeReadingClick : BookDetailUiEvent
74-
data object OnReadingClick : BookDetailUiEvent
75-
data object OnCompletedClick : BookDetailUiEvent
76+
data object OnBackClick : BookDetailUiEvent
77+
data object OnBookStatusButtonClick : BookDetailUiEvent
78+
data object OnRegisterRecordButtonClick : BookDetailUiEvent
79+
data object OnRecordSortButtonClick : BookDetailUiEvent
80+
data object OnBookUpdateBottomSheetDismiss : BookDetailUiEvent
81+
data class OnBookStatusItemSelected(val bookStatus: BookStatus) : BookDetailUiEvent
82+
data object OnBookStatusUpdateButtonClick : BookDetailUiEvent
83+
data object OnRecordSortBottomSheetDismiss : BookDetailUiEvent
84+
data class OnRecordSortItemSelected(val sortType: RecordSort) : BookDetailUiEvent
7685
data class OnRecordItemClick(val recordId: String) : BookDetailUiEvent
7786
}
7887

feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/component/BookUpdateBottomSheet.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ internal fun BookUpdateBottomSheet(
4949
bookStatuses: ImmutableList<BookStatus>,
5050
currentBookStatus: BookStatus?,
5151
onItemSelected: (BookStatus) -> Unit,
52-
onBookRegisterButtonClick: () -> Unit,
52+
onBookUpdateButtonClick: () -> Unit,
5353
modifier: Modifier = Modifier,
5454
) {
5555
ReedBottomSheet(
@@ -107,7 +107,7 @@ internal fun BookUpdateBottomSheet(
107107
Spacer(modifier = Modifier.height(ReedTheme.spacing.spacing4))
108108
ReedButton(
109109
onClick = {
110-
onBookRegisterButtonClick()
110+
onBookUpdateButtonClick()
111111
},
112112
sizeStyle = largeButtonStyle,
113113
colorStyle = ReedButtonColorStyle.PRIMARY,
@@ -168,7 +168,7 @@ private fun BookUpdateBottomSheetPreview() {
168168
bookStatuses = BookStatus.entries.toImmutableList(),
169169
currentBookStatus = null,
170170
onItemSelected = {},
171-
onBookRegisterButtonClick = {},
171+
onBookUpdateButtonClick = {},
172172
)
173173
}
174174
}

feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/component/RecordItem.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ internal fun RecordItem(
6969
Spacer(modifier = Modifier.width(ReedTheme.spacing.spacing2))
7070
Column {
7171
Text(
72-
text = "#감동 공감",
72+
text = "#감동·공감",
7373
color = ReedTheme.colors.contentBrand,
7474
style = ReedTheme.typography.label1SemiBold,
7575
)

feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/component/RecordsCollection.kt

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.ninecraft.booket.feature.detail.book.component
22

3+
import androidx.compose.foundation.clickable
34
import androidx.compose.foundation.layout.Arrangement
45
import androidx.compose.foundation.layout.PaddingValues
56
import androidx.compose.foundation.layout.Spacer
@@ -12,6 +13,7 @@ import androidx.compose.ui.Modifier
1213
import androidx.compose.ui.unit.dp
1314
import com.ninecraft.booket.core.designsystem.ComponentPreview
1415
import com.ninecraft.booket.core.designsystem.theme.ReedTheme
16+
import com.ninecraft.booket.feature.detail.book.BookDetailUiEvent
1517
import com.ninecraft.booket.feature.detail.book.BookDetailUiState
1618
import kotlinx.collections.immutable.toImmutableList
1719

@@ -24,8 +26,12 @@ internal fun RecordsCollection(
2426
modifier = modifier
2527
.fillMaxWidth()
2628
.padding(horizontal = ReedTheme.spacing.spacing5)
27-
.height((192 * state.recordCollections.size).dp + 40.dp),
28-
contentPadding = PaddingValues(vertical = ReedTheme.spacing.spacing6),
29+
// contentPadding + Header + (RecordItem + padding) * size
30+
.height(36.dp + 40.dp + (192 * state.recordCollections.size).dp),
31+
contentPadding = PaddingValues(
32+
top = ReedTheme.spacing.spacing6,
33+
bottom = ReedTheme.spacing.spacing3,
34+
),
2935
verticalArrangement = Arrangement.spacedBy(ReedTheme.spacing.spacing3),
3036
userScrollEnabled = false,
3137
) {
@@ -43,6 +49,9 @@ internal fun RecordsCollection(
4349
emotionTags = emotionTags.toImmutableList(),
4450
pageNumber = pageNumber,
4551
createdAt = createdAt,
52+
modifier = Modifier.clickable {
53+
state.eventSink(BookDetailUiEvent.OnRecordItemClick(id))
54+
},
4655
)
4756
}
4857
}

feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/component/RecordsCollectionHeader.kt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.ninecraft.booket.feature.detail.book.component
22

3+
import androidx.compose.foundation.clickable
34
import androidx.compose.foundation.layout.Arrangement
45
import androidx.compose.foundation.layout.Row
56
import androidx.compose.foundation.layout.Spacer
@@ -13,10 +14,11 @@ import androidx.compose.ui.Modifier
1314
import androidx.compose.ui.graphics.vector.ImageVector
1415
import androidx.compose.ui.res.stringResource
1516
import androidx.compose.ui.res.vectorResource
16-
import com.ninecraft.booket.core.designsystem.R as designR
1717
import com.ninecraft.booket.core.designsystem.theme.ReedTheme
1818
import com.ninecraft.booket.feature.detail.R
19+
import com.ninecraft.booket.feature.detail.book.BookDetailUiEvent
1920
import com.ninecraft.booket.feature.detail.book.BookDetailUiState
21+
import com.ninecraft.booket.core.designsystem.R as designR
2022

2123
@Composable
2224
internal fun RecordsCollectionHeader(
@@ -41,7 +43,11 @@ internal fun RecordsCollectionHeader(
4143
style = ReedTheme.typography.headline2SemiBold,
4244
)
4345
}
44-
Row {
46+
Row(
47+
modifier = Modifier.clickable {
48+
state.eventSink(BookDetailUiEvent.OnRecordSortButtonClick)
49+
},
50+
) {
4551
Text(
4652
text = stringResource(state.currentRecordSort.getDisplayNameRes()),
4753
color = ReedTheme.colors.contentSecondary,

0 commit comments

Comments
 (0)