Skip to content

Commit

Permalink
[부나] 2단계 재화 미션 제출합니다. (#26)
Browse files Browse the repository at this point in the history
* feat: 하마드 서버 base url 추가

* feat(Page): 공통 코드를 Page 클래스로 이동

* docs: 주문 기능 구현 기능 목록 작성

* chore: Retrofit 라이브러리 추가

* feat: RetrofitServiceCreater 구현

* refactor: OkHttpClient를 Retrofit으로 리팩터링

* feat: 상품 주문하기 ui 구현

* feat: 주문할 상품을 보여주는 화면 구현

* feat: PointEditText 커스텀뷰 구현

* feat: 장바구니 아이템 주문하는 기능 구현

* feat: 쇼핑 목록 화면으로 이동하는 기능 구현

* feat: 주문 목록을 불러오는 기능 구현

* feat: 상세 주문 내역을 보여주는 기능 구현

* fix: 상품 주문시, 상품 id와 수량을 서버에 보내는 대신 cartItemId를 전달하도록 변경

* refactor: RecyclerViewBindingAdapter의 setAdapter 메서드의 인자를 ConcatAdapter에서 RecyclerViewAdapter로 변경

* refactor: ORDER_DETAIL과 ORDER 뷰타입의 value를 OrderProduct에서 관리하도록 변경

* refactor: cartItemIds를 orderItems로 변경

* chore: kotlinx.serialization 라이브러리 추가

* refactor: Dto에 Serializable 어노테이션 추가

* feat: 각 화면별로 뒤로가기 기능 구현

* refactor: 라인 포맷팅

* refactor: isolatedViewTypeConcatAdapter을 notIsolatedViewTypeConcatAdapter로 변경

* feat: 스낵바를 보여주는 확장함수 구현

* refactor: 상품 주문 완료시 스낵바로 메시지를 보여주도록 변경

* refactor: 사용하지 않는 클래스, 메서드 제거

* refactor: ShoppingDatabase를 싱클톤으로 변경

* refactor: inject 메서드명을 명시적으로 변경

* refactor: ui의 CartProduct typealias를 제거하고 Model suffix를 붙이도록 변경

* refactor: ui의 OrderModel typealias를 제거하고 Model suffix를 붙이도록 변경

* refactor: ui의 OrderProductModel typealias를 제거하고 Model suffix를 붙이도록 변경

* refactor: ui의 UiPage typealias를 제거하고 Model suffix를 붙이도록 변경

* refactor: ui의 UiPayment typealias를 제거하고 Model suffix를 붙이도록 변경

* refactor: ui의 PointUi typealias를 제거하고 Model suffix를 붙이도록 변경

* refactor: ui의 PriceUi typealias를 제거하고 Model suffix를 붙이도록 변경

* refactor: ui의 UiProduct typealias를 제거하고 Model suffix를 붙이도록 변경

* refactor: ui의 UiProductCount typealias를 제거하고 Model suffix를 붙이도록 변경

* refactor: ui의 UiRecentProduct typealias를 제거하고 Model suffix를 붙이도록 변경

* refactor: 함수 네이밍 통일화

* refactor: 재화 관련 도메인을 추상화

* refactor: OrderPresenter 중복 코드를 메서드로 분리

* refactor: Ui 모델 파라미터명을 cartProductModel로 변경

* refactor: 네이밍 통일화

* refactor: abstract class를 interface로 변경

* refactor: page 관련 뷰 업데이트를 하나의 추상 메서드로 변경

* refactor: OrderActivity의 showOrders 메서드명 변경

* refactor: PaymentRequest의 SerializedName 파라미터명 변경

* test: ProductDetailPresenter 테스트 코드 작성

* test: ShoppingPresenter 테스트 코드 작성

* test: OrderPresenter 테스트 코드 작성

* feat: 응답에 대해 response의 body null 여부를 검사하도록 변경

* refactor: typealias가 적용되지 않은 ProductId에 typealias 적용

* fix: item_order_history.xml에서 binding type이 맞지 않아 크래시 발생하는 버그 수정

* fix: item_order_history.xml에서 제품 이미지뷰에 scaleType 적용

* feat: 상세 주문 내역 뒤로가기 기능 구현

* feat: Gson의 SerializedName을 kotlinx-serialization의 SerialName으로 변경

* chore: Gson 라이브러리 의존성 제거

* fix: gson 라이브러리 import 제거

* fix: 주문 상세 리사이클러뷰에서 아이템이 보여지지 않는 버그 수정

* feat: 주문 상세 아이템의 상품 이미지에 scaleType(centerCrop) 적용

* fix: 결제 아이템 뷰의 높이를 wrap_content로 변경

* fix: CounterView의 숫자를 클릭하면 뒤의 배경이 클릭되는 버그 수정

* refactor: Log 출력 제거

* refactor: 코드 포맷팅

* fix: 토큰 설정이 안 되었던 버그 수정

* refactor: 주문 목록 가져오는 api body 형식 변경에 따른 dto 변경

* feat: 필요 없는 않는 json 변환 옵션 제거

- isLenient
- ignoreUnknownKeys

* refactor: toText() 시그니처 대신 toString()을 오버라이드하여 사용하도록 변경

* refactor: 제품 가져오기 페이지네이션 api 적용

* refactor: 주문 목록 api 변경에 따른 스펙 변경

* refactor: findCartProductByProductId의 실패 콜백 람다의 인자 변경

* refactor: 장바구니에 담긴 제품 개수를 매번 서버에 요청하도록 변경

* refactor: Repository 네이밍의 Impl을 Default로 변경

* feat: 주문 목록 페이징 구현

* fix: 쇼핑 리스트 페이지네이션이 동작하지 않는 버그 수정

* refactor: 주문 목록 더 보기 기능에서 take 함수를 호출하지 않도록 변경

* fix: 최근 상품 목록에서 장바구니 개수가 담기지 않는 버그 수정

* fix: 최근 상품 디테일 화면에서 상품 개수를 더해지지 않는 버그 수정

* fix: 커스텀뷰에서 TypedArray 인스턴스에 use 사용를 사용하는 대신 recycle() 메서드를 호출하도록 변경

- API 31 미만에서는 크래시 발생
  • Loading branch information
tmdgh1592 authored Jun 5, 2023
1 parent 1f8ac9a commit c08795c
Show file tree
Hide file tree
Showing 202 changed files with 3,763 additions and 1,328 deletions.
34 changes: 30 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,35 @@
# android-shopping-order

## UI
- [ ] 데이터가 로딩되기 전 상태에서는 스켈레톤 UI를 노출한다.
- [ ] 메인 액티비티가 로딩되기 전에 서버를 선택한다.
- [x] 데이터가 로딩되기 전 상태에서는 스켈레톤 UI를 노출한다.
- [x] 메인 액티비티가 로딩되기 전에 서버를 선택한다.

## Domain
- [ ] 사용자 인증 정보를 저장한다.
- [ ] 서버를 선택하여 교체할 수 있다.
- [x] 사용자 인증 정보를 저장한다.
- [x] 서버를 선택하여 교체할 수 있다.
- [x] 장바구니에 담은 상품을 주문할 수 있다.
```gherkin
Given 장바구니에서 주문할 상품을 선택한다.
When 상품을 주문한다.
Then 주문이 완료되면 성공 메시지를 보여준다.
```
- [x] 상품 주문시 포인트를 적용할 수 있다.
```gherkin
Given 장바구니에서 선택된 상품이 존재한다.
And 포인트가 존재한다.
When 상품을 주문한다.
Then 포인트가 적용된 가격으로 주문한다.
```
- [x] 사용자 별로 주문 목록을 확인할 수 있다.
```gherkin
Given 사용자가 주문한 상품이 존재한다.
When 주문 목록을 확인한다.
Then 주문 목록을 보여준다.
```
- [x] 특정 주문의 상세 정보를 확인할 수 있다.
```gherkin
Given 주문한 목록이 존재한다.
When 특정 주문을 조회한다.
Then 특정 주문의 상세 정보를 보여준다.
```
- [x] 서버 통신을 Retrofit으로 리팩터링한다.
11 changes: 11 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ plugins {
id("org.jetbrains.kotlin.android")
id("kotlin-kapt")
id("kotlin-parcelize")
kotlin("plugin.serialization") version "1.8.21"
}

android {
Expand All @@ -28,13 +29,16 @@ android {
)
}
}

compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}

kotlinOptions {
jvmTarget = "11"
}

dataBinding {
enable = true
}
Expand Down Expand Up @@ -68,4 +72,11 @@ dependencies {
implementation("com.squareup.okhttp3:okhttp:4.11.0")
implementation("com.squareup.okhttp3:mockwebserver:4.11.0")
testImplementation("com.squareup.okhttp3:mockwebserver:4.11.0")

// Retrofit
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0")

// kotlinx-serializable
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
}
11 changes: 10 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
android:theme="@style/Theme.Shopping"
android:usesCleartextTraffic="true"
tools:targetApi="31">
<activity
android:name=".ui.orderdetail.OrderDetailActivity"
android:exported="false" />
<activity
android:name=".ui.orderhistory.OrderHistoryActivity"
android:exported="false" />
<activity
android:name=".ui.serversetting.ServerSettingActivity"
android:exported="true">
Expand All @@ -24,11 +30,14 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ui.order.OrderActivity"
android:exported="false" />
<activity
android:name=".ui.cart.CartActivity"
android:exported="true" />
<activity
android:name=".ui.detail.ProductDetailActivity"
android:name=".ui.productdetail.ProductDetailActivity"
android:exported="true" />
<activity
android:name=".ui.shopping.ShoppingActivity"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package woowacourse.shopping.data.dao.recentproduct

