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] 추천 뷰 구현 #24

Merged
merged 55 commits into from
May 23, 2024
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
b8d2853
[feat] #22 광고뷰 아이템 구현
Hyobeen-Park May 20, 2024
f9b4b24
[add] #22 광고뷰 이미지 추가
Hyobeen-Park May 20, 2024
63dbe7c
[feat] #22 광고 뷰 구현
Hyobeen-Park May 20, 2024
774436d
[feat] #22 뷰페이저 어댑터 구현
Hyobeen-Park May 20, 2024
5420bfd
[feat] #22 추천 뷰모델 생성 및 광고뷰 어댑터 연결
Hyobeen-Park May 20, 2024
de1ce2f
[feat] #22 원형 메뉴 아이템 구현
Hyobeen-Park May 20, 2024
08a8616
[feat] #22 추천뷰 ScrollView로 수정 및 원형 메뉴 리사이클러뷰 추가
Hyobeen-Park May 20, 2024
cd39e35
[feat] #22 맞춤 상품 아이템 구현
Hyobeen-Park May 20, 2024
4a03d6a
[add] #22 아이콘 추가
Hyobeen-Park May 20, 2024
6c347da
[feat] #22 맞춤 상품 뷰 구현
Hyobeen-Park May 20, 2024
a2c5329
[feat] #22 발매 상품 아이템 구현
Hyobeen-Park May 20, 2024
80ee282
[feat] #22 발매 상품 뷰 구현
Hyobeen-Park May 20, 2024
c6c2d65
[feat] #22 인스타그램 아이템 구현
Hyobeen-Park May 20, 2024
7c207f0
[feat] #22 인스타그램 뷰 구현
Hyobeen-Park May 20, 2024
571e931
[chore] #22 어댑터 네이밍 수정
Hyobeen-Park May 20, 2024
682aefb
[chore] #22 원형 메뉴 마진, 패딩 수정
Hyobeen-Park May 20, 2024
6ed0a56
[feat] #22 원형 메뉴 어댑터 구현
Hyobeen-Park May 20, 2024
463a144
[feat] #22 원형 메뉴 어댑터 연결
Hyobeen-Park May 20, 2024
2b00572
[chore] #22 원형 메뉴 글씨 잘리는 오류 수정
Hyobeen-Park May 20, 2024
2584ce8
[add] #22 맞춤상품 원형 이미지 추가
Hyobeen-Park May 21, 2024
35e3f95
[add] #22 맞춤 상품 데이터 추가
Hyobeen-Park May 21, 2024
79991b0
[feat] #22 맞춤상품 어댑터 연결
Hyobeen-Park May 21, 2024
7b0382f
[mod] #22 마진 및 아이템 글씨 잘리는 오류 수정
Hyobeen-Park May 21, 2024
14d72aa
[chore] #22 함수 private으로 수정
Hyobeen-Park May 21, 2024
e7694d3
[add] #22 더미데이터 추가
Hyobeen-Park May 21, 2024
825a921
[chore] #22 layout 수정
Hyobeen-Park May 21, 2024
909ca51
[feat] #22 Just Dropped 어댑터 구현
Hyobeen-Park May 21, 2024
3b71de4
[feat] #22 Style 어댑터 구현
Hyobeen-Park May 21, 2024
0e39b30
[chore] #22 Just Dropped 아이템 레이아웃 및 네이밍 수정
Hyobeen-Park May 21, 2024
69b76da
[mod] #22 For You 뷰홀더 분리 및 어댑터 수정
Hyobeen-Park May 21, 2024
4521336
[mod] #22 layout 수정
Hyobeen-Park May 21, 2024
0f4ebc4
[mod] #22 strings 추출
Hyobeen-Park May 21, 2024
fc213b6
[chore] #22 이미지 크기 조정
Hyobeen-Park May 21, 2024
796f9c2
[feat] #22 For You clickable 레이아웃 검색뷰로 연결
Hyobeen-Park May 21, 2024
fbc2cbf
[mod] #22 원형 메뉴 enum class로 분리
Hyobeen-Park May 21, 2024
a1bb216
[mod] #22 원형 메뉴 ViewHolder 분리
Hyobeen-Park May 21, 2024
aaed73b
[mod] #22 광고 ViewHolder, 데이터 분리
Hyobeen-Park May 22, 2024
97ffef0
Merge remote-tracking branch 'origin/develop' into feat-view2-xml
Hyobeen-Park May 22, 2024
d45a1c9
[feat] #22 바텀시트 구현
Hyobeen-Park May 22, 2024
f0c4021
[feat] #22 추천 상품 조회 API
Hyobeen-Park May 22, 2024
e43ca75
[feat] #22 추천 상품 조회 API 연결
Hyobeen-Park May 23, 2024
c129664
[chore] #22 이미지 정리
Hyobeen-Park May 23, 2024
7697202
[chore] #22 style 데이터 수정
Hyobeen-Park May 23, 2024
ea971f7
[chore] #22 네이밍 수정
Hyobeen-Park May 23, 2024
b7670e4
[chore] #22 InstagramModel 패키지 이동
Hyobeen-Park May 23, 2024
4581e9f
[chore] #22 네이밍 수정
Hyobeen-Park May 23, 2024
62c57b7
[chore] #22 layout 수정
Hyobeen-Park May 23, 2024
e0ffa71
[mod] #22 원형 메뉴 strings 추출
Hyobeen-Park May 23, 2024
39de15c
[chore] #22 원형 메뉴 4월 -> 5월 로 수정
Hyobeen-Park May 23, 2024
9de9011
[add] #22 원형 메뉴 이미지 추가
Hyobeen-Park May 23, 2024
cb6513c
[feat] #22 For You 페이지 설정
Hyobeen-Park May 23, 2024
d1948ad
Merge remote-tracking branch 'origin/develop' into feat-view2-xml
Hyobeen-Park May 23, 2024
4fae373
[chore] #22 코드 정리
Hyobeen-Park May 23, 2024
beac447
[mod] #22 바텀시트 모서리부분 수정
Hyobeen-Park May 23, 2024
6eee5d2
[chore] #22 불필요한 코드 삭제
Hyobeen-Park May 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package org.sopt.kream.data.datasource

