Skip to content

Commit 3e5c5f4

Browse files
committed
Merge branch 'develop' into BOOK-304-feature/#173
# Conflicts: # feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/book/BookSearchPresenter.kt
2 parents 08252b1 + 993f756 commit 3e5c5f4

File tree

48 files changed

+724
-258
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+724
-258
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.ninecraft.booket.core.common.utils
2+
3+
import android.content.Context
4+
import androidx.annotation.StringRes
5+
import androidx.compose.runtime.Composable
6+
import androidx.compose.ui.res.stringResource
7+
8+
// https://www.youtube.com/watch?v=mB1Lej0aDus
9+
sealed class UiText {
10+
data class DirectString(val value: String) : UiText()
11+
12+
class StringResource(
13+
@StringRes val resId: Int,
14+
vararg val args: Any,
15+
) : UiText()
16+
17+
@Composable
18+
fun asString() = when (this) {
19+
is DirectString -> value
20+
is StringResource -> stringResource(resId, *args)
21+
}
22+
23+
fun asString(context: Context) = when (this) {
24+
is DirectString -> value
25+
is StringResource -> context.getString(resId, *args)
26+
}
27+
}

core/data/api/src/main/kotlin/com/ninecraft/booket/core/data/api/repository/AuthRepository.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.ninecraft.booket.core.data.api.repository
22

33
import com.ninecraft.booket.core.model.AutoLoginState
4+
import com.ninecraft.booket.core.model.UserState
45
import kotlinx.coroutines.flow.Flow
56

