Skip to content

Commit 6a940c4

Browse files
committed
Merge branch 'develop' into BOOK-212-feature/#98
# Conflicts: # core/data/api/src/main/kotlin/com/ninecraft/booket/core/data/api/repository/BookRepository.kt # core/data/impl/src/main/kotlin/com/ninecraft/booket/core/data/impl/repository/DefaultBookRepository.kt # feature/library/src/main/kotlin/com/ninecraft/booket/feature/library/LibraryPresenter.kt # feature/library/src/main/kotlin/com/ninecraft/booket/feature/library/LibraryUiState.kt # feature/screens/src/main/kotlin/com/ninecraft/booket/feature/screens/Screens.kt
2 parents 6eee795 + afa26ff commit 6a940c4

File tree

33 files changed

+937
-145
lines changed

33 files changed

+937
-145
lines changed

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,15 @@ import com.ninecraft.booket.core.model.LibraryModel
99
import com.ninecraft.booket.core.model.SeedModel
1010

1111
interface BookRepository {
12-
val recentSearches: Flow<List<String>>
12+
val bookRecentSearches: Flow<List<String>>
13+
val libraryRecentSearches: Flow<List<String>>
1314

1415
suspend fun searchBook(
1516
query: String,
1617
start: Int,
1718
): Result<BookSearchModel>
1819

19-
suspend fun removeRecentSearch(query: String)
20+
suspend fun removeBookRecentSearch(query: String)
2021

2122
suspend fun getBookDetail(isbn: String): Result<BookDetailModel>
2223

@@ -25,6 +26,16 @@ interface BookRepository {
2526
bookStatus: String,
2627
): Result<BookUpsertModel>
2728

29+
suspend fun filterLibraryBooks(
30+
31+
suspend fun searchLibraryBooks(
32+
title: String,
33+
page: Int,
34+
size: Int,
35+
): Result<LibraryModel>
36+
37+
suspend fun removeLibraryRecentSearch(query: String)
38+
2839
suspend fun getHome(): Result<HomeModel>
2940

3041
suspend fun getLibrary(

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ internal fun BookSearchResponse.toModel(): BookSearchModel {
6363

6464
internal fun BookSummary.toModel(): BookSummaryModel {
6565
return BookSummaryModel(
66-
isbn = isbn,
66+
isbn13 = isbn13,
6767
title = title.decodeHtmlEntities(),
6868
author = author,
6969
publisher = publisher,

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

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,19 @@ package com.ninecraft.booket.core.data.impl.repository
33
import com.ninecraft.booket.core.common.utils.runSuspendCatching
44
import com.ninecraft.booket.core.data.api.repository.BookRepository
55
import com.ninecraft.booket.core.data.impl.mapper.toModel
6-
import com.ninecraft.booket.core.datastore.api.datasource.RecentSearchDataSource
6+
import com.ninecraft.booket.core.datastore.api.datasource.BookRecentSearchDataSource
7+
import com.ninecraft.booket.core.datastore.api.datasource.LibraryRecentSearchDataSource
78
import com.ninecraft.booket.core.network.request.BookUpsertRequest
89
import com.ninecraft.booket.core.network.service.ReedService
910
import javax.inject.Inject
1011

1112
internal class DefaultBookRepository @Inject constructor(
1213
private val service: ReedService,
13-
private val dataSource: RecentSearchDataSource,
14+
private val bookRecentSearchDataSource: BookRecentSearchDataSource,
15+
private val libraryRecentSearchDataSource: LibraryRecentSearchDataSource,
1416
) : BookRepository {
15-
override val recentSearches = dataSource.recentSearches
17+
override val bookRecentSearches = bookRecentSearchDataSource.recentSearches
18+
override val libraryRecentSearches = libraryRecentSearchDataSource.recentSearches
1619

1720
override suspend fun searchBook(
1821
query: String,
@@ -23,12 +26,12 @@ internal class DefaultBookRepository @Inject constructor(
2326
start = start,
2427
).toModel()
2528

26-
dataSource.addRecentSearch(query)
29+
bookRecentSearchDataSource.addRecentSearch(query)
2730
result
2831
}
2932

30-
override suspend fun removeRecentSearch(query: String) {
31-
dataSource.removeRecentSearch(query)
33+
override suspend fun removeBookRecentSearch(query: String) {
34+
bookRecentSearchDataSource.removeRecentSearch(query)
3235
}
3336

3437
override suspend fun getBookDetail(isbn: String) = runSuspendCatching {
@@ -39,6 +42,21 @@ internal class DefaultBookRepository @Inject constructor(
3942
service.upsertBook(BookUpsertRequest(bookIsbn, bookStatus)).toModel()
4043
}
4144

45+
override suspend fun filterLibraryBooks(status: String?, page: Int, size: Int) = runSuspendCatching {
46+
service.getLibraryBooks(status, null, page, size).toModel()
47+
}
48+
49+
override suspend fun searchLibraryBooks(title: String, page: Int, size: Int) = runSuspendCatching {
50+
val result = service.getLibraryBooks(null, title, page, size).toModel()
51+
52+
libraryRecentSearchDataSource.addRecentSearch(title)
53+
result
54+
}
55+
56+
override suspend fun removeLibraryRecentSearch(query: String) {
57+
libraryRecentSearchDataSource.removeRecentSearch(query)
58+
}
59+
4260
override suspend fun getHome() = runSuspendCatching {
4361
service.getHome().toModel()
4462
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package com.ninecraft.booket.core.datastore.api.datasource
2+
3+
interface BookRecentSearchDataSource : RecentSearchDataSource
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package com.ninecraft.booket.core.datastore.api.datasource
2+
3+
interface LibraryRecentSearchDataSource : RecentSearchDataSource

core/datastore/impl/src/main/kotlin/com/ninecraft/booket/core/datastore/impl/datasource/DefaultRecentSearchDataSource.kt renamed to core/datastore/impl/src/main/kotlin/com/ninecraft/booket/core/datastore/impl/datasource/DefaultBookRecentSearchDataSource.kt

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import androidx.datastore.core.DataStore
44
import androidx.datastore.preferences.core.Preferences
55
import androidx.datastore.preferences.core.edit
66
import androidx.datastore.preferences.core.stringPreferencesKey
7-
import com.ninecraft.booket.core.datastore.api.datasource.RecentSearchDataSource
8-
import com.ninecraft.booket.core.datastore.impl.di.RecentSearchDataStore
7+
import com.ninecraft.booket.core.datastore.api.datasource.BookRecentSearchDataSource
8+
import com.ninecraft.booket.core.datastore.impl.di.BookRecentSearchDataStore
99
import com.ninecraft.booket.core.datastore.impl.util.handleIOException
1010
import com.orhanobut.logger.Logger
1111
import kotlinx.coroutines.flow.Flow
@@ -14,14 +14,14 @@ import kotlinx.serialization.SerializationException
1414
import kotlinx.serialization.json.Json
1515
import javax.inject.Inject
1616

17-
class DefaultRecentSearchDataSource @Inject constructor(
18-
@RecentSearchDataStore private val dataStore: DataStore<Preferences>,
19-
) : RecentSearchDataSource {
17+
class DefaultBookRecentSearchDataSource @Inject constructor(
18+
@BookRecentSearchDataStore private val dataStore: DataStore<Preferences>,
19+
) : BookRecentSearchDataSource {
2020
@Suppress("TooGenericExceptionCaught")
2121
override val recentSearches: Flow<List<String>> = dataStore.data
2222
.handleIOException()
2323
.map { prefs ->
24-
prefs[RECENT_SEARCHES]?.let { jsonString ->
24+
prefs[BOOK_RECENT_SEARCHES]?.let { jsonString ->
2525
try {
2626
Json.decodeFromString<List<String>>(jsonString)
2727
} catch (e: SerializationException) {
@@ -39,7 +39,7 @@ class DefaultRecentSearchDataSource @Inject constructor(
3939
if (query.isBlank()) return
4040

4141
dataStore.edit { prefs ->
42-
val currentSearches = prefs[RECENT_SEARCHES]?.let { jsonString ->
42+
val currentSearches = prefs[BOOK_RECENT_SEARCHES]?.let { jsonString ->
4343
try {
4444
Json.decodeFromString<List<String>>(jsonString).toMutableList()
4545
} catch (e: SerializationException) {
@@ -59,7 +59,7 @@ class DefaultRecentSearchDataSource @Inject constructor(
5959
// 최근 10개만 유지
6060
val limitedSearches = currentSearches.take(MAX_SEARCH_COUNT)
6161
try {
62-
prefs[RECENT_SEARCHES] = Json.encodeToString(limitedSearches)
62+
prefs[BOOK_RECENT_SEARCHES] = Json.encodeToString(limitedSearches)
6363
} catch (e: SerializationException) {
6464
Logger.e(e, "Failed to serialize recent searches")
6565
}
@@ -69,7 +69,7 @@ class DefaultRecentSearchDataSource @Inject constructor(
6969
@Suppress("TooGenericExceptionCaught")
7070
override suspend fun removeRecentSearch(query: String) {
7171
dataStore.edit { prefs ->
72-
val currentSearches = prefs[RECENT_SEARCHES]?.let { jsonString ->
72+
val currentSearches = prefs[BOOK_RECENT_SEARCHES]?.let { jsonString ->
7373
try {
7474
Json.decodeFromString<List<String>>(jsonString).toMutableList()
7575
} catch (e: SerializationException) {
@@ -83,7 +83,7 @@ class DefaultRecentSearchDataSource @Inject constructor(
8383

8484
currentSearches.remove(query)
8585
try {
86-
prefs[RECENT_SEARCHES] = Json.encodeToString(currentSearches)
86+
prefs[BOOK_RECENT_SEARCHES] = Json.encodeToString(currentSearches)
8787
} catch (e: SerializationException) {
8888
Logger.e(e, "Failed to serialize recent searches after removal")
8989
}
@@ -92,12 +92,12 @@ class DefaultRecentSearchDataSource @Inject constructor(
9292

9393
override suspend fun clearRecentSearches() {
9494
dataStore.edit { prefs ->
95-
prefs.remove(RECENT_SEARCHES)
95+
prefs.remove(BOOK_RECENT_SEARCHES)
9696
}
9797
}
9898

9999
companion object {
100-
private val RECENT_SEARCHES = stringPreferencesKey("RECENT_SEARCHES")
100+
private val BOOK_RECENT_SEARCHES = stringPreferencesKey("BOOK_RECENT_SEARCHES")
101101
private const val MAX_SEARCH_COUNT = 10
102102
}
103103
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package com.ninecraft.booket.core.datastore.impl.datasource
2+
3+
import androidx.datastore.core.DataStore
4+
import androidx.datastore.preferences.core.Preferences
5+
import androidx.datastore.preferences.core.edit
6+
import androidx.datastore.preferences.core.stringPreferencesKey
7+
import com.ninecraft.booket.core.datastore.api.datasource.LibraryRecentSearchDataSource
8+
import com.ninecraft.booket.core.datastore.impl.di.LibraryRecentSearchDataStore
9+
import com.ninecraft.booket.core.datastore.impl.util.handleIOException
10+
import com.orhanobut.logger.Logger
11+
import kotlinx.coroutines.flow.Flow
12+
import kotlinx.coroutines.flow.map
13+
import kotlinx.serialization.SerializationException
14+
import kotlinx.serialization.json.Json
15+
import javax.inject.Inject
16+
17+
class DefaultLibraryRecentSearchDataSource @Inject constructor(
18+
@LibraryRecentSearchDataStore private val dataStore: DataStore<Preferences>,
19+
) : LibraryRecentSearchDataSource {
20+
@Suppress("TooGenericExceptionCaught")
21+
override val recentSearches: Flow<List<String>> = dataStore.data
22+
.handleIOException()
23+
.map { prefs ->
24+
prefs[LIBRARY_RECENT_SEARCHES]?.let { jsonString ->
25+
try {
26+
Json.decodeFromString<List<String>>(jsonString)
27+
} catch (e: SerializationException) {
28+
Logger.e(e, "Failed to deserialize recent searches")
29+
emptyList()
30+
} catch (e: Exception) {
31+
Logger.e(e, "Unexpected error while reading recent searches")
32+
emptyList()
33+
}
34+
} ?: emptyList()
35+
}
36+
37+
@Suppress("TooGenericExceptionCaught")
38+
override suspend fun addRecentSearch(query: String) {
39+
if (query.isBlank()) return
40+
41+
dataStore.edit { prefs ->
42+
val currentSearches = prefs[LIBRARY_RECENT_SEARCHES]?.let { jsonString ->
43+
try {
44+
Json.decodeFromString<List<String>>(jsonString).toMutableList()
45+
} catch (e: SerializationException) {
46+
Logger.e(e, "Failed to deserialize recent searches for adding")
47+
mutableListOf()
48+
} catch (e: Exception) {
49+
Logger.e(e, "Unexpected error while adding recent search")
50+
mutableListOf()
51+
}
52+
} ?: mutableListOf()
53+
54+
// 기존에 있으면 제거 (upsert 로직)
55+
currentSearches.remove(query)
56+
// 맨 앞에 추가 (가장 최근 검색어)
57+
currentSearches.add(0, query)
58+
59+
// 최근 10개만 유지
60+
val limitedSearches = currentSearches.take(MAX_SEARCH_COUNT)
61+
try {
62+
prefs[LIBRARY_RECENT_SEARCHES] = Json.encodeToString(limitedSearches)
63+
} catch (e: SerializationException) {
64+
Logger.e(e, "Failed to serialize recent searches")
65+
}
66+
}
67+
}
68+
69+
@Suppress("TooGenericExceptionCaught")
70+
override suspend fun removeRecentSearch(query: String) {
71+
dataStore.edit { prefs ->
72+
val currentSearches = prefs[LIBRARY_RECENT_SEARCHES]?.let { jsonString ->
73+
try {
74+
Json.decodeFromString<List<String>>(jsonString).toMutableList()
75+
} catch (e: SerializationException) {
76+
Logger.e(e, "Failed to deserialize recent searches for removal")
77+
mutableListOf()
78+
} catch (e: Exception) {
79+
Logger.e(e, "Unexpected error while removing recent search")
80+
mutableListOf()
81+
}
82+
} ?: mutableListOf()
83+
84+
currentSearches.remove(query)
85+
try {
86+
prefs[LIBRARY_RECENT_SEARCHES] = Json.encodeToString(currentSearches)
87+
} catch (e: SerializationException) {
88+
Logger.e(e, "Failed to serialize recent searches after removal")
89+
}
90+
}
91+
}
92+
93+
override suspend fun clearRecentSearches() {
94+
dataStore.edit { prefs ->
95+
prefs.remove(LIBRARY_RECENT_SEARCHES)
96+
}
97+
}
98+
99+
companion object {
100+
private val LIBRARY_RECENT_SEARCHES = stringPreferencesKey("LIBRARY_RECENT_SEARCHES")
101+
private const val MAX_SEARCH_COUNT = 10
102+
}
103+
}

core/datastore/impl/src/main/kotlin/com/ninecraft/booket/core/datastore/impl/di/DataStoreModule.kt

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ import android.content.Context
44
import androidx.datastore.core.DataStore
55
import androidx.datastore.preferences.core.Preferences
66
import androidx.datastore.preferences.preferencesDataStore
7+
import com.ninecraft.booket.core.datastore.api.datasource.BookRecentSearchDataSource
8+
import com.ninecraft.booket.core.datastore.api.datasource.LibraryRecentSearchDataSource
79
import com.ninecraft.booket.core.datastore.api.datasource.OnboardingDataSource
8-
import com.ninecraft.booket.core.datastore.api.datasource.RecentSearchDataSource
910
import com.ninecraft.booket.core.datastore.api.datasource.TokenDataSource
11+
import com.ninecraft.booket.core.datastore.impl.datasource.DefaultLibraryRecentSearchDataSource
1012
import com.ninecraft.booket.core.datastore.impl.datasource.DefaultOnboardingDataSource
11-
import com.ninecraft.booket.core.datastore.impl.datasource.DefaultRecentSearchDataSource
13+
import com.ninecraft.booket.core.datastore.impl.datasource.DefaultBookRecentSearchDataSource
1214
import com.ninecraft.booket.core.datastore.impl.datasource.DefaultTokenDataSource
1315
import dagger.Binds
1416
import dagger.Module
@@ -22,11 +24,13 @@ import javax.inject.Singleton
2224
@InstallIn(SingletonComponent::class)
2325
object DataStoreModule {
2426
private const val TOKEN_DATASTORE_NAME = "TOKENS_DATASTORE"
25-
private const val RECENT_SEARCH_DATASTORE_NAME = "RECENT_SEARCH_DATASTORE"
27+
private const val BOOK_RECENT_SEARCH_DATASTORE_NAME = "BOOK_RECENT_SEARCH_DATASTORE"
28+
private const val LIBRARY_RECENT_SEARCH_DATASTORE_NAME = "LIBRARY_RECENT_SEARCH_DATASTORE"
2629
private const val ONBOARDING_DATASTORE_NAME = "ONBOARDING_DATASTORE"
2730

2831
private val Context.tokenDataStore by preferencesDataStore(name = TOKEN_DATASTORE_NAME)
29-
private val Context.recentSearchDataStore by preferencesDataStore(name = RECENT_SEARCH_DATASTORE_NAME)
32+
private val Context.bookRecentSearchDataStore by preferencesDataStore(name = BOOK_RECENT_SEARCH_DATASTORE_NAME)
33+
private val Context.libraryRecentSearchDataStore by preferencesDataStore(name = LIBRARY_RECENT_SEARCH_DATASTORE_NAME)
3034
private val Context.onboardingDataStore by preferencesDataStore(name = ONBOARDING_DATASTORE_NAME)
3135

3236
@TokenDataStore
@@ -36,12 +40,19 @@ object DataStoreModule {
3640
@ApplicationContext context: Context,
3741
): DataStore<Preferences> = context.tokenDataStore
3842

39-
@RecentSearchDataStore
43+
@BookRecentSearchDataStore
4044
@Provides
4145
@Singleton
42-
fun provideRecentSearchDataStore(
46+
fun provideBookRecentSearchDataStore(
4347
@ApplicationContext context: Context,
44-
): DataStore<Preferences> = context.recentSearchDataStore
48+
): DataStore<Preferences> = context.bookRecentSearchDataStore
49+
50+
@LibraryRecentSearchDataStore
51+
@Provides
52+
@Singleton
53+
fun provideLibraryRecentSearchDataStore(
54+
@ApplicationContext context: Context,
55+
): DataStore<Preferences> = context.libraryRecentSearchDataStore
4556

4657
@OnboardingDataStore
4758
@Provides
@@ -63,9 +74,15 @@ abstract class DataStoreBindModule {
6374

6475
@Binds
6576
@Singleton
66-
abstract fun bindRecentSearchDataSource(
67-
defaultRecentSearchDataSource: DefaultRecentSearchDataSource,
68-
): RecentSearchDataSource
77+
abstract fun bindBookRecentSearchDataSource(
78+
defaultBookRecentSearchDataSource: DefaultBookRecentSearchDataSource,
79+
): BookRecentSearchDataSource
80+
81+
@Binds
82+
@Singleton
83+
abstract fun bindLibraryRecentSearchDataSource(
84+
defaultLibraryRecentSearchDataSource: DefaultLibraryRecentSearchDataSource,
85+
): LibraryRecentSearchDataSource
6986

7087
@Binds
7188
@Singleton

core/datastore/impl/src/main/kotlin/com/ninecraft/booket/core/datastore/impl/di/DataStoreQualifier.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@ annotation class TokenDataStore
88

99
@Qualifier
1010
@Retention(AnnotationRetention.BINARY)
11-
annotation class RecentSearchDataStore
11+
annotation class BookRecentSearchDataStore
12+
13+
@Qualifier
14+
@Retention(AnnotationRetention.BINARY)
15+
annotation class LibraryRecentSearchDataStore
1216

1317
@Qualifier
1418
@Retention(AnnotationRetention.BINARY)

0 commit comments

Comments
 (0)