import woowacourse.shopping.data.model.DataRecentProduct
import woowacourse.shopping.data.entity.RecentProductEntity

interface RecentProductDao {
fun getSize(): Int
fun getRecentProductsPartially(size: Int): List<DataRecentProduct>
fun addRecentProduct(item: DataRecentProduct)
fun removeLast()
fun getRecentProducts(size: Int): List<RecentProductEntity>
fun saveRecentProduct(item: RecentProductEntity)
fun deleteLast()
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ import android.content.ContentValues
import android.database.sqlite.SQLiteOpenHelper
import android.provider.BaseColumns
import woowacourse.shopping.data.database.contract.RecentProductContract
import woowacourse.shopping.data.model.DataPrice
import woowacourse.shopping.data.model.DataRecentProduct
import woowacourse.shopping.data.model.Product
import woowacourse.shopping.data.entity.ProductEntity
import woowacourse.shopping.data.entity.RecentProductEntity

class RecentProductDaoImpl(private val database: SQLiteOpenHelper) : RecentProductDao {

Expand All @@ -23,8 +22,8 @@ class RecentProductDaoImpl(private val database: SQLiteOpenHelper) : RecentProdu
}

@SuppressLint("Range")
override fun getRecentProductsPartially(size: Int): List<DataRecentProduct> {
val products = mutableListOf<DataRecentProduct>()
override fun getRecentProducts(size: Int): List<RecentProductEntity> {
val products = mutableListOf<RecentProductEntity>()
val db = database.writableDatabase
val cursor = db.rawQuery(GET_PARTIALLY_QUERY, arrayOf(size.toString()))
while (cursor.moveToNext()) {
Expand All @@ -33,27 +32,28 @@ class RecentProductDaoImpl(private val database: SQLiteOpenHelper) : RecentProdu
cursor.getInt(cursor.getColumnIndex(RecentProductContract.COLUMN_PRODUCT_ID))
val name: String =
cursor.getString(cursor.getColumnIndex(RecentProductContract.COLUMN_NAME))
val price: DataPrice =
DataPrice(cursor.getInt(cursor.getColumnIndex(RecentProductContract.COLUMN_PRICE)))
val price =
cursor.getInt(cursor.getColumnIndex(RecentProductContract.COLUMN_PRICE))
val imageUrl: String =
cursor.getString(cursor.getColumnIndex(RecentProductContract.COLUMN_IMAGE_URL))
products.add(DataRecentProduct(id, Product(productId, name, price, imageUrl)))
products.add(RecentProductEntity(id, ProductEntity(productId, name, price, imageUrl)))
}
cursor.close()
return products
}

override fun addRecentProduct(item: DataRecentProduct) {
override fun saveRecentProduct(item: RecentProductEntity) {
val contentValues = ContentValues().apply {
put(RecentProductContract.COLUMN_NAME, item.product.name)
put(RecentProductContract.COLUMN_PRICE, item.product.price.value)
put(RecentProductContract.COLUMN_PRODUCT_ID, item.product.id)
put(RecentProductContract.COLUMN_PRICE, item.product.price)
put(RecentProductContract.COLUMN_IMAGE_URL, item.product.imageUrl)
}

database.writableDatabase.insert(RecentProductContract.TABLE_NAME, null, contentValues)
}

override fun removeLast() {
override fun deleteLast() {
val db = database.writableDatabase
db.rawQuery(REMOVE_LAST_QUERY, null).close()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import android.database.sqlite.SQLiteOpenHelper
import woowacourse.shopping.data.database.contract.RecentProductContract

const val DATABASE_NAME = "ShoppingDatabase.db"
const val DATABASE_VERSION = 12
const val DATABASE_VERSION = 13

class ShoppingDatabase(context: Context) :
class ShoppingDatabase private constructor(context: Context) :
SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) {
override fun onCreate(db: SQLiteDatabase?) {
db?.execSQL(RecentProductContract.CREATE_TABLE_QUERY)
Expand All @@ -18,4 +18,17 @@ class ShoppingDatabase(context: Context) :
db?.execSQL(RecentProductContract.DELETE_TABLE_QUERY)
onCreate(db)
}

companion object {
private var database: ShoppingDatabase? = null

fun get(context: Context): ShoppingDatabase {
if (database == null) {
synchronized(this) {
if (database == null) database = ShoppingDatabase(context)
}
}
return database!!
}
}
}
26 changes: 26 additions & 0 deletions app/src/main/java/woowacourse/shopping/data/dto/CartDto.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package woowacourse.shopping.data.dto

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

@Serializable
data class CartGetResponse(
@SerialName("id")
val id: Int,
@SerialName("quantity")
val quantity: Int,
@SerialName("product")
val product: ProductItemResponse,
)

@Serializable
data class CartAddRequest(
@SerialName("productId")
val productId: Int,
)

@Serializable
data class CartPatchRequest(
@SerialName("quantity")
val quantity: Int,
)
48 changes: 48 additions & 0 deletions app/src/main/java/woowacourse/shopping/data/dto/OrderDto.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package woowacourse.shopping.data.dto

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

@Serializable
data class OrdersResponse(
@SerialName("pageInfo")
val pageInfo: PageInfoResponse,
@SerialName("orders")
val orders: List<OrderResponse> = listOf(),
)

@Serializable
data class OrderResponse(
@SerialName("orderId")
val orderId: Int,
@SerialName("orderedProducts")
val orderedProducts: List<OrderProductResponse> = listOf(),
@SerialName("payment")
val payment: PaymentResponse,
)

@Serializable
data class OrderProductResponse(
@SerialName("name")
val name: String,
@SerialName("price")
val price: Int,
@SerialName("quantity")
val quantity: Int,
@SerialName("imageUrl")
val imageUrl: String,
)

@Serializable
data class OrderPostRequest(
@SerialName("orderItems")
val orderItems: List<OrderItem>,
@SerialName("payment")
val payment: PaymentRequest,
)

@Serializable
data class OrderItem(
@SerialName("cartItemId")
val cartItemId: Int,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package woowacourse.shopping.data.dto

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

@Serializable
data class PageInfoResponse(
@SerialName("page")
val page: Int,
@SerialName("size")
val size: Int,
@SerialName("totalElements")
val totalElements: Int,
@SerialName("totalPages")
val totalPages: Int,
)
24 changes: 24 additions & 0 deletions app/src/main/java/woowacourse/shopping/data/dto/PaymentDto.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package woowacourse.shopping.data.dto

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

@Serializable
data class PaymentResponse(
@SerialName("originalPayment")
val originalPayment: Int = 0,
@SerialName("finalPayment")
val finalPayment: Int = 0,
@SerialName("point")
val point: Int = 0,
)

@Serializable
data class PaymentRequest(
@SerialName("originalPayment")
val originalPayment: Int,
@SerialName("finalPayment")
val finalPayment: Int,
@SerialName("point")
val usedPoint: Int,
)
10 changes: 10 additions & 0 deletions app/src/main/java/woowacourse/shopping/data/dto/PointDto.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package woowacourse.shopping.data.dto

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

@Serializable
data class PointResponse(
@SerialName("availablePoint")
val availablePoint: Int = 0,
)
54 changes: 54 additions & 0 deletions app/src/main/java/woowacourse/shopping/data/dto/ProductDto.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package woowacourse.shopping.data.dto

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

@Serializable
data class ProductsResponse(
@SerialName("pageInfo")
val pageInfo: PageInfoResponse,
@SerialName("products")
val products: List<ProductItemResponse> = listOf(),
)

@Serializable
data class ProductItemResponse(
@SerialName("id")
val id: Int,
@SerialName("imageUrl")
val imageUrl: String,
@SerialName("name")
val name: String,
@SerialName("price")
val price: Int,
)

@Serializable
data class ProductPostRequest(
@SerialName("name")
val name: String,
@SerialName("price")
val price: Int,
@SerialName("imageUrl")
val imageUrl: String,
)

@Serializable
data class ProductPutRequest(
@SerialName("name")
val name: String,
@SerialName("price")
val price: Int,
@SerialName("imageUrl")
val imageUrl: String,
)

@Serializable
data class ProductDeleteRequest(
@SerialName("name")
val name: String,
@SerialName("price")
val price: Int,
@SerialName("imageUrl")
val imageUrl: String,
)
Loading

0 comments on commit c08795c

Please sign in to comment.