67
interface AuthRepository {
@@ -11,4 +12,8 @@ interface AuthRepository {
1112
suspend fun withdraw(): Result<Unit>
1213

1314
val autoLoginState: Flow<AutoLoginState>
15+
16+
val userState: Flow<UserState>
17+
18+
suspend fun getCurrentUserState(): UserState
1419
}

core/data/api/src/main/kotlin/com/ninecraft/booket/core/data/api/repository/BookRepository.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ interface BookRepository {
1212
val bookRecentSearches: Flow<List<String>>
1313
val libraryRecentSearches: Flow<List<String>>
1414

15+
suspend fun searchBookAsGuest(
16+
query: String,
17+
start: Int,
18+
): Result<BookSearchModel>
19+
1520
suspend fun searchBook(
1621
query: String,
1722
start: Int,

core/data/impl/src/main/kotlin/com/ninecraft/booket/core/data/impl/mapper/ResponseToModel.kt

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import com.ninecraft.booket.core.network.response.BookSearchResponse
2626
import com.ninecraft.booket.core.network.response.BookSummary
2727
import com.ninecraft.booket.core.network.response.BookUpsertResponse
2828
import com.ninecraft.booket.core.network.response.Category
29+
import com.ninecraft.booket.core.network.response.GuestBookSearchResponse
30+
import com.ninecraft.booket.core.network.response.GuestBookSummary
2931
import com.ninecraft.booket.core.network.response.HomeResponse
3032
import com.ninecraft.booket.core.network.response.LibraryBookSummary
3133
import com.ninecraft.booket.core.network.response.LibraryBooks
@@ -79,6 +81,35 @@ internal fun BookSummary.toModel(): BookSummaryModel {
7981
)
8082
}
8183

84+
internal fun GuestBookSearchResponse.toModel(): BookSearchModel {
85+
return BookSearchModel(
86+
version = version,
87+
title = title,
88+
pubDate = pubDate,
89+
totalResults = totalResults,
90+
startIndex = startIndex,
91+
itemsPerPage = itemsPerPage,
92+
query = query,
93+
searchCategoryId = searchCategoryId,
94+
searchCategoryName = searchCategoryName,
95+
lastPage = lastPage,
96+
books = books.map { it.toModel() },
97+
)
98+
}
99+
100+
internal fun GuestBookSummary.toModel(): BookSummaryModel {
101+
return BookSummaryModel(
102+
isbn13 = isbn13,
103+
title = title.decodeHtmlEntities(),
104+
author = author,
105+
publisher = publisher,
106+
coverImageUrl = coverImageUrl,
107+
link = link,
108+
userBookStatus = "BEFORE_REGISTRATION",
109+
key = "$title-$isbn13",
110+
)
111+
}
112+
82113
internal fun BookDetailResponse.toModel(): BookDetailModel {
83114
return BookDetailModel(
84115
version = version,

core/data/impl/src/main/kotlin/com/ninecraft/booket/core/data/impl/repository/DefaultAuthRepository.kt

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import com.ninecraft.booket.core.common.utils.runSuspendCatching
44
import com.ninecraft.booket.core.data.api.repository.AuthRepository
55
import com.ninecraft.booket.core.datastore.api.datasource.TokenDataSource
66
import com.ninecraft.booket.core.model.AutoLoginState
7+
import com.ninecraft.booket.core.model.UserState
78
import com.ninecraft.booket.core.network.request.LoginRequest
89
import com.ninecraft.booket.core.network.service.ReedService
910
import kotlinx.coroutines.flow.map
@@ -48,9 +49,16 @@ internal class DefaultAuthRepository @Inject constructor(
4849

4950
override val autoLoginState = tokenDataSource.accessToken
5051
.map { accessToken ->
51-
when {
52-
accessToken.isBlank() -> AutoLoginState.NOT_LOGGED_IN
53-
else -> AutoLoginState.LOGGED_IN
54-
}
52+
if (accessToken.isBlank()) AutoLoginState.NOT_LOGGED_IN else AutoLoginState.LOGGED_IN
5553
}
54+
55+
override val userState = tokenDataSource.accessToken
56+
.map { accessToken ->
57+
if (accessToken.isBlank()) UserState.Guest else UserState.LoggedIn
58+
}
59+
60+
override suspend fun getCurrentUserState(): UserState {
61+
val accessToken = tokenDataSource.getAccessToken()
62+
return if (accessToken.isBlank()) UserState.Guest else UserState.LoggedIn
63+
}
5664
}

core/data/impl/src/main/kotlin/com/ninecraft/booket/core/data/impl/repository/DefaultBookRepository.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,19 @@ internal class DefaultBookRepository @Inject constructor(
1717
override val bookRecentSearches = bookRecentSearchDataSource.recentSearches
1818
override val libraryRecentSearches = libraryRecentSearchDataSource.recentSearches
1919

20+
override suspend fun searchBookAsGuest(
21+
query: String,
22+
start: Int,
23+
) = runSuspendCatching {
24+
val result = service.searchBookAsGuest(
25+
query = query,
26+
start = start,
27+
).toModel()
28+
29+
bookRecentSearchDataSource.addRecentSearch(query)
30+
result
31+
}
32+
2033
override suspend fun searchBook(
2134
query: String,
2235
start: Int,

core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/component/button/ButtonColorStyle.kt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,21 @@ package com.ninecraft.booket.core.designsystem.component.button
22

33
import androidx.compose.foundation.BorderStroke
44
import androidx.compose.runtime.Composable
5+
import androidx.compose.ui.graphics.Color
56
import androidx.compose.ui.unit.dp
67
import com.ninecraft.booket.core.designsystem.theme.Kakao
78
import com.ninecraft.booket.core.designsystem.theme.ReedTheme
89

910
enum class ReedButtonColorStyle {
10-
PRIMARY, SECONDARY, TERTIARY, STROKE, KAKAO;
11+
PRIMARY, SECONDARY, TERTIARY, STROKE, TEXT, KAKAO;
1112

1213
@Composable
1314
fun containerColor(isPressed: Boolean) = when (this) {
1415
PRIMARY -> if (isPressed) ReedTheme.colors.bgPrimaryPressed else ReedTheme.colors.bgPrimary
1516
SECONDARY -> if (isPressed) ReedTheme.colors.bgSecondaryPressed else ReedTheme.colors.bgSecondary
1617
TERTIARY -> if (isPressed) ReedTheme.colors.bgTertiaryPressed else ReedTheme.colors.bgTertiary
1718
STROKE -> if (isPressed) ReedTheme.colors.basePrimary else ReedTheme.colors.basePrimary
19+
TEXT -> Color.Transparent
1820
KAKAO -> Kakao
1921
}
2022

@@ -24,11 +26,15 @@ enum class ReedButtonColorStyle {
2426
SECONDARY -> ReedTheme.colors.contentPrimary
2527
TERTIARY -> ReedTheme.colors.contentBrand
2628
STROKE -> ReedTheme.colors.contentBrand
29+
TEXT -> ReedTheme.colors.borderBrand
2730
KAKAO -> ReedTheme.colors.contentPrimary
2831
}
2932

3033
@Composable
31-
fun disabledContainerColor() = ReedTheme.colors.bgDisabled
34+
fun disabledContainerColor() = when (this) {
35+
TEXT -> Color.Transparent
36+
else -> ReedTheme.colors.bgDisabled
37+
}
3238

3339
@Composable
3440
fun disabledContentColor() = ReedTheme.colors.contentDisabled
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package com.ninecraft.booket.core.designsystem.component.button
2+
3+
import androidx.compose.foundation.interaction.MutableInteractionSource
4+
import androidx.compose.foundation.interaction.collectIsPressedAsState
5+
import androidx.compose.foundation.layout.Arrangement
6+
import androidx.compose.foundation.layout.Column
7+
import androidx.compose.foundation.layout.FlowRow
8+
import androidx.compose.foundation.layout.IntrinsicSize
9+
import androidx.compose.foundation.layout.padding
10+
import androidx.compose.foundation.layout.width
11+
import androidx.compose.material3.ButtonDefaults
12+
import androidx.compose.material3.HorizontalDivider
13+
import androidx.compose.material3.Text
14+
import androidx.compose.material3.TextButton
15+
import androidx.compose.runtime.Composable
16+
import androidx.compose.runtime.getValue
17+
import androidx.compose.runtime.remember
18+
import androidx.compose.ui.Modifier
19+
import androidx.compose.ui.graphics.Color
20+
import androidx.compose.ui.unit.dp
21+
import com.ninecraft.booket.core.common.utils.MultipleEventsCutter
22+
import com.ninecraft.booket.core.common.utils.get
23+
import com.ninecraft.booket.core.designsystem.ComponentPreview
24+
25+
@Composable
26+
fun ReedTextButton(
27+
onClick: () -> Unit,
28+
text: String,
29+
sizeStyle: ButtonSizeStyle,
30+
colorStyle: ReedButtonColorStyle,
31+
modifier: Modifier = Modifier,
32+
enabled: Boolean = true,
33+
multipleEventsCutterEnabled: Boolean = true,
34+
) {
35+
val multipleEventsCutter = remember { MultipleEventsCutter.get() }
36+
37+
val interactionSource = remember { MutableInteractionSource() }
38+
val isPressed by interactionSource.collectIsPressedAsState()
39+
40+
TextButton(
41+
onClick = {
42+
if (multipleEventsCutterEnabled) {
43+
multipleEventsCutter.processEvent { onClick() }
44+
} else {
45+
onClick()
46+
}
47+
},
48+
modifier = modifier,
49+
enabled = enabled,
50+
colors = ButtonDefaults.textButtonColors(
51+
containerColor = colorStyle.containerColor(isPressed),
52+
contentColor = colorStyle.contentColor(),
53+
disabledContentColor = colorStyle.disabledContentColor(),
54+
disabledContainerColor = colorStyle.disabledContainerColor(),
55+
),
56+
contentPadding = sizeStyle.paddingValues,
57+
) {
58+
Column(
59+
modifier = Modifier.width(IntrinsicSize.Max),
60+
verticalArrangement = Arrangement.spacedBy(1.dp),
61+
) {
62+
Text(
63+
text = text,
64+
style = sizeStyle.textStyle.copy(
65+
color = if (enabled) colorStyle.contentColor() else colorStyle.disabledContentColor(),
66+
),
67+
)
68+
HorizontalDivider(
69+
thickness = 1.dp,
70+
color = if (enabled) colorStyle.contentColor() else Color.Transparent,
71+
)
72+
}
73+
}
74+
}
75+
76+
@ComponentPreview
77+
@Composable
78+
private fun ReedTextButtonPreview() {
79+
Column(
80+
modifier = Modifier.padding(20.dp),
81+
verticalArrangement = Arrangement.spacedBy(20.dp),
82+
) {
83+
FlowRow(
84+
horizontalArrangement = Arrangement.spacedBy(20.dp),
85+
verticalArrangement = Arrangement.spacedBy(20.dp),
86+
) {
87+
ReedTextButton(
88+
onClick = {},
89+
colorStyle = ReedButtonColorStyle.TEXT,
90+
sizeStyle = largeButtonStyle,
91+
text = "text button",
92+
)
93+
94+
ReedTextButton(
95+
onClick = {},
96+
enabled = false,
97+
colorStyle = ReedButtonColorStyle.TEXT,
98+
sizeStyle = largeButtonStyle,
99+
text = "text button",
100+
)
101+
}
102+
}
103+
}

core/designsystem/src/main/res/values/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@
33
<string name="server_error_message">이용에 불편을 드려 죄송합니다.\n잠시후 다시 이용해주세요.</string>
44
<string name="unknown_error_message">알 수 없는 오류가 발생하였습니다.</string>
55
<string name="search_book_hint">도서 검색 후 내 서재에 담아보세요</string>
6+
<string name="login_required">로그인이 필요한 기능입니다</string>
67
</resources>

core/model/src/main/kotlin/com/ninecraft/booket/core/model/BookSearchModel.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,11 @@ data class BookSummaryModel(
2727
val link: String = "",
2828
val userBookStatus: String = "",
2929
val key: String = "",
30-
)
30+
) {
31+
val isRegistered: Boolean
32+
get() = userBookStatus != BEFORE_REGISTRATION
33+
34+
companion object {
35+
const val BEFORE_REGISTRATION = "BEFORE_REGISTRATION"
36+
}
37+
}

0 commit comments

Comments
 (0)