Skip to content

Commit b00143f

Browse files
committed
[BOOK-151] feat: 최근 검색어 저장을 위한 DataStore 구축
1 parent f6ac5a6 commit b00143f

File tree

5 files changed

+102
-1
lines changed

5 files changed

+102
-1
lines changed

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,26 @@ 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
67
import com.ninecraft.booket.core.network.request.BookUpsertRequest
78
import com.ninecraft.booket.core.network.service.ReedService
89
import javax.inject.Inject
910

1011
internal class DefaultBookRepository @Inject constructor(
1112
private val service: ReedService,
13+
private val dataSource: RecentSearchDataSource,
1214
) : BookRepository {
1315
override suspend fun searchBook(
1416
query: String,
1517
start: Int,
1618
) = runSuspendCatching {
17-
service.searchBook(
19+
val result = service.searchBook(
1820
query = query,
1921
start = start,
2022
).toModel()
23+
24+
dataSource.addRecentSearch(query)
25+
result
2126
}
2227

2328
override suspend fun getBookDetail(itemId: String) = runSuspendCatching {
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.ninecraft.booket.core.datastore.api.datasource
2+
3+
import kotlinx.coroutines.flow.Flow
4+
5+
interface RecentSearchDataSource {
6+
val recentSearches: Flow<List<String>>
7+
suspend fun addRecentSearch(query: String)
8+
suspend fun removeRecentSearch(query: String)
9+
suspend fun clearRecentSearches()
10+
}

core/datastore/impl/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
plugins {
44
alias(libs.plugins.booket.android.library)
55
alias(libs.plugins.booket.android.hilt)
6+
alias(libs.plugins.booket.kotlin.library.serialization)
67
}
78

89
android {
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
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.RecentSearchDataSource
8+
import com.ninecraft.booket.core.datastore.impl.util.handleIOException
9+
import kotlinx.coroutines.flow.Flow
10+
import kotlinx.coroutines.flow.map
11+
import kotlinx.serialization.json.Json
12+
import javax.inject.Inject
13+
14+
class DefaultRecentSearchDataSource @Inject constructor(
15+
private val dataStore: DataStore<Preferences>,
16+
) : RecentSearchDataSource {
17+
override val recentSearches: Flow<List<String>> = dataStore.data
18+
.handleIOException()
19+
.map { prefs ->
20+
prefs[RECENT_SEARCHES]?.let { jsonString ->
21+
try {
22+
Json.decodeFromString<List<String>>(jsonString)
23+
} catch (e: Exception) {
24+
emptyList()
25+
}
26+
} ?: emptyList()
27+
}
28+
29+
override suspend fun addRecentSearch(query: String) {
30+
if (query.isBlank()) return
31+
32+
dataStore.edit { prefs ->
33+
val currentSearches = prefs[RECENT_SEARCHES]?.let { jsonString ->
34+
try {
35+
Json.decodeFromString<List<String>>(jsonString).toMutableList()
36+
} catch (e: Exception) {
37+
mutableListOf()
38+
}
39+
} ?: mutableListOf()
40+
41+
// 기존에 있으면 제거 (upsert 로직)
42+
currentSearches.remove(query)
43+
// 맨 앞에 추가 (가장 최근 검색어)
44+
currentSearches.add(0, query)
45+
46+
// 최근 10개만 유지
47+
val limitedSearches = currentSearches.take(MAX_SEARCH_COUNT)
48+
prefs[RECENT_SEARCHES] = Json.encodeToString(limitedSearches)
49+
}
50+
}
51+
52+
override suspend fun removeRecentSearch(query: String) {
53+
dataStore.edit { prefs ->
54+
val currentSearches = prefs[RECENT_SEARCHES]?.let { jsonString ->
55+
try {
56+
Json.decodeFromString<List<String>>(jsonString).toMutableList()
57+
} catch (e: Exception) {
58+
mutableListOf()
59+
}
60+
} ?: mutableListOf()
61+
62+
currentSearches.remove(query)
63+
prefs[RECENT_SEARCHES] = Json.encodeToString(currentSearches)
64+
}
65+
}
66+
67+
override suspend fun clearRecentSearches() {
68+
dataStore.edit { prefs ->
69+
prefs.remove(RECENT_SEARCHES)
70+
}
71+
}
72+
73+
companion object {
74+
private val RECENT_SEARCHES = stringPreferencesKey("RECENT_SEARCHES")
75+
private const val MAX_SEARCH_COUNT = 10
76+
}
77+
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ 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.RecentSearchDataSource
78
import com.ninecraft.booket.core.datastore.api.datasource.TokenPreferencesDataSource
9+
import com.ninecraft.booket.core.datastore.impl.datasource.DefaultRecentSearchDataSource
810
import com.ninecraft.booket.core.datastore.impl.datasource.DefaultTokenPreferencesDataSource
911
import dagger.Binds
1012
import dagger.Module
@@ -36,4 +38,10 @@ abstract class DataStoreBindModule {
3638
abstract fun bindTokenPreferencesDataSource(
3739
defaultTokenPreferencesDataSource: DefaultTokenPreferencesDataSource,
3840
): TokenPreferencesDataSource
41+
42+
@Binds
43+
@Singleton
44+
abstract fun bindRecentSearchDataSource(
45+
defaultRecentSearchDataSource: DefaultRecentSearchDataSource,
46+
): RecentSearchDataSource
3947
}

0 commit comments

Comments
 (0)