import org.sopt.kream.data.model.response.ResponseRecommendProductDto
import org.sopt.kream.data.model.response.ResponseSearchProductDto
import org.sopt.kream.util.base.BaseResponse

interface ProductRemoteDataSource {
suspend fun getSearchProduct(findName: String): BaseResponse<ResponseSearchProductDto>

suspend fun getRecommendProduct(memberId: Int): BaseResponse<ResponseRecommendProductDto>
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ package org.sopt.kream.data.datasourceimpl

import org.sopt.kream.data.ServicePool
import org.sopt.kream.data.datasource.ProductRemoteDataSource
import org.sopt.kream.data.model.response.ResponseRecommendProductDto
import org.sopt.kream.data.model.response.ResponseSearchProductDto
import org.sopt.kream.util.base.BaseResponse

class ProductRemoteDataSourceImpl : ProductRemoteDataSource {
private val productService = ServicePool.productService

override suspend fun getSearchProduct(findName: String): BaseResponse<ResponseSearchProductDto> = productService.getSearchProduct(findName = findName)

override suspend fun getRecommendProduct(memberId: Int): BaseResponse<ResponseRecommendProductDto> = productService.getRecommendProduct(memberId = memberId)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.sopt.kream.data.mapper

import org.sopt.kream.data.model.response.ResponseRecommendProductDto.ResponseForYouProductDto
import org.sopt.kream.domain.model.RecommendForYouProductModel

fun ResponseForYouProductDto.toRecommendForYouProductModel() =
RecommendForYouProductModel(
thumbnailUrl = this.thumbnailUrl,
brandTitle = this.brandTitle,
engTitle = this.engTitle,
price = this.price,
transactionCount = this.transactionCount,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.sopt.kream.data.mapper

import org.sopt.kream.data.model.response.ResponseRecommendProductDto.ResponseJustDroppedProductDto
import org.sopt.kream.domain.model.RecommendJustDroppedProductModel

fun ResponseJustDroppedProductDto.toRecommendJustDroppedProductModel() =
RecommendJustDroppedProductModel(
thumbnailUrl = this.thumbnailUrl,
brandTitle = this.brandTitle,
engTitle = this.engTitle,
price = this.price,
transactionCount = this.transactionCount,
isScrap = this.isScrap,
isFast = this.isFast,
isFreeDeliver = this.isFreeDeliver,
isSave = this.isSave,
isCoupon = this.isCoupon,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.sopt.kream.data.mapper

import org.sopt.kream.data.model.response.ResponseRecommendProductDto
import org.sopt.kream.domain.model.RecommendProductModel

fun ResponseRecommendProductDto.toRecommendProductModel() =
RecommendProductModel(
recommendForYouProducts = this.forYouList.map { it.toRecommendForYouProductModel() },
recommendJustDroppedProducts = this.justDropList.map { it.toRecommendJustDroppedProductModel() },
Comment on lines +8 to +9
Copy link
Contributor

Choose a reason for hiding this comment

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

개인적으로는 it을 그대로 사용하는 것보다 네이밍을 해주고 사용하는 것을 선호하는 편이지만 갠취니까 그냥 참고만 해주세요 ~

)
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package org.sopt.kream.data.model.response

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class ResponseRecommendProductDto(
@SerialName("forYouList")
val forYouList: List<ResponseForYouProductDto>,
@SerialName("justDropList")
val justDropList: List<ResponseJustDroppedProductDto>,
) {
@Serializable
data class ResponseForYouProductDto(
@SerialName("thumbnailUrl")
val thumbnailUrl: String,
@SerialName("brandTitle")
val brandTitle: String,
@SerialName("engTitle")
val engTitle: String,
@SerialName("price")
val price: String,
@SerialName("transactionCount")
val transactionCount: String,
)

@Serializable
data class ResponseJustDroppedProductDto(
@SerialName("thumbnailUrl")
val thumbnailUrl: String,
@SerialName("brandTitle")
val brandTitle: String,
@SerialName("engTitle")
val engTitle: String,
@SerialName("price")
val price: String,
@SerialName("transactionCount")
val transactionCount: String,
@SerialName("isScrap")
val isScrap: Boolean,
@SerialName("isFast")
val isFast: Boolean,
@SerialName("isFreeDeliver")
val isFreeDeliver: Boolean,
@SerialName("isSave")
val isSave: Boolean,
@SerialName("isCoupon")
val isCoupon: Boolean,
)
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package org.sopt.kream.data.repository

import org.sopt.kream.data.datasource.ProductRemoteDataSource
import org.sopt.kream.data.mapper.toRecommendProductModel
import org.sopt.kream.data.mapper.toSearchProductModel
import org.sopt.kream.domain.model.RecommendProductModel
import org.sopt.kream.domain.model.SearchProductModel
import org.sopt.kream.domain.repository.ProductRepository

Expand All @@ -12,4 +14,9 @@ class ProductRepositoryImpl(
runCatching {
productRemoteDataSource.getSearchProduct(findName = findName).data.toSearchProductModel()
}

override suspend fun getRecommendProduct(memberId: Int): Result<RecommendProductModel> =
runCatching {
productRemoteDataSource.getRecommendProduct(memberId = memberId).data.toRecommendProductModel()
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
package org.sopt.kream.data.service

import org.sopt.kream.data.model.response.ResponseRecommendProductDto
import org.sopt.kream.data.model.response.ResponseSearchProductDto
import org.sopt.kream.util.base.BaseResponse
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.Query

interface ProductService {
@GET("product")
suspend fun getSearchProduct(
@Query("findName") findName: String,
): BaseResponse<ResponseSearchProductDto>

@GET("product/recommend")
suspend fun getRecommendProduct(
@Header("memberId") memberId: Int,
): BaseResponse<ResponseRecommendProductDto>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.sopt.kream.domain.model

import androidx.annotation.DrawableRes
Copy link
Contributor

Choose a reason for hiding this comment

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

Domain Layer는 순수 코틀린 파일만 있어야 합니다 (다른 라이브러리에 의존성 X) 이런 식으로 구현하면 androix 라이브러리에 의존성이 있는 상태가 되니 해당 파일은 presentation 으로 이동시키는 게 클린 아키텍처에 더 부합 할 것 같숩니당!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

헉 그렇군요..!! 감사합니다😻


data class InstagramModel(
@DrawableRes val image: Int,
val id: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.sopt.kream.domain.model

data class RecommendForYouProductModel(
val thumbnailUrl: String,
val brandTitle: String,
val engTitle: String,
val price: String,
val transactionCount: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.sopt.kream.domain.model

data class RecommendJustDroppedProductModel(
val thumbnailUrl: String,
val brandTitle: String,
val engTitle: String,
val price: String,
val transactionCount: String,
val isScrap: Boolean,
val isFast: Boolean,
val isFreeDeliver: Boolean,
val isSave: Boolean,
val isCoupon: Boolean,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.sopt.kream.domain.model

data class RecommendProductModel(
val recommendForYouProducts: List<RecommendForYouProductModel>,
val recommendJustDroppedProducts: List<RecommendJustDroppedProductModel>,
)
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package org.sopt.kream.domain.repository

import org.sopt.kream.domain.model.RecommendProductModel
import org.sopt.kream.domain.model.SearchProductModel

interface ProductRepository {
suspend fun getSearchProduct(findName: String): Result<SearchProductModel>

suspend fun getRecommendProduct(memberId: Int): Result<RecommendProductModel>
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import org.sopt.kream.data.datasourceimpl.ProductRemoteDataSourceImpl
import org.sopt.kream.data.repository.DummyRepositoryImpl
import org.sopt.kream.data.repository.ProductRepositoryImpl
import org.sopt.kream.presentation.ui.dummy.DummyViewModel
import org.sopt.kream.presentation.ui.main.home.recommend.RecommendViewModel
import org.sopt.kream.presentation.ui.search.SearchViewModel

class ViewModelFactory : ViewModelProvider.Factory {
Expand All @@ -15,6 +16,8 @@ class ViewModelFactory : ViewModelProvider.Factory {
return DummyViewModel(DummyRepositoryImpl(DummyRemoteDataSourceImpl())) as T
} else if (modelClass.isAssignableFrom(SearchViewModel::class.java)) {
return SearchViewModel(ProductRepositoryImpl(ProductRemoteDataSourceImpl())) as T
} else if (modelClass.isAssignableFrom(RecommendViewModel::class.java)) {
return RecommendViewModel(ProductRepositoryImpl(ProductRemoteDataSourceImpl())) as T
}
throw IllegalArgumentException("Unknown ViewModel Class")
}
Expand Down
Copy link
Contributor

Choose a reason for hiding this comment

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

뷰홀더랑 네이밍 맞추는 편이 좋을 것 같습니다 ~

Copy link
Contributor Author

Choose a reason for hiding this comment

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

헉 네이밍 바꾸면서 이걸 놓쳤네요😅 감사합니다!!

Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.sopt.kream.presentation.ui.main.home.recommend

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import org.sopt.kream.databinding.ItemRecommendAdBinding

Copy link
Contributor

Choose a reason for hiding this comment

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

시간적 여유가 있으면 ListAdapter + DiffUtil 사용해 보는 걸 추천합니다 (사실 이거 가져가기로 했었어서,,, 적용했으면 좋겠습니당)

class RecommendAdViewPagerAdapter(private val data: List<Int>) : RecyclerView.Adapter<RecommendAdvertisementViewHolder>() {
private val item = data

override fun getItemCount(): Int = item.size

override fun onBindViewHolder(
holder: RecommendAdvertisementViewHolder,
position: Int,
) {
holder.onBind(item[position])
}

override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int,
): RecommendAdvertisementViewHolder {
val binding = ItemRecommendAdBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return RecommendAdvertisementViewHolder(binding)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.sopt.kream.presentation.ui.main.home.recommend

import androidx.recyclerview.widget.RecyclerView
import org.sopt.kream.databinding.ItemRecommendAdBinding

class RecommendAdvertisementViewHolder(
private val binding: ItemRecommendAdBinding,
) : RecyclerView.ViewHolder(binding.root) {
fun onBind(
item: Int,
) {
with(binding) {
ivRecommendAd.setImageResource(item)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.sopt.kream.presentation.ui.main.home.recommend

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import org.sopt.kream.databinding.ItemRecommendCircleMenuBinding
import org.sopt.kream.presentation.ui.type.RecommendCircleMenuType
import kotlin.enums.EnumEntries

class RecommendCircleMenuAdapter(private val list: EnumEntries<RecommendCircleMenuType>) : RecyclerView.Adapter<RecommendCircleMenuViewHolder>() {
private val item = list

override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int,
): RecommendCircleMenuViewHolder {
val binding = ItemRecommendCircleMenuBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return RecommendCircleMenuViewHolder(binding)
}

override fun onBindViewHolder(
holder: RecommendCircleMenuViewHolder,
position: Int,
) {
holder.onBind(item.get(position).menu)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
holder.onBind(item.get(position).menu)
holder.onBind(item[position].menu)

그리고 이거 이미지 디쟌 측에서 추가해주시면 menu만 넘기는 게 아니라 그냥 아이템 객체 자체를 넘겨야 할 것 같숩니다

Copy link
Contributor Author

Choose a reason for hiding this comment

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

넵~~!!

}

override fun getItemCount(): Int = list.size
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.sopt.kream.presentation.ui.main.home.recommend

import androidx.recyclerview.widget.RecyclerView
import org.sopt.kream.databinding.ItemRecommendCircleMenuBinding

class RecommendCircleMenuViewHolder(
private val binding: ItemRecommendCircleMenuBinding,
) : RecyclerView.ViewHolder(binding.root) {
fun onBind(
item: String,
) {
with(binding) {
tvCircleMenuTitle.text = item
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package org.sopt.kream.presentation.ui.main.home.recommend

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.ListAdapter
import org.sopt.kream.databinding.ItemRecommendForYouProductBinding
import org.sopt.kream.domain.model.RecommendForYouProductModel
import org.sopt.kream.util.view.ItemDiffCallback

class RecommendForYouAdapter(
private val navigateToProductDetail: (Int) -> Unit,
Copy link
Contributor

Choose a reason for hiding this comment

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

왁 화면 연결까지 야무지네요

Copy link
Contributor Author

Choose a reason for hiding this comment

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

헤헿 감사합니다❤️

private val page: Int,
) : ListAdapter<
RecommendForYouProductModel,
RecommendForYouViewHolder,
>(
ItemDiffCallback<RecommendForYouProductModel>(
onContentsTheSame = { old, new -> old == new },
onItemsTheSame = { old, new -> old.engTitle == new.engTitle },
Comment on lines +14 to +19
Copy link
Contributor

Choose a reason for hiding this comment

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

오 여기는 리스트 어댑터를 사용하셨네요? 안 사용하신 부분도 적용해주시면 좋을 것 같아요!

),
) {
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int,
): RecommendForYouViewHolder =
RecommendForYouViewHolder(
ItemRecommendForYouProductBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false,
),
navigateToProductDetail,
)

override fun onBindViewHolder(
holder: RecommendForYouViewHolder,
position: Int,
) {
holder.onBind(
recommendForYouProductModel = currentList[page * 6 + position],
Copy link
Contributor

Choose a reason for hiding this comment

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

이거 이런 식으로 설정한 이유가 뭔가요? 애초에 어댑터에 값을 넣을 때 6개씩 쪼개서 리스트를 만들어두고 그 리스트를 어댑터에 넣어주는 편이 좋을 것 같습니다

position = position,
)
}

override fun getItemCount(): Int = 6
Copy link
Contributor

Choose a reason for hiding this comment

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

요거 따로 설정해 주시지 않아도 돼요

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.sopt.kream.presentation.ui.main.home.recommend

import android.view.View
import androidx.recyclerview.widget.RecyclerView
import coil.load
import org.sopt.kream.databinding.ItemRecommendForYouProductBinding
import org.sopt.kream.domain.model.RecommendForYouProductModel

class RecommendForYouViewHolder(
private val binding: ItemRecommendForYouProductBinding,
private val navigateToProductDetail: (Int) -> Unit,
) : RecyclerView.ViewHolder(binding.root) {
fun onBind(
recommendForYouProductModel: RecommendForYouProductModel,
position: Int,
) {
with(binding) {
ivForYou.load(recommendForYouProductModel.thumbnailUrl)
tvForYouBrand.text = recommendForYouProductModel.brandTitle
tvForYouProduct.text = recommendForYouProductModel.engTitle
tvForYouPrice.text = recommendForYouProductModel.price
tvForYouTransaction.text = recommendForYouProductModel.transactionCount
tvForYouSee.visibility = View.INVISIBLE
}
}
}
Loading
Loading