diff --git a/data/src/main/java/org/gdsc/data/database/GroupPaging.kt b/data/src/main/java/org/gdsc/data/database/GroupPaging.kt new file mode 100644 index 00000000..17145cea --- /dev/null +++ b/data/src/main/java/org/gdsc/data/database/GroupPaging.kt @@ -0,0 +1,8 @@ +package org.gdsc.data.database + +import org.gdsc.domain.model.GroupPreview + +data class GroupPaging( + val groupList: List, + val page: Page +) \ No newline at end of file diff --git a/data/src/main/java/org/gdsc/data/datasource/GroupDataSource.kt b/data/src/main/java/org/gdsc/data/datasource/GroupDataSource.kt index d6c2680d..8653d6e9 100644 --- a/data/src/main/java/org/gdsc/data/datasource/GroupDataSource.kt +++ b/data/src/main/java/org/gdsc/data/datasource/GroupDataSource.kt @@ -1,5 +1,6 @@ package org.gdsc.data.datasource +import org.gdsc.domain.model.GroupPreview import org.gdsc.domain.model.response.Group @@ -7,4 +8,6 @@ interface GroupDataSource { suspend fun getMyGroups(): List suspend fun selectGroup(groupId: Int): String + + suspend fun searchGroup(keyword: String, limitCount: Int): List } \ No newline at end of file diff --git a/data/src/main/java/org/gdsc/data/datasource/GroupDataSourceImpl.kt b/data/src/main/java/org/gdsc/data/datasource/GroupDataSourceImpl.kt index 9dc80400..5ce7b982 100644 --- a/data/src/main/java/org/gdsc/data/datasource/GroupDataSourceImpl.kt +++ b/data/src/main/java/org/gdsc/data/datasource/GroupDataSourceImpl.kt @@ -1,7 +1,10 @@ package org.gdsc.data.datasource import android.util.Log +import org.gdsc.data.database.GroupPaging import org.gdsc.data.network.GroupAPI +import org.gdsc.domain.model.GroupPreview +import org.gdsc.domain.model.request.GroupSearchRequest import org.gdsc.domain.model.response.Group import javax.inject.Inject @@ -29,4 +32,8 @@ class GroupDataSourceImpl @Inject constructor( } return "" } + + override suspend fun searchGroup(keyword: String, limitCount: Int): List { + return groupAPI.searchGroup(GroupSearchRequest(keyword)).data.groupList.take(limitCount) + } } \ No newline at end of file diff --git a/data/src/main/java/org/gdsc/data/network/GroupAPI.kt b/data/src/main/java/org/gdsc/data/network/GroupAPI.kt index 4cbdd088..acbff774 100644 --- a/data/src/main/java/org/gdsc/data/network/GroupAPI.kt +++ b/data/src/main/java/org/gdsc/data/network/GroupAPI.kt @@ -1,7 +1,10 @@ package org.gdsc.data.network +import org.gdsc.data.database.GroupPaging import org.gdsc.data.model.Response +import org.gdsc.domain.model.request.GroupSearchRequest import org.gdsc.domain.model.response.Group +import retrofit2.http.Body import retrofit2.http.GET import retrofit2.http.POST import retrofit2.http.Path @@ -16,4 +19,8 @@ interface GroupAPI { @Path("groupId") groupId: Int ): Response + @POST("api/v1/group/search") + suspend fun searchGroup( + @Body groupSearchRequest: GroupSearchRequest + ): Response } \ No newline at end of file diff --git a/data/src/main/java/org/gdsc/data/repository/GroupRepositoryImpl.kt b/data/src/main/java/org/gdsc/data/repository/GroupRepositoryImpl.kt index 4174d164..6be11426 100644 --- a/data/src/main/java/org/gdsc/data/repository/GroupRepositoryImpl.kt +++ b/data/src/main/java/org/gdsc/data/repository/GroupRepositoryImpl.kt @@ -1,6 +1,7 @@ package org.gdsc.data.repository import org.gdsc.data.datasource.GroupDataSource +import org.gdsc.domain.model.GroupPreview import org.gdsc.domain.model.response.Group import org.gdsc.domain.repository.GroupRepository import javax.inject.Inject @@ -15,4 +16,8 @@ class GroupRepositoryImpl @Inject constructor( override suspend fun selectGroup(groupId: Int): String { return groupDataSource.selectGroup(groupId) } + + override suspend fun searchGroup(keyword: String, limitCount: Int): List { + return groupDataSource.searchGroup(keyword, limitCount) + } } \ No newline at end of file diff --git a/domain/src/main/java/org/gdsc/domain/model/GroupPreview.kt b/domain/src/main/java/org/gdsc/domain/model/GroupPreview.kt new file mode 100644 index 00000000..434eea9e --- /dev/null +++ b/domain/src/main/java/org/gdsc/domain/model/GroupPreview.kt @@ -0,0 +1,9 @@ +package org.gdsc.domain.model + +data class GroupPreview( + val groupId: Int, + val groupIntroduce: String, + val groupName: String, + val memberCnt: Int, + val restaurantCnt: Int +) \ No newline at end of file diff --git a/domain/src/main/java/org/gdsc/domain/model/request/GroupSearchRequest.kt b/domain/src/main/java/org/gdsc/domain/model/request/GroupSearchRequest.kt new file mode 100644 index 00000000..8dcd8b79 --- /dev/null +++ b/domain/src/main/java/org/gdsc/domain/model/request/GroupSearchRequest.kt @@ -0,0 +1,5 @@ +package org.gdsc.domain.model.request + +data class GroupSearchRequest( + val keyword: String +) \ No newline at end of file diff --git a/domain/src/main/java/org/gdsc/domain/repository/GroupRepository.kt b/domain/src/main/java/org/gdsc/domain/repository/GroupRepository.kt index 2a95577f..b81a58c0 100644 --- a/domain/src/main/java/org/gdsc/domain/repository/GroupRepository.kt +++ b/domain/src/main/java/org/gdsc/domain/repository/GroupRepository.kt @@ -1,9 +1,12 @@ package org.gdsc.domain.repository +import org.gdsc.domain.model.GroupPreview import org.gdsc.domain.model.response.Group interface GroupRepository { suspend fun getMyGroups(): List suspend fun selectGroup(groupId: Int): String + + suspend fun searchGroup(keyword: String, limitCount: Int): List } \ No newline at end of file diff --git a/domain/src/main/java/org/gdsc/domain/usecase/GetGroupBySearchWithLimitCountUseCase.kt b/domain/src/main/java/org/gdsc/domain/usecase/GetGroupBySearchWithLimitCountUseCase.kt new file mode 100644 index 00000000..3547034e --- /dev/null +++ b/domain/src/main/java/org/gdsc/domain/usecase/GetGroupBySearchWithLimitCountUseCase.kt @@ -0,0 +1,10 @@ +package org.gdsc.domain.usecase + +import org.gdsc.domain.repository.GroupRepository +import javax.inject.Inject + +class GetGroupBySearchWithLimitCountUseCase @Inject constructor( + private val groupRepository: GroupRepository +) { + suspend operator fun invoke(keyword: String, limitCount: Int) = groupRepository.searchGroup(keyword, limitCount) +} \ No newline at end of file diff --git a/presentation/src/main/java/org/gdsc/presentation/view/allsearch/AllSearchFragment.kt b/presentation/src/main/java/org/gdsc/presentation/view/allsearch/AllSearchFragment.kt index 90835c1b..62358a27 100644 --- a/presentation/src/main/java/org/gdsc/presentation/view/allsearch/AllSearchFragment.kt +++ b/presentation/src/main/java/org/gdsc/presentation/view/allsearch/AllSearchFragment.kt @@ -55,6 +55,8 @@ class AllSearchFragment : Fragment() { binding.cgRecentSearch.removeAllViews() keywordList.forEach { if (it.isNotBlank()) { + binding.tvRecentSearch.visibility = View.VISIBLE + binding.tvDelete.visibility = View.VISIBLE binding.cgRecentSearch.addView( newChip(it, { keyword -> @@ -64,6 +66,9 @@ class AllSearchFragment : Fragment() { navigateToResultPage() } ) + } else { + binding.tvRecentSearch.visibility = View.GONE + binding.tvDelete.visibility = View.GONE } } } diff --git a/presentation/src/main/java/org/gdsc/presentation/view/allsearch/AllSearchViewModel.kt b/presentation/src/main/java/org/gdsc/presentation/view/allsearch/AllSearchViewModel.kt index 7ba86fa8..e18b1357 100644 --- a/presentation/src/main/java/org/gdsc/presentation/view/allsearch/AllSearchViewModel.kt +++ b/presentation/src/main/java/org/gdsc/presentation/view/allsearch/AllSearchViewModel.kt @@ -13,8 +13,10 @@ import kotlinx.coroutines.launch import org.gdsc.domain.DrinkPossibility import org.gdsc.domain.FoodCategory import org.gdsc.domain.SortType +import org.gdsc.domain.model.GroupPreview import org.gdsc.domain.model.Location import org.gdsc.domain.model.RegisteredRestaurant +import org.gdsc.domain.usecase.GetGroupBySearchWithLimitCountUseCase import org.gdsc.domain.usecase.GetRestaurantBySearchUseCase import org.gdsc.domain.usecase.GetRestaurantBySearchWithLimitCountUseCase import org.gdsc.domain.usecase.user.DeleteSearchedKeywordUseCase @@ -32,41 +34,12 @@ class AllSearchViewModel @Inject constructor( private val updateSearchedKeywordUseCase: UpdateSearchedKeywordUseCase, private val deleteSearchedKeywordUseCase: DeleteSearchedKeywordUseCase, private val initSearchedKeywordUseCase: InitSearchedKeywordUseCase, - private val getRestaurantBySearchWithLimitCountUseCase: GetRestaurantBySearchWithLimitCountUseCase + private val getRestaurantBySearchWithLimitCountUseCase: GetRestaurantBySearchWithLimitCountUseCase, + private val getGroupBySearchWithLimitCountUseCase: GetGroupBySearchWithLimitCountUseCase ) : ViewModel() { init { - viewModelScope.launch { - val location = locationManager.getCurrentLocation() - - if (location == null) { - _searchedRestaurantPreviewState.value = emptyList() - } else { - - val userLoc = Location(location.longitude.toString(), location.latitude.toString()) - - _searchedRestaurantPreviewState.value = - getRestaurantBySearchWithLimitCountUseCase(searchKeyword.value, userLoc, 3) - } - - } - - viewModelScope.launch { - val location = locationManager.getCurrentLocation() - - if (location == null) { - _searchedRestaurantState.value = PagingData.empty() - } else { - val userLoc = Location(location.longitude.toString(), location.latitude.toString()) - - getRestaurantBySearchUseCase(searchKeyword.value, userLoc).distinctUntilChanged() - .collect { - _searchedRestaurantState.value = it - } - } - } - viewModelScope.launch { val keywords = getSearchedKeywordsUseCase() if (keywords.isNotEmpty()) { @@ -101,6 +74,12 @@ class AllSearchViewModel @Inject constructor( val searchedRestaurantPreviewState: StateFlow> get() = _searchedRestaurantPreviewState + private var _searchedGroupPreviewState = + MutableStateFlow>(emptyList()) + + val searchedGroupPreviewState: StateFlow> + get() = _searchedGroupPreviewState + private var _searchedKeywordsState = MutableStateFlow>(emptyList()) val searchedKeywordsState: StateFlow> @@ -140,5 +119,46 @@ class AllSearchViewModel @Inject constructor( } } + fun searchRestaurantPreviewWithKeyword() { + viewModelScope.launch { + val location = locationManager.getCurrentLocation() + + if (location == null) { + _searchedRestaurantPreviewState.value = emptyList() + } else { + + val userLoc = Location(location.longitude.toString(), location.latitude.toString()) + + _searchedRestaurantPreviewState.value = + getRestaurantBySearchWithLimitCountUseCase(searchKeyword.value, userLoc, 3) + } + + } + } + + fun searchRestaurantWithKeyword() { + viewModelScope.launch { + val location = locationManager.getCurrentLocation() + + if (location == null) { + _searchedRestaurantState.value = PagingData.empty() + } else { + val userLoc = Location(location.longitude.toString(), location.latitude.toString()) + + getRestaurantBySearchUseCase(searchKeyword.value, userLoc).distinctUntilChanged() + .collect { + _searchedRestaurantState.value = it + } + } + } + } + + fun searchGroupPreviewWithKeyword() { + viewModelScope.launch { + val result = getGroupBySearchWithLimitCountUseCase(searchKeyword.value, 3) + _searchedGroupPreviewState.value = result + } + } + } \ No newline at end of file diff --git a/presentation/src/main/java/org/gdsc/presentation/view/allsearch/SearchCategoryAllFragment.kt b/presentation/src/main/java/org/gdsc/presentation/view/allsearch/SearchCategoryAllFragment.kt index 3c4ee35e..8c2247ec 100644 --- a/presentation/src/main/java/org/gdsc/presentation/view/allsearch/SearchCategoryAllFragment.kt +++ b/presentation/src/main/java/org/gdsc/presentation/view/allsearch/SearchCategoryAllFragment.kt @@ -43,6 +43,9 @@ class SearchCategoryAllFragment( override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + viewModel.searchRestaurantPreviewWithKeyword() + viewModel.searchGroupPreviewWithKeyword() + binding.restaurantRecyclerView.adapter = searchCategoryRestaurantPreviewAdapter binding.restaurantRecyclerView.layoutManager = LinearLayoutManager(requireContext()) @@ -68,44 +71,12 @@ class SearchCategoryAllFragment( } } - // Todo: Real APi - searchCategoryGroupPreviewAdapter.submitList( - listOf( - GroupInfo( - "https://avatars.githubusercontent.com/u/58663494?v=4", - 1, - "햄버거 먹으러 갈 사람 여기여기 모여라", - "버거 대마왕", - "https://avatars.githubusercontent.com/u/58663494?v=4", - false, - (0 .. 500).shuffled().first(), - false, - (0 .. 500).shuffled().first() - ), - GroupInfo( - "https://avatars.githubusercontent.com/u/58663494?v=4", - 2, - "햄버거 먹으러 갈 사람 여기여기 모여라", - "버거 대마왕", - "https://avatars.githubusercontent.com/u/58663494?v=4", - false, - (0 .. 500).shuffled().first(), - false, - (0 .. 500).shuffled().first() - ), - GroupInfo( - "https://avatars.githubusercontent.com/u/58663494?v=4", - 3, - "햄버거 먹으러 갈 사람 여기여기 모여라", - "버거 대마왕", - "https://avatars.githubusercontent.com/u/58663494?v=4", - false, - (0 .. 500).shuffled().first(), - false, - (0 .. 500).shuffled().first() - ), - ) - ) + repeatWhenUiStarted { + viewModel.searchedGroupPreviewState.collect { + searchCategoryGroupPreviewAdapter.submitList(it) + } + } + } override fun onDestroyView() { diff --git a/presentation/src/main/java/org/gdsc/presentation/view/allsearch/SearchCategoryRestaurantFragment.kt b/presentation/src/main/java/org/gdsc/presentation/view/allsearch/SearchCategoryRestaurantFragment.kt index cd13104f..af2d5526 100644 --- a/presentation/src/main/java/org/gdsc/presentation/view/allsearch/SearchCategoryRestaurantFragment.kt +++ b/presentation/src/main/java/org/gdsc/presentation/view/allsearch/SearchCategoryRestaurantFragment.kt @@ -42,6 +42,7 @@ class SearchCategoryRestaurantFragment( setSpinners() viewModel.setSearchKeyword(searchKeyword) + viewModel.searchRestaurantWithKeyword() binding.restaurantRecyclerView.adapter = searchCategoryRestaurantAdapter binding.restaurantRecyclerView.layoutManager = LinearLayoutManager(requireContext()) @@ -49,6 +50,7 @@ class SearchCategoryRestaurantFragment( } private fun observeState() { + repeatWhenUiStarted { viewModel.searchedRestaurantState.collect { searchCategoryRestaurantAdapter.submitData(it) diff --git a/presentation/src/main/java/org/gdsc/presentation/view/allsearch/adapter/SearchCategoryGroupPreviewAdapter.kt b/presentation/src/main/java/org/gdsc/presentation/view/allsearch/adapter/SearchCategoryGroupPreviewAdapter.kt index 00e6c93e..82423220 100644 --- a/presentation/src/main/java/org/gdsc/presentation/view/allsearch/adapter/SearchCategoryGroupPreviewAdapter.kt +++ b/presentation/src/main/java/org/gdsc/presentation/view/allsearch/adapter/SearchCategoryGroupPreviewAdapter.kt @@ -6,27 +6,27 @@ import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import com.bumptech.glide.Glide -import org.gdsc.domain.model.GroupInfo +import org.gdsc.domain.model.GroupPreview import org.gdsc.presentation.R import org.gdsc.presentation.databinding.ItemSearchGroupBinding class SearchCategoryGroupPreviewAdapter - : ListAdapter( + : ListAdapter( diffCallback ) { companion object { - val diffCallback = object : DiffUtil.ItemCallback() { + val diffCallback = object : DiffUtil.ItemCallback() { override fun areItemsTheSame( - oldItem: GroupInfo, - newItem: GroupInfo + oldItem: GroupPreview, + newItem: GroupPreview ): Boolean { return oldItem == newItem } override fun areContentsTheSame( - oldItem: GroupInfo, - newItem: GroupInfo + oldItem: GroupPreview, + newItem: GroupPreview ): Boolean { return oldItem == newItem } @@ -36,10 +36,10 @@ class SearchCategoryGroupPreviewAdapter class GroupWithSearchPreviewViewHolder( private val binding: ItemSearchGroupBinding, ): RecyclerView.ViewHolder(binding.root) { - fun bind(item: GroupInfo) { + fun bind(item: GroupPreview) { binding.run { Glide.with(itemView.context) - .load(item.groupProfileImageUrl) + .load("https://picsum.photos/200") .placeholder(R.drawable.base_profile_image) .into(ivGroupImage)