Conversation
| }, | ||
| onWishlistClick = { product, position -> | ||
| product.isWishlisted = !product.isWishlisted | ||
| // In wishlist fragment, usually removing from wishlist means removing from the list |
There was a problem hiding this comment.
전체적으로 굿굿 이런 주석은 빼도 될지도요?
| <TextView | ||
| android:id="@+id/tv_detail_description" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="wrap_content" |
|
|
||
| <!-- 제품 상세 정보 --> | ||
| <string name="product_description">The Nike Everyday Plus Cushioned Socks bring comfort to your workout with extra cushioning under the heel and forefoot and a snug, supportive arch band. Sweat-wicking power and breathability up top help keep your feet dry and cool to help push you through that extra set.</string> | ||
| <string name="wishlist_btn_text">위시리스트</string> |
There was a problem hiding this comment.
저는 아직 이 부분을 못 만들었는데, 만들겠습니다
kimdoyeon1234
left a comment
There was a problem hiding this comment.
이번 주차에 Navigation Component와 DataStore, ViewBinding까지 최신 스택을 골고루 활용해 완성도 높은 결과물을 만들어내신 점 정말 인상적이고 고생 많으셨습니다!
특히 ConstraintLayout의 ratio 속성을 활용한 UI 대응과 데이터 레이어를 분리한 설계가 아주 좋았는데, 다만 성능 최적화를 위해 repeatOnLifecycle 사용이나 어댑터 객체 재사용 같은 부분만 조금 더 보완한다면 좋은 코드가 될 것 같습니다
짧은 시간 안에 많은 기능을 안정적으로 구현하시느라 정말 수고하셨고, 고생하셨어요!
|
|
||
| private fun setupRecyclerView() { | ||
| viewLifecycleOwner.lifecycleScope.launch { | ||
| dataStoreManager.productsFlow.collect { products -> | ||
| val adapter = ProductAdapter( | ||
| products, | ||
| onItemClick = { product -> | ||
| navigateToDetail(product) | ||
| }, | ||
| onWishlistClick = { product, _ -> | ||
| viewLifecycleOwner.lifecycleScope.launch { | ||
| dataStoreManager.updateWishlistStatus(product.id, !product.isWishlisted) | ||
| } | ||
| } | ||
| ) | ||
|
|
||
| binding.rvAllProducts.layoutManager = GridLayoutManager(context, 2) | ||
| binding.rvAllProducts.adapter = adapter | ||
| } | ||
| } |
There was a problem hiding this comment.
현재 lifecycleScope.launch를 통해 collect를 호출하고 있는데, 이 경우 프래그먼트가 STOPPED 상태일 때도 계속 수집이 발생합니다. repeatOnLifecycle을 사용해 안정성을 높여보는 것도 좋을거 같습니다!
| val adapter = ProductAdapter( | ||
| products, | ||
| onItemClick = { product -> | ||
| navigateToDetail(product) |
There was a problem hiding this comment.
데이터가 업데이트될 때마다 val adapter = ProductAdapter(...)를 새로 생성하고 있습니다. 어댑터는 멤버 변수로 한 번만 선언하고, 리스트 데이터가 바뀔 때는 어댑터 내부에 public 메서드(예: updateList)를 만들어 데이터만 갈아끼워 주는 것이 성능상 더 좋을거 같습니다!
| val products = if (jsonString.isEmpty()) { | ||
| getInitialProducts().toMutableList() | ||
| } else { |
There was a problem hiding this comment.
updateWishlistStatus 메서드 내에서 초기 제품 리스트를 가져오는 로직이 productsFlow와 중복됩니다! 이미 productsFlow에서 초기 데이터 처리를 하고 있으니, 이 메서드에서는 현재 저장된 데이터를 first()로 가져와서 업데이트만 하도록 단순화할 수 있을 것 같아요!
|
|
||
| val product = arguments?.getParcelable<Product>("product") | ||
|
|
There was a problem hiding this comment.
Android 13(Tiramisu) 이상부터 getParcelable의 사용 방식이 변경되었습니다. 호환성을 위해 아래와 같이 버전 분기 처리를 해주면 더 안전한 코드가 될 것 같습니다
📌 [feat/#30] 4주차 미션_제로
DataStore와 Gson을 연동하여 앱 내 상품 데이터(위시리스트 상태)를 영구 저장하고, 구매하기 화면에 Tab Layout을 구현하여 5주차 과제 기반을 마련했습니다.
🔗 관련 이슈
Closes #30
✨ 변경 사항
-> 5주차 과제 수행을 위해 필요한 빈 Fragment들을 생성하고 연결했습니다.
비동기 처리 및 DataStore로 더미 데이터 대체하기
홈 화면 나이키 최신 상품, 구매하기, 위시리스트 전부 DataStore로 변경하기
data class를 저장하기 위해선 Proto DataStore 방식도 존재하지만 저희는 json으로 변환하는 방식으로 함.
위시리스트 기능(하트 기능) 구현하기
구매하기 페이지에 Tab기능 추가하기
Top & T-shirts, sale 의 Tab으로 빈 화면의 Fragment 생성
🔍 테스트
📸 스크린샷 (선택)
실행영상
umc_android_zero_4th_run_video.mp4
🚨 추가 이슈