Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEAT/#105] 탐색 뷰 더미데이터 연결 #106

Merged
merged 8 commits into from
Jan 21, 2025
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.spoony.spoony.data.di

import com.spoony.spoony.data.repositoryimpl.DummyRepositoryImpl
import com.spoony.spoony.data.repositoryimpl.ExploreRepositoryImpl
import com.spoony.spoony.domain.repository.DummyRepository
import com.spoony.spoony.domain.repository.ExploreRepository
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
Expand All @@ -14,4 +16,8 @@ abstract class RepositoryModule {
@Binds
@Singleton
abstract fun bindDummyRepository(dummyRepositoryImpl: DummyRepositoryImpl): DummyRepository

@Binds
@Singleton
abstract fun bindExploreRepository(exploreRepositoryImpl: ExploreRepositoryImpl): ExploreRepository
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package com.spoony.spoony.data.repositoryimpl

import com.spoony.spoony.domain.entity.CategoryEntity
import com.spoony.spoony.domain.entity.FeedEntity
import com.spoony.spoony.domain.repository.ExploreRepository
import javax.inject.Inject

class ExploreRepositoryImpl @Inject constructor() : ExploreRepository {
override suspend fun getCategoryList(): Result<List<CategoryEntity>> = Result.success(
listOf(
CategoryEntity(
categoryId = 1,
categoryName = "전체",
iconUrl = "https://spoony-storage.s3.ap-northeast-2.amazonaws.com/category/icons/all_white.png",
unSelectedIconUrl = "https://spoony-storage.s3.ap-northeast-2.amazonaws.com/category/icons/all_black.png"
),
CategoryEntity(
categoryId = 2,
categoryName = "로컬 수저",
iconUrl = "https://spoony-storage.s3.ap-northeast-2.amazonaws.com/category/icons/local_white.png",
unSelectedIconUrl = "https://spoony-storage.s3.ap-northeast-2.amazonaws.com/category/icons/all_black.png"
),
CategoryEntity(
categoryId = 3,
categoryName = "한식",
iconUrl = "https://spoony-storage.s3.ap-northeast-2.amazonaws.com/category/icons/korean_white.png",
unSelectedIconUrl = "https://spoony-storage.s3.ap-northeast-2.amazonaws.com/category/icons/korean_black.png"
),
CategoryEntity(
categoryId = 4,
categoryName = "일식",
iconUrl = "https://spoony-storage.s3.ap-northeast-2.amazonaws.com/category/icons/japanese_white.png",
unSelectedIconUrl = "https://spoony-storage.s3.ap-northeast-2.amazonaws.com/category/icons/japanese_black.png"
),
CategoryEntity(
categoryId = 5,
categoryName = "중식",
iconUrl = "https://spoony-storage.s3.ap-northeast-2.amazonaws.com/category/icons/chinese_white.png",
unSelectedIconUrl = "https://spoony-storage.s3.ap-northeast-2.amazonaws.com/category/icons/chinese_black.png"
),
CategoryEntity(
categoryId = 6,
categoryName = "양식",
iconUrl = "https://spoony-storage.s3.ap-northeast-2.amazonaws.com/category/icons/american_white.png",
unSelectedIconUrl = "https://spoony-storage.s3.ap-northeast-2.amazonaws.com/category/icons/american_black.png"
),
CategoryEntity(
categoryId = 7,
categoryName = "퓨전/세계요리",
iconUrl = "https://spoony-storage.s3.ap-northeast-2.amazonaws.com/category/icons/world_white.png",
unSelectedIconUrl = "https://spoony-storage.s3.ap-northeast-2.amazonaws.com/category/icons/world_black.png"
),
CategoryEntity(
categoryId = 8,
categoryName = "카페",
iconUrl = "https://spoony-storage.s3.ap-northeast-2.amazonaws.com/category/icons/cafe_white.png",
unSelectedIconUrl = "https://spoony-storage.s3.ap-northeast-2.amazonaws.com/category/icons/cafe_black.png"
),
CategoryEntity(
categoryId = 9,
categoryName = "주류",
iconUrl = "https://spoony-storage.s3.ap-northeast-2.amazonaws.com/category/icons/drink_white.png",
unSelectedIconUrl = "https://spoony-storage.s3.ap-northeast-2.amazonaws.com/category/icons/drink_black.png"
)
)
)

override suspend fun getFeedList(
userId: Int,
categoryId: Int,
locationQuery: String,
sortBy: String
): Result<List<FeedEntity>> = Result.success(
listOf(
FeedEntity(
userId = 3,
userName = "두더지",
userRegion = "용산구",
postId = 3,
title = "스타벅스 삼성역섬유센터R점 리뷰",
categoryInfo = CategoryEntity(
categoryId = 2,
categoryName = "카페",
iconUrl = "https://spoony-storage.s3.ap-northeast-2.amazonaws.com/category/icons/cafe_color.png",
textColor = "FFE4E5",
backgroundColor = "FF7E84"
),
zzimCount = 1
),
FeedEntity(
userId = 3,
userName = "두더지",
userRegion = "용산구",
postId = 4,
title = "스타벅스 삼성역섬유센터R점 리뷰",
categoryInfo = CategoryEntity(
categoryId = 2,
categoryName = "카페",
iconUrl = "https://spoony-storage.s3.ap-northeast-2.amazonaws.com/category/icons/cafe_color.png",
textColor = "FFE4E5",
backgroundColor = "FF7E84"
),
zzimCount = 1
),
FeedEntity(
userId = 3,
userName = "두더지",
userRegion = "용산구",
postId = 5,
title = "스타벅스 삼성역섬유센터R점 리뷰",
categoryInfo = CategoryEntity(
categoryId = 2,
categoryName = "카페",
iconUrl = "https://spoony-storage.s3.ap-northeast-2.amazonaws.com/category/icons/cafe_color.png",
textColor = "FFE4E5",
backgroundColor = "FF7E84"
),
zzimCount = 1
),
FeedEntity(
userId = 3,
userName = "두더지",
userRegion = "용산구",
postId = 6,
title = "스타벅스 삼성역섬유센터R점 리뷰",
categoryInfo = CategoryEntity(
categoryId = 2,
categoryName = "카페",
iconUrl = "https://spoony-storage.s3.ap-northeast-2.amazonaws.com/category/icons/cafe_color.png",
textColor = "FFE4E5",
backgroundColor = "FF7E84"
),
zzimCount = 1
),
FeedEntity(
userId = 3,
userName = "두더지",
userRegion = "용산구",
postId = 7,
title = "스타벅스 삼성역섬유센터R점 리뷰",
categoryInfo = CategoryEntity(
categoryId = 2,
categoryName = "카페",
iconUrl = "https://spoony-storage.s3.ap-northeast-2.amazonaws.com/category/icons/cafe_color.png",
textColor = "FFE4E5",
backgroundColor = "FF7E84"
),
zzimCount = 1
)
)
)
}
11 changes: 11 additions & 0 deletions app/src/main/java/com/spoony/spoony/domain/entity/FeedEntity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.spoony.spoony.domain.entity

data class FeedEntity(
val userId: Int,
val userName: String,
val userRegion: String,
val postId: Int,
val title: String,
val categoryInfo: CategoryEntity,
val zzimCount: Int
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.spoony.spoony.domain.repository

import com.spoony.spoony.domain.entity.CategoryEntity
import com.spoony.spoony.domain.entity.FeedEntity

interface ExploreRepository {
suspend fun getCategoryList(): Result<List<CategoryEntity>>

suspend fun getFeedList(
userId: Int,
categoryId: Int,
locationQuery: String,
sortBy: String
): Result<List<FeedEntity>>
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.spoony.spoony.presentation.explore

import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
Expand Down Expand Up @@ -49,6 +48,7 @@ import kotlinx.collections.immutable.persistentListOf
@Composable
fun ExploreRoute(
paddingValues: PaddingValues,
navigateToPlaceDetail: () -> Unit,
viewModel: ExploreViewModel = hiltViewModel()
) {
val state = viewModel.state.collectAsStateWithLifecycle()
Expand All @@ -74,14 +74,13 @@ fun ExploreRoute(
feedList = feedList,
onLocationSortingButtonClick = viewModel::updateSelectedCity,
onSortingButtonClick = viewModel::updateSelectedSortingOption,
onFeedItemClick = {},
onFeedItemClick = navigateToPlaceDetail,
onRegisterButtonClick = {},
updateSelectedCategory = viewModel::updateSelectedCategory
)
}
}

@OptIn(ExperimentalFoundationApi::class)
@Composable
private fun ExploreScreen(
paddingValues: PaddingValues,
Expand All @@ -93,7 +92,7 @@ private fun ExploreScreen(
feedList: UiState<ImmutableList<FeedModel>>,
onLocationSortingButtonClick: (String) -> Unit,
onSortingButtonClick: (SortingOption) -> Unit,
onFeedItemClick: (Int) -> Unit,
onFeedItemClick: () -> Unit,
onRegisterButtonClick: () -> Unit,
updateSelectedCategory: (Int) -> Unit
) {
Expand Down Expand Up @@ -143,6 +142,7 @@ private fun ExploreScreen(
unSelectedIconUrl = category.unSelectedIconUrl ?: "",
selectedIconUrl = category.iconUrl,
isSelected = selectedCategoryId == category.categoryId,
isGradient = true,
onClick = { updateSelectedCategory(category.categoryId) }
)
}
Expand All @@ -152,7 +152,7 @@ private fun ExploreScreen(
feedList = feedList,
selectedSortingOption = selectedSortingOption,
onSortingButtonClick = { isSortingBottomSheetVisible = it },
onFeedItemClick = onFeedItemClick,
onFeedItemClick = { onFeedItemClick() },
onRegisterButtonClick = onRegisterButtonClick
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import kotlinx.collections.immutable.ImmutableList
data class ExploreState(
val spoonCount: UiState<Int> = UiState.Loading,
val selectedCity: String = "마포구",
val selectedCategoryId: Int = 0,
val selectedCategoryId: Int = 1,
val selectedSortingOption: SortingOption = SortingOption.LATEST,
val categoryList: UiState<ImmutableList<CategoryEntity>> = UiState.Loading,
val feedList: UiState<ImmutableList<FeedModel>> = UiState.Loading
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,94 @@
package com.spoony.spoony.presentation.explore

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.spoony.spoony.core.state.UiState
import com.spoony.spoony.domain.repository.ExploreRepository
import com.spoony.spoony.presentation.explore.model.toModel
import com.spoony.spoony.presentation.explore.type.SortingOption
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch

@HiltViewModel
class ExploreViewModel @Inject constructor() : ViewModel() {
class ExploreViewModel @Inject constructor(
private val exploreRepository: ExploreRepository
) : ViewModel() {
private var _state: MutableStateFlow<ExploreState> = MutableStateFlow(ExploreState())
val state: StateFlow<ExploreState>
get() = _state

init {
getCategoryList()
getFeedList(
userId = 1,
categoryId = 2,
locationQuery = "강남",
sortBy = "latest"
)
}

private fun getCategoryList() {
viewModelScope.launch {
runCatching {
exploreRepository.getCategoryList()
.onSuccess { response ->
_state.update {
it.copy(
categoryList = UiState.Success(response.toImmutableList())
)
}
}
.onFailure {
_state.update {
it.copy(
categoryList = UiState.Failure("카테고리 목록 조회 실패")
)
}
}
}
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p1) Repository에서 이미 Result 객체로 보내주고 있는데 한번 더 runCatching으로 묶은 이유가 있을까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제가 runCatching이 뭔지,,, 까먹었나봅니다,,,ㅋㅋㅋ큐ㅠ


fun getFeedList(
userId: Int,
categoryId: Int,
locationQuery: String,
sortBy: String
) {
viewModelScope.launch {
runCatching {
exploreRepository.getFeedList(
userId = userId,
categoryId = categoryId,
locationQuery = locationQuery,
sortBy = sortBy
).onSuccess { response ->
_state.update {
it.copy(
feedList = UiState.Success(
response.map { feed ->
feed.toModel()
}.toImmutableList()
)
)
}
}
.onFailure {
_state.update {
it.copy(
feedList = UiState.Failure("피드 목록 조회 실패")
)
}
}
}
}
}

fun updateSelectedSortingOption(sortingOption: SortingOption) {
_state.update {
it.copy(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.spoony.spoony.presentation.explore.model

import com.spoony.spoony.domain.entity.CategoryEntity
import com.spoony.spoony.domain.entity.FeedEntity

data class FeedModel(
val feedId: Int,
Expand All @@ -11,3 +12,13 @@ data class FeedModel(
val categoryEntity: CategoryEntity,
val addMapCount: Int
)

fun FeedEntity.toModel(): FeedModel = FeedModel(
feedId = this.postId,
userId = this.userId,
username = this.userName,
userRegion = this.userRegion,
title = this.title,
categoryEntity = this.categoryInfo,
addMapCount = this.zzimCount
)
Loading
Loading