Skip to content

Commit

Permalink
Merge pull request #93 from team-JMT/feat/all_search
Browse files Browse the repository at this point in the history
All Search 식당 데이터 작업
  • Loading branch information
soopeach authored Mar 12, 2024
2 parents 9c20c23 + 70d66b3 commit 52a23d0
Show file tree
Hide file tree
Showing 50 changed files with 2,067 additions and 39 deletions.
58 changes: 58 additions & 0 deletions data/src/main/java/org/gdsc/data/LocalHistoryDataStore.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package org.gdsc.data

import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import javax.inject.Inject

val Context.historyDataStore: DataStore<Preferences> by preferencesDataStore(name = "history")

class LocalHistoryDataStore @Inject constructor(private val context: Context) {
private val searchedKeywordKey = stringPreferencesKey("accessToken")

suspend fun updateSearchedKeyword(newKeyword: String): List<String> {
val previous = getSearchedKeywordToken()?.toConvertedList() ?: emptyList()
val newHistories = (previous + newKeyword).distinct().toConvertedString()
updateSearchedKeywordToken(newHistories)
return newHistories.toConvertedList()
}

suspend fun getSearchedKeyword() = getSearchedKeywordToken()?.toConvertedList() ?: emptyList()

suspend fun deleteSearchedKeyword(targetKeyword: String): List<String> {
val previous = getSearchedKeywordToken()?.toConvertedList() ?: emptyList()
val newHistories = previous.filter { it != targetKeyword }.toConvertedString()
updateSearchedKeywordToken(newHistories)
return newHistories.toConvertedList()
}

suspend fun initSearchedKeyword(): List<String> {
updateSearchedKeywordToken(emptyList<String>().toConvertedString())
return emptyList()
}

private suspend fun getSearchedKeywordToken() = context.historyDataStore.data
.map { preferences ->
preferences[searchedKeywordKey]
}.first()

private suspend fun updateSearchedKeywordToken(newKeywords: String) {
context.historyDataStore.edit { preferences ->
preferences[searchedKeywordKey] = newKeywords
}
}

private fun List<String>.toConvertedString(): String {
return this.toString().replace("[", "").replace("]", "")
}

private fun String.toConvertedList(): List<String> {
return this.split(",").map { it.trim() }
}

}
Original file line number Diff line number Diff line change
@@ -1,26 +1,22 @@
package org.gdsc.data.database

import android.util.Log
import androidx.paging.PagingSource
import androidx.paging.PagingState
import androidx.room.PrimaryKey
import kotlinx.coroutines.CoroutineScope
import org.gdsc.data.model.RegisteredRestaurantResponse
import org.gdsc.data.model.Response
import org.gdsc.data.network.RestaurantAPI
import org.gdsc.domain.model.request.RestaurantSearchMapRequest
import org.gdsc.domain.model.request.RestaurantSearchRequest

