-
Notifications
You must be signed in to change notification settings - Fork 47
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
[둘리] 3, 4단계 쇼핑 장바구니 제출합니다. #33
Merged
Merged
Changes from 1 commit
Commits
Show all changes
47 commits
Select commit
Hold shift + click to select a range
6f04e7e
refactor: 함수 간소화
hyemdooly e7af72c
refactor: supportActionBar Label 설정 삭제, manifest 이용
hyemdooly 6977e5f
refactor: test 코드 수정
hyemdooly 8c85cf2
feat: ProductList 상품 장바구니 추가 뷰 수정
hyemdooly 723c091
docs: 3단계 요구사항 정리
hyemdooly b528d57
feat: 장바구니 버튼 생성
hyemdooly fd660c5
feat: ProductDetail 수량 선택 Dialog 구현
hyemdooly e9a1b6c
feat: CartActivity 하단 뷰 구현
hyemdooly 7181e9b
feat: CartActivity Item layout 변경사항 수정
hyemdooly 27b2a1b
feat: cart badge 생성
hyemdooly dd70d3b
feat: ProductListActivity List Count 구현
hyemdooly e230169
feat: ProductListActivity AppBar Cart Badge 구현
hyemdooly 15dc571
feat: ProductDetailActivity 마지막으로 본 상품 startActivity
hyemdooly 588a1ee
feat: ProductDetailActivity 다른 액티비티 실행 시 Stack 조절
hyemdooly dc79515
feat: Cart 아이콘 장바구니 비었으면 Gone으로 수정
hyemdooly 7d0a2e3
feat: Cart 아이콘 장바구니 비었으면 Gone으로 수정
hyemdooly 8f145f4
Merge remote-tracking branch 'origin/step4' into step4
hyemdooly 9370658
feat: ProductListPresenter에서 삭제했던 최근 본 상품 복구
hyemdooly 0337194
refactor: domain 코드 이동, ktlintformat
hyemdooly 3e7fc30
feat: CartActivity 상품 개수 업데이트 구현
hyemdooly 1c419ad
feat: CartActivity, CartSystem 선택 구현 (리팩토링 필수)
hyemdooly 49e6293
feat: ProductListActivity <-> CartActivity 데이터 동일하게 연동
hyemdooly 3200e3a
refactor: CartActivity LiveData 활용 리팩터링
hyemdooly cbcd2f4
refactor: DataBinding format 수정
hyemdooly 01b5db9
fix: CartActivity 버그 수정
hyemdooly 57a2b4d
refactor: ProductListActivity Presenter 리팩터링
hyemdooly f6d3645
fix: ProductListActivity Presenter 리팩터링 및 버그 수정
hyemdooly b5e1269
refactor: CartPresenterTest 코드 수정에 맞게 리팩터링 및 수정
hyemdooly dc3106f
refactor: ProductDetailPresenterTest 리팩터링 및 수정
hyemdooly 47cb4a5
refactor: ProductListPresenterTest 수정, CartPresenterTest 테스트 통과 안되는 …
hyemdooly e23cdba
refactor: formatting
hyemdooly 65cade1
feat: 4단계 MockServer 구현 및 적용
hyemdooly b3e732f
refactor: 강제종료 버그 수정, 패키지 정리
hyemdooly 6869b1f
fix: 최근 본 상품 반대로 나오는 버그 수정, ProductDetialActivity 다이얼로그 dismiss 추가
hyemdooly ebdc9bd
docs: README 업데이트
hyemdooly ba1d77f
fix: 갯수 제한 걸리는 버그 수정
hyemdooly 2797d74
Merge remote-tracking branch 'origin/step4' into step4
hyemdooly 5cf4f06
refactor: CartProductModel의 isChecked, count variable -> valuable로 변경
hyemdooly c291ea5
refactor: ProductModel variable -> valuable로 수정
hyemdooly 508e204
refactor: backing property 변수 위치 수정
hyemdooly b04a4af
refactor: lateinit var -> by lazy로 최대한 수정
hyemdooly 8d09837
refactor: presenter에서 데이터를 내려주도록 수정
hyemdooly a9268da
refactor: AppCompatButton -> Button으로 수정
hyemdooly 9bac38d
refactor: 요구사항에 없는 내용 삭제
hyemdooly 261e924
refactor: 테스트코드 로직 최대한 삭제
hyemdooly 9ec4930
refactor: ProductViewHolder 생성자에서 onClick 등록
hyemdooly 1227d57
refactor: plus, minus 한계치 수정
hyemdooly File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
refactor: CartActivity LiveData 활용 리팩터링
- Loading branch information
commit 3200e3a96cee262602d40577b39c506517b14133
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
app/src/main/java/woowacourse/shopping/model/CartProductModel.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
package woowacourse.shopping.model | ||
|
||
data class CartProductModel(var isChecked: Boolean, val id: Int, val name: String, val imageUrl: String, val count: Int, val totalPrice: Int) | ||
data class CartProductModel(var isChecked: Boolean, val id: Int, val name: String, val imageUrl: String, var count: Int, val price: Int) | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 7 additions & 1 deletion
8
app/src/main/java/woowacourse/shopping/view/cart/CartContract.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
package woowacourse.shopping.view.cart | ||
|
||
import androidx.lifecycle.LiveData | ||
import androidx.lifecycle.MutableLiveData | ||
import woowacourse.shopping.domain.* | ||
import woowacourse.shopping.model.CartProductModel | ||
import woowacourse.shopping.model.toDomain | ||
|
@@ -8,86 +10,87 @@ import woowacourse.shopping.model.toUiModel | |
class CartPresenter( | ||
private val view: CartContract.View, | ||
private val cartRepository: CartRepository, | ||
private val productRepository: ProductRepository | ||
private val productRepository: ProductRepository, | ||
) : CartContract.Presenter { | ||
private val cartPagination = CartPagination(PAGINATION_SIZE, cartRepository) | ||
private val cartSystem = CartSystem(productRepository) | ||
|
||
private val currentCartProducts = | ||
convertToCartProductModels(cartPagination.nextItems()).toMutableList() | ||
private val cartItems = | ||
( | ||
currentCartProducts.map { CartViewItem.CartProductItem(it) } + | ||
CartViewItem.PaginationItem(cartPagination.status) | ||
private val cartItems: MutableList<CartViewItem> | ||
|
||
private var _cartSystemResult = MutableLiveData(CartSystemResult(0, 0)) | ||
private var _cartPageStatus = MutableLiveData( | ||
CartPageStatus( | ||
isPrevEnabled = false, | ||
isNextEnabled = false, | ||
0 | ||
) | ||
) | ||
private var _isCheckedAll = MutableLiveData(false) | ||
|
||
override val cartSystemResult: LiveData<CartSystemResult> | ||
get() = _cartSystemResult | ||
override val cartPageStatus: LiveData<CartPageStatus> | ||
get() = _cartPageStatus | ||
override val isCheckedAll: LiveData<Boolean> | ||
get() = _isCheckedAll | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 라이브데이터는 흔히 backing property 기법을 사용합니다. |
||
|
||
init { | ||
val models = convertCartProductToModels(cartPagination.nextItems()) | ||
cartItems = (models.map { CartViewItem.CartProductItem(it) } | ||
+ CartViewItem.PaginationItem(cartPagination.status) | ||
).toMutableList() | ||
} | ||
|
||
override fun fetchProducts() { | ||
view.showProducts(cartItems) | ||
view.showTotalResult(false, 0, 0) | ||
} | ||
|
||
override fun removeProduct(id: Int) { | ||
val nextItemExist = cartPagination.isNextEnabled | ||
val removedItem = currentCartProducts.find { it.id == id } | ||
cartRepository.remove(id) | ||
cartItems.removeAt(currentCartProducts.indexOf(removedItem)) | ||
currentCartProducts.remove(removedItem) | ||
val result = cartSystem.removeProduct(id) | ||
view.showTotalResult( | ||
cartSystem.selectedProducts.containsAll(currentCartProducts.map { product -> product.toDomain() }), | ||
result.totalPrice, | ||
result.totalCount | ||
) | ||
cartItems.removeIf { it is CartViewItem.CartProductItem && it.product.id == id } | ||
_cartSystemResult.value = cartSystem.removeProduct(id) | ||
_isCheckedAll.value = getIsCheckedAll() | ||
|
||
// 남은 자리 페이지 뒷 상품으로 다시 채우기 | ||
if (nextItemExist) { | ||
cartItems.removeLast() | ||
fillProductInBlank() | ||
cartItems.add(CartViewItem.PaginationItem(cartPagination.status)) | ||
view.showChangedItems() | ||
return | ||
} | ||
if (nextItemExist) addNextProduct() | ||
view.showChangedItems() | ||
} | ||
|
||
override fun selectAll(isChecked: Boolean) { | ||
val products = if (isChecked) { | ||
cartItems.filterIsInstance<CartViewItem.CartProductItem>().forEachIndexed { index, it -> | ||
it.product.isChecked = true | ||
view.showChangedItem(index) | ||
} | ||
|
||
currentCartProducts.map { it.toDomain() } - cartSystem.selectedProducts.toSet() | ||
} else { | ||
cartItems.filterIsInstance<CartViewItem.CartProductItem>().forEachIndexed { index, it -> | ||
it.product.isChecked = false | ||
view.showChangedItem(index) | ||
} | ||
currentCartProducts.map { it.toDomain() }.intersect(cartSystem.selectedProducts.toSet()) | ||
private fun addNextProduct() { | ||
cartItems.removeLast() | ||
getNextCartProductModel()?.let { | ||
cartItems.add(CartViewItem.CartProductItem(it)) | ||
} | ||
cartItems.add(CartViewItem.PaginationItem(cartPagination.status)) | ||
} | ||
|
||
var result: CartSystemResult? = null | ||
products.forEach { | ||
result = cartSystem.selectProduct(it) | ||
} | ||
result?.let { | ||
view.showTotalResult( | ||
isChecked, | ||
it.totalPrice, | ||
it.totalCount | ||
) | ||
} | ||
private fun getIsCheckedAll() = | ||
cartSystem.selectedProducts.containsAll(convertItemsToCartProduct(cartItems)) | ||
|
||
return | ||
private fun getNextCartProductModel(): CartProductModel? { | ||
val product = cartPagination.currentLastItem() ?: return null | ||
return product.toUiModel( | ||
cartSystem.isSelectedProduct(product), | ||
productRepository.find(product.id) | ||
) | ||
} | ||
|
||
private fun fillProductInBlank() { | ||
val product = cartPagination.currentLastItem() ?: return | ||
val productModel = product.toUiModel(cartSystem.isSelectedProduct(product), productRepository.find(product.id)) | ||
currentCartProducts.add(productModel) | ||
cartItems.add(CartViewItem.CartProductItem(productModel)) | ||
} | ||
override fun selectAll(isChecked: Boolean) { | ||
cartItems.filterIsInstance<CartViewItem.CartProductItem>().forEachIndexed { index, it -> | ||
it.product.isChecked = isChecked | ||
view.showChangedItem(index) | ||
} | ||
|
||
val products = if (isChecked) { // 전체 선택 | ||
convertItemsToCartProduct(cartItems) - cartSystem.selectedProducts.toSet() | ||
} else { // 전체 해제 | ||
convertItemsToCartProduct(cartItems).intersect(cartSystem.selectedProducts.toSet()) | ||
} | ||
products.forEach { | ||
_cartSystemResult.value = cartSystem.selectProduct(it) | ||
} | ||
_isCheckedAll.value = isChecked | ||
} | ||
|
||
override fun fetchNextPage() { | ||
val items = cartPagination.nextItems() | ||
|
@@ -105,48 +108,36 @@ class CartPresenter( | |
} | ||
} | ||
|
||
private fun changeListItems(items: List<CartProduct>) { | ||
val models = convertCartProductToModels(items) | ||
cartItems.clear() | ||
cartItems.addAll(models.map { CartViewItem.CartProductItem(it) }) | ||
cartItems.add(CartViewItem.PaginationItem(cartPagination.status)) | ||
} | ||
|
||
override fun updateCartProductCount(id: Int, count: Int) { | ||
cartRepository.update(id, count) | ||
currentCartProducts.find { it.id == id }?.let { | ||
val index = currentCartProducts.indexOf(it) | ||
currentCartProducts[index] = CartProductModel( | ||
it.isChecked, | ||
it.id, | ||
it.name, | ||
it.imageUrl, | ||
count, | ||
it.totalPrice / it.count * count | ||
) | ||
cartItems[index] = CartViewItem.CartProductItem(currentCartProducts[index]) | ||
val cartProducts = convertItemsToCartProduct(cartItems) | ||
cartProducts.find { it.id == id }?.let { | ||
val index = cartProducts.indexOf(it) | ||
(cartItems[index] as CartViewItem.CartProductItem).product.count = count | ||
view.showChangedItem(index) | ||
val systemResult = cartSystem.updateProduct(id, count) | ||
view.showTotalResult( | ||
cartSystem.selectedProducts.containsAll(currentCartProducts.map { product -> product.toDomain() }), | ||
systemResult.totalPrice, | ||
systemResult.totalCount | ||
) | ||
_cartSystemResult.value = cartSystem.updateProduct(id, count) | ||
} | ||
} | ||
|
||
override fun selectProduct(product: CartProductModel) { | ||
val result = cartSystem.selectProduct(product.toDomain()) ?: return | ||
view.showTotalResult( | ||
cartSystem.selectedProducts.containsAll(currentCartProducts.map { product -> product.toDomain() }), | ||
result.totalPrice, | ||
result.totalCount | ||
) | ||
_cartSystemResult.value = cartSystem.selectProduct(product.toDomain()) | ||
_isCheckedAll.value = getIsCheckedAll() | ||
} | ||
|
||
private fun convertToCartProductModels(cartProducts: List<CartProduct>) = | ||
cartProducts.map { it.toUiModel(cartSystem.isSelectedProduct(it), productRepository.find(it.id)) } | ||
private fun convertCartProductToModels(cartProducts: List<CartProduct>) = | ||
cartProducts.map { | ||
it.toUiModel(cartSystem.isSelectedProduct(it), productRepository.find(it.id)) | ||
}.toMutableList() | ||
|
||
private fun changeListItems(items: List<CartProduct>) { | ||
currentCartProducts.clear() | ||
currentCartProducts.addAll(convertToCartProductModels(items)) | ||
cartItems.clear() | ||
cartItems.addAll(currentCartProducts.map { CartViewItem.CartProductItem(it) }) | ||
cartItems.add(CartViewItem.PaginationItem(cartPagination.status)) | ||
} | ||
private fun convertItemsToCartProduct(items: List<CartViewItem>): List<CartProduct> = | ||
items.filterIsInstance<CartViewItem.CartProductItem>().map { it.product.toDomain() } | ||
|
||
companion object { | ||
private const val PAGINATION_SIZE = 5 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
data class에서 isChecked 변수를 variable로 정의하셨네요.
var로 선언하게되면 외부에서 isChecked에 접근하여 얼마든지 상태를 변경할 수 있기 때문에, isChecked 를 참조하고 있는 곳에 예상치 못한 동작이 발생할 수 있어요.
외부에서 변경하지 못하도록 개선해보면 어떨까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
valuable로 수정하고 프레젠터에서 리스트의 아이템을 복사해서 다시 넣어주도록 수정했습니다!