class RestaurantByMapPagingSource(
private val api: RestaurantAPI,
private val restaurantSearchMapRequest: RestaurantSearchMapRequest,
private val restaurantSearchRequest: RestaurantSearchRequest,
): PagingSource<Int, RegisteredRestaurantResponse>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, RegisteredRestaurantResponse> {
val page = params.key ?: 1
return try {
val items = api.getRestaurantLocationInfoByMap(
page = page,
size = params.loadSize,
restaurantSearchMapRequest = restaurantSearchMapRequest
restaurantSearchRequest = restaurantSearchRequest
)
LoadResult.Page(
data = items.data.restaurants,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.gdsc.data.database

import androidx.paging.PagingSource
import androidx.paging.PagingState
import org.gdsc.data.model.RegisteredRestaurantResponse
import org.gdsc.data.network.RestaurantAPI
import org.gdsc.domain.model.request.RestaurantSearchRequest

class RestaurantBySearchPagingSource(
private val api: RestaurantAPI,
private val restaurantSearchRequest: RestaurantSearchRequest,
): PagingSource<Int, RegisteredRestaurantResponse>() {
override fun getRefreshKey(state: PagingState<Int, RegisteredRestaurantResponse>): Int? {
return state.anchorPosition?.let { anchorPosition ->
val anchorPage = state.closestPageToPosition(anchorPosition)
anchorPage?.prevKey?.plus(1) ?: anchorPage?.nextKey?.minus(1)
}
}

override suspend fun load(params: LoadParams<Int>): LoadResult<Int, RegisteredRestaurantResponse> {
val page = params.key ?: 1
return try {
val items = api.getRegisteredRestaurantsBySearch(
restaurantSearchRequest = restaurantSearchRequest
)
LoadResult.Page(
data = items.data.restaurants,
prevKey = null,
nextKey = if (items.data.restaurants.isEmpty()) null else page + 1
)
} catch (e: Exception) {
return LoadResult.Error(e)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ import androidx.paging.PagingState
import androidx.paging.RemoteMediator
import androidx.room.withTransaction
import org.gdsc.data.network.RestaurantAPI
import org.gdsc.domain.model.request.RestaurantSearchMapRequest
import org.gdsc.domain.model.request.RestaurantSearchRequest
import retrofit2.HttpException
import java.io.IOException

@OptIn(ExperimentalPagingApi::class)
class RestaurantMediator(
private val userId: Int,
private val restaurantSearchMapRequest: RestaurantSearchMapRequest,
private val restaurantSearchRequest: RestaurantSearchRequest,
private val db: RestaurantDatabase,
private val api: RestaurantAPI,
): RemoteMediator<Int,RegisteredRestaurant>() {
Expand Down Expand Up @@ -47,7 +47,7 @@ class RestaurantMediator(
userId = userId,
page = currentPageNumber,
size = state.config.pageSize,
restaurantSearchMapRequest = restaurantSearchMapRequest
restaurantSearchRequest = restaurantSearchRequest
)

val repos = response.data
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import org.gdsc.domain.model.RestaurantLocationInfo
import org.gdsc.domain.model.UserLocation
import org.gdsc.domain.model.request.ModifyRestaurantInfoRequest
import org.gdsc.domain.model.request.RestaurantRegistrationRequest
import org.gdsc.domain.model.request.RestaurantSearchMapRequest
import org.gdsc.domain.model.response.RestaurantInfoResponse

interface RestaurantDataSource {
Expand Down Expand Up @@ -43,6 +42,10 @@ interface RestaurantDataSource {
userLocation: Location?, startLocation: Location?, endLocation: Location?, sortType: SortType, foodCategory: FoodCategory?, drinkPossibility: DrinkPossibility?
): Flow<PagingData<RegisteredRestaurantResponse>>

suspend fun getRegisteredRestaurantsBySearch(keyword: String?, userLocation: Location?): Flow<PagingData<RegisteredRestaurantResponse>>

suspend fun getRegisteredRestaurantsBySearchWithLimitCount(keyword: String?, userLocation: Location?, limit: Int): List<RegisteredRestaurantResponse>

suspend fun getRestaurantReviews(restaurantId: Int): ReviewPaging

suspend fun postRestaurantReview(restaurantId: Int, reviewContent: String, reviewImages: List<MultipartBody.Part>): Boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import org.gdsc.data.database.RegisteredRestaurant
import org.gdsc.data.database.RestaurantByMapPagingSource
import org.gdsc.data.database.RestaurantBySearchPagingSource
import org.gdsc.data.database.RestaurantDatabase
import org.gdsc.data.database.RestaurantMediator
import org.gdsc.data.database.ReviewPaging
Expand All @@ -32,7 +33,7 @@ import org.gdsc.domain.model.RestaurantLocationInfo
import org.gdsc.domain.model.UserLocation
import org.gdsc.domain.model.request.ModifyRestaurantInfoRequest
import org.gdsc.domain.model.request.RestaurantRegistrationRequest
import org.gdsc.domain.model.request.RestaurantSearchMapRequest
import org.gdsc.domain.model.request.RestaurantSearchRequest
import org.gdsc.domain.model.response.RestaurantInfoResponse
import retrofit2.HttpException
import javax.inject.Inject
Expand Down Expand Up @@ -148,10 +149,10 @@ class RestaurantDataSourceImpl @Inject constructor(
isCanDrinkLiquor = isCanDrinkLiquor,
)

val restaurantSearchMapRequest = RestaurantSearchMapRequest(filter, locationData)
val restaurantSearchRequest = RestaurantSearchRequest(filter, locationData)
val mediator = RestaurantMediator(
userId = userId,
restaurantSearchMapRequest = restaurantSearchMapRequest,
restaurantSearchRequest = restaurantSearchRequest,
db = db,
api = restaurantAPI,
)
Expand Down Expand Up @@ -204,7 +205,7 @@ class RestaurantDataSourceImpl @Inject constructor(
foodCategory: FoodCategory?,
drinkPossibility: DrinkPossibility?
): Flow<PagingData<RegisteredRestaurantResponse>> {
val restaurantSearchMapRequest = RestaurantSearchMapRequest(
val restaurantSearchRequest = RestaurantSearchRequest(
userLocation = userLocation,
startLocation = startLocation,
endLocation = endLocation,
Expand All @@ -229,11 +230,45 @@ class RestaurantDataSourceImpl @Inject constructor(
) {
RestaurantByMapPagingSource(
restaurantAPI,
restaurantSearchMapRequest
restaurantSearchRequest
)
}.flow.cachedIn(coroutineScope)
}

override suspend fun getRegisteredRestaurantsBySearch(
keyword: String?, userLocation: Location?
): Flow<PagingData<RegisteredRestaurantResponse>> {
return Pager(
config = PagingConfig(
pageSize = 20,
enablePlaceholders = true
)
) {
RestaurantBySearchPagingSource(
restaurantAPI,
RestaurantSearchRequest(
keyword = keyword,
userLocation = userLocation
)
)
}.flow.cachedIn(coroutineScope)
}

override suspend fun getRegisteredRestaurantsBySearchWithLimitCount(
keyword: String?,
userLocation: Location?,
limit: Int
): List<RegisteredRestaurantResponse> {

return restaurantAPI.
getRegisteredRestaurantsBySearch(
RestaurantSearchRequest(
keyword = keyword,
userLocation = userLocation
)
).data.restaurants.take(limit)
}

override suspend fun getRestaurantReviews(restaurantId: Int): ReviewPaging {
return restaurantAPI.getRestaurantReviews(restaurantId).data
}
Expand Down
8 changes: 8 additions & 0 deletions data/src/main/java/org/gdsc/data/datasource/UserDataSource.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,12 @@ interface UserDataSource {
suspend fun postUserLogout(refreshToken: String): String

suspend fun postUserSignout(): String

suspend fun getSearchedKeywords(): List<String>

suspend fun updateSearchedKeyword(newKeyword: String): List<String>

suspend fun deleteSearchedKeyword(targetKeyword: String): List<String>

suspend fun initSearchedKeyword(): List<String>
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.gdsc.data.datasource

import okhttp3.MultipartBody
import org.gdsc.data.LocalHistoryDataStore
import org.gdsc.data.network.UserAPI
import org.gdsc.domain.model.Response
import org.gdsc.domain.model.request.NicknameRequest
Expand All @@ -11,7 +12,8 @@ import retrofit2.HttpException
import javax.inject.Inject

class UserDataSourceImpl @Inject constructor(
private val userAPI: UserAPI
private val userAPI: UserAPI,
private val localHistoryDataStore: LocalHistoryDataStore
) : UserDataSource {
override suspend fun postNickname(nicknameRequest: NicknameRequest): NicknameResponse {
return userAPI.postNickname(nicknameRequest).data
Expand Down Expand Up @@ -69,4 +71,20 @@ class UserDataSourceImpl @Inject constructor(
override suspend fun postUserSignout(): String {
return userAPI.postUserSignOut().code
}

override suspend fun getSearchedKeywords(): List<String> {
return localHistoryDataStore.getSearchedKeyword()
}

override suspend fun updateSearchedKeyword(newKeyword: String): List<String> {
return localHistoryDataStore.updateSearchedKeyword(newKeyword)
}

override suspend fun deleteSearchedKeyword(targetKeyword: String): List<String> {
return localHistoryDataStore.deleteSearchedKeyword(targetKeyword)
}

override suspend fun initSearchedKeyword(): List<String> {
return localHistoryDataStore.initSearchedKeyword()
}
}
5 changes: 5 additions & 0 deletions data/src/main/java/org/gdsc/data/di/DatabaseModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import org.gdsc.data.LocalHistoryDataStore
import org.gdsc.data.database.RestaurantDatabase
import javax.inject.Singleton

Expand All @@ -24,4 +25,8 @@ class DatabaseModule {
@Singleton
@Provides
fun provideRestaurantDao(database: RestaurantDatabase) = database.restaurantDao()

@Singleton
@Provides
fun provideHistoryDataStore(@ApplicationContext context: Context) = LocalHistoryDataStore(context)
}
11 changes: 8 additions & 3 deletions data/src/main/java/org/gdsc/data/network/RestaurantAPI.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import org.gdsc.data.database.ReviewPaging
import org.gdsc.data.model.Response
import org.gdsc.domain.model.RestaurantLocationInfo
import org.gdsc.domain.model.UserLocation
import org.gdsc.domain.model.request.RestaurantSearchMapRequest
import org.gdsc.domain.model.request.RestaurantSearchRequest
import org.gdsc.domain.model.request.ModifyRestaurantInfoRequest
import org.gdsc.domain.model.response.RestaurantInfoResponse
import org.gdsc.domain.model.response.RestaurantRegistrationResponse
Expand Down Expand Up @@ -54,13 +54,18 @@ interface RestaurantAPI {
@Part pictures: List<MultipartBody.Part>,
): Response<RestaurantRegistrationResponse>

@POST("api/v1/restaurant/search")
suspend fun getRegisteredRestaurantsBySearch(
@Body restaurantSearchRequest: RestaurantSearchRequest,
): Response<RegisteredRestaurantPaging>

@POST("api/v1/restaurant/search/{userid}")
suspend fun getRegisteredRestaurants(
@Path("userid") userId: Int,
@Query("page") page: Int? = null,
@Query("size") size: Int? = null,
@Query("sort") sort: String? = null,
@Body restaurantSearchMapRequest: RestaurantSearchMapRequest,
@Body restaurantSearchRequest: RestaurantSearchRequest,
): Response<RegisteredRestaurantPaging>

@PUT("api/v1/restaurant")
Expand All @@ -73,7 +78,7 @@ interface RestaurantAPI {
@Query("page") page: Int? = null,
@Query("size") size: Int? = null,
@Query("sort") sort: Array<String>? = null,
@Body restaurantSearchMapRequest: RestaurantSearchMapRequest,
@Body restaurantSearchRequest: RestaurantSearchRequest,
): Response<RegisteredRestaurantPaging>

@GET("/api/v1/restaurant/{recommendRestaurantId}/review")
Expand Down
Loading

0 comments on commit 52a23d0

Please sign in to comment.