Skip to content

Commit 379d33d

Browse files
authored
[PC-1355] 결제 성공 후 완료 모달 구현 (#170)
* [PC-1355] 스토어 이동 시 BillingClient 중복 생성 방지 BillingHelper를 ViewModelScoped로 변경하여 Store 이동 시 BillingClient 중복 생성과 결제 중복 문제 해결 * [PC-1355] 일회성 결제 로직에 인정 및 소비 처리 추가 - INAPP 일회성 결제 상품 처리 로직 추가 - 결제 완료 후 상품을 먼저 인정(acknowledge)하고 소비(consume)하도록 수정 - 중복 토큰 처리 방지 * [PC-1355] 결제 성공 후 완료 모달 구현 - 현재 구매 성공 후 모달 구현 - /api/payments/in-app << api 실패 - 구매한 퍼즐 개수를 모름 << 알아낼 방법 회의 필요 * Revert "[PC-1355] 일회성 결제 로직에 인정 및 소비 처리 추가" This reverts commit 8568c15. * [PC-1355] 결제 성공 모달 인자(구매한 퍼즐의 수) 추가 * [PC-1355] 오타 수정 * [PC-1355] BillingClient 생성 및 해제 시점에 로그 * [PC-1355] purchasedPuzzleCount를 ViewModel state로 관리하도록 변경 * [PC-1355] 오타 수정 * [PC-1355] 구매 검증 API 응답에 rewardPuzzleCount 추가 및 모달에 표시 * [PC-1355] 현재 퍼즐 수 업데이트 로직 위치 변경 * [PC-1355] 현재 유저의 퍼즐 조회 API 세팅 * [PC-1355] store 화면 진입 시 현재 유저의 퍼즐 조회 * [PC-1355] 결제 검증 성공 시 서버에서 최신 퍼즐 개수 재조회하도록 수정 * [PC-1355] FakeUserDataSource에서 getUserPuzzle 미구현으로 인한 CI 실패 수정 * [PC-1355] FakeUserRepository에서 getUserPuzzle 미구현으로 인한 CI 실패 수정 * [PC-1355] FakeUserRepository에 setUserPuzzle 추가 * [PC-1355] 하드코딩된 문자열을 리소스로 분리 * [PC-1355] 테스트 끝난 로직 로그 제거 * [PC-1355] 뷰모델 init에서 getUserPuzzle이 병렬로 처리되도록 변경 * [PC-1355] StoreLoadingScreen 구현 * [PC-1355] Store 화면 관련 파일 구조 정리 * [PC-1355] Store 로딩 화면 Compact, Expanded 구분 * [PC-1355} StoreLoading 애니메이션 로직 변경 * [PC-1355] 구매 성공 모달 테스트 코드 작성 * [PC-1355] StoreLoading 로직 추가 * [PC-1355] 프로퍼티 명 변경 (puzzleCount -> count) * [PC-1355] async -> launch 변경 * [PC-1355] 컴포넌트 Preview 작성 * [PC-1355] Store 설명 문자열 리소스로 분리 * [PC-1355] 스켈레톤 애니메이션 로직 분리 * [PC-1355] 반환값 List -> ImmutableList
1 parent ae56869 commit 379d33d

File tree

34 files changed

+1007
-340
lines changed

34 files changed

+1007
-340
lines changed

core/billing/src/main/java/com/puzzle/billing/data/BillingHelperImpl.kt

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,16 @@ import com.puzzle.billing.domain.PaymentRepository
1717
import com.puzzle.billing.model.NormalProduct
1818
import com.puzzle.billing.model.PieceProduct
1919
import com.puzzle.billing.model.PromotionProduct
20-
import com.puzzle.common.suspendRunCatching
21-
import com.puzzle.domain.model.error.ErrorHelper
2220
import com.puzzle.domain.model.payment.CashProduct
2321
import com.puzzle.domain.model.payment.Product
2422
import com.puzzle.domain.model.payment.PurchaseProduct
2523
import dagger.hilt.android.qualifiers.ApplicationContext
26-
import dagger.hilt.android.scopes.ViewModelScoped
2724
import kotlinx.collections.immutable.ImmutableList
28-
import kotlinx.collections.immutable.persistentListOf
2925
import kotlinx.collections.immutable.toImmutableList
30-
import kotlinx.coroutines.CoroutineScope
3126
import kotlinx.coroutines.Dispatchers
32-
import kotlinx.coroutines.SupervisorJob
3327
import kotlinx.coroutines.flow.MutableStateFlow
3428
import kotlinx.coroutines.flow.StateFlow
3529
import kotlinx.coroutines.flow.asStateFlow
36-
import kotlinx.coroutines.launch
3730
import kotlinx.coroutines.suspendCancellableCoroutine
3831
import kotlinx.coroutines.withContext
3932
import javax.inject.Inject
@@ -67,7 +60,9 @@ class BillingHelperImpl @Inject constructor(
6760
.setListener(purchasesUpdatedListener)
6861
.enablePendingPurchases(pendingPurchasesParams)
6962
.enableAutoServiceReconnection()
70-
.build()
63+
.build().also{
64+
Log.d("BillingClient", "BillingClient created")
65+
}
7166

7267
override suspend fun getAvailableProducts(): CashProduct = paymentRepository.getAvailableProduct()
7368

@@ -174,4 +169,13 @@ class BillingHelperImpl @Inject constructor(
174169
}
175170
}
176171

172+
override fun release() {
173+
if (billingClient.isReady) {
174+
Log.d("BillingClient", "BillingClient connection closing...")
175+
billingClient.endConnection()
176+
} else {
177+
Log.d("BillingClient", "BillingClient release called, but it wasn't ready")
178+
}
179+
}
180+
177181
}

core/billing/src/main/java/com/puzzle/billing/data/PaymentRepositoryImpl.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@ class PaymentRepositoryImpl @Inject constructor(
1313
paymentDataSource.getAvailableProduct().toDomain()
1414

1515
override suspend fun verifyPurchaseProduct(purchaseProduct: PurchaseProduct) =
16-
paymentDataSource.verifyPurchaseProduct(purchaseProduct)
16+
paymentDataSource.verifyPurchaseProduct(purchaseProduct).toDomain()
1717
}

core/billing/src/main/java/com/puzzle/billing/domain/BillingHelper.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import android.app.Activity
44
import com.puzzle.billing.model.PieceProduct
55
import com.puzzle.domain.model.payment.CashProduct
66
import com.puzzle.domain.model.payment.PurchaseProduct
7+
import com.puzzle.domain.model.payment.VerifyPurchaseProduct
78
import kotlinx.collections.immutable.ImmutableList
89
import kotlinx.coroutines.flow.StateFlow
910

@@ -12,5 +13,6 @@ interface BillingHelper {
1213
suspend fun getAvailableProducts(): CashProduct
1314
suspend fun processAvailableProducts(cashProducts: CashProduct): ImmutableList<PieceProduct>
1415
fun purchaseProduct(activity: Activity, purchaseProduct: PieceProduct)
15-
suspend fun verifyPurchaseProduct(purchaseProduct: PurchaseProduct)
16+
suspend fun verifyPurchaseProduct(purchaseProduct: PurchaseProduct): VerifyPurchaseProduct
17+
fun release()
1618
}

core/billing/src/main/java/com/puzzle/billing/domain/PaymentRepository.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ package com.puzzle.billing.domain
22

33
import com.puzzle.domain.model.payment.CashProduct
44
import com.puzzle.domain.model.payment.PurchaseProduct
5+
import com.puzzle.domain.model.payment.VerifyPurchaseProduct
56

67
interface PaymentRepository {
78
suspend fun getAvailableProduct(): CashProduct
8-
suspend fun verifyPurchaseProduct(purchaseProduct: PurchaseProduct)
9+
suspend fun verifyPurchaseProduct(purchaseProduct: PurchaseProduct): VerifyPurchaseProduct
910
}

core/data/src/main/java/com/puzzle/data/repository/UserRepositoryImpl.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import com.puzzle.datastore.datasource.token.LocalTokenDataSource
44
import com.puzzle.datastore.datasource.user.LocalUserDataSource
55
import com.puzzle.domain.model.user.RejectReason
66
import com.puzzle.domain.model.user.UserInfo
7+
import com.puzzle.domain.model.user.UserPuzzle
78
import com.puzzle.domain.model.user.UserRole
89
import com.puzzle.domain.model.user.UserSetting
910
import com.puzzle.domain.repository.UserRepository
@@ -55,6 +56,9 @@ class UserRepositoryImpl @Inject constructor(
5556
return response.toDomain()
5657
}
5758

59+
override suspend fun getUserPuzzle(): UserPuzzle =
60+
userDataSource.getUserPuzzle().toDomain()
61+
5862
override suspend fun updatePushNotification(toggle: Boolean) =
5963
userDataSource.updatePushNotification(toggle)
6064

core/data/src/test/java/com/puzzle/data/source/user/FakeUserDataSource.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import com.puzzle.network.model.user.GetBlockSyncTimeResponse
44
import com.puzzle.network.model.user.GetRejectReasonResponse
55
import com.puzzle.network.model.user.GetSettingInfoResponse
66
import com.puzzle.network.model.user.GetUserInfoResponse
7+
import com.puzzle.network.model.user.GetUserPuzzleResponse
78
import com.puzzle.network.source.user.UserDataSource
89

910
class FakeUserDataSource : UserDataSource {
@@ -14,6 +15,8 @@ class FakeUserDataSource : UserDataSource {
1415
}
1516

1617
override suspend fun getUserInfo(): GetUserInfoResponse = userInfoResponse
18+
override suspend fun getUserPuzzle(): GetUserPuzzleResponse = throw NotImplementedError()
19+
1720
override suspend fun getBlockSyncTime(): GetBlockSyncTimeResponse = throw NotImplementedError()
1821
override suspend fun getSettingsInfo(): GetSettingInfoResponse = throw NotImplementedError()
1922
override suspend fun getRejectReason(): GetRejectReasonResponse = throw NotImplementedError()

core/designsystem/src/main/res/values/strings.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,4 +278,14 @@
278278
<string name="alarm_matching_accepted_content">당신을 기다리는 조각이 있어요🧩\n마음이 닿으면 응답해보세요💕</string>
279279
<string name="alarm_matching_success_title">퍼즐이 완성되었어요🎉</string>
280280
<string name="alarm_matching_success_content">OOO님과 연락처가 공개되었어요.\n대화를 시작해보세요!</string>
281+
282+
<!--Store-->
283+
<string name="store_purchase_success_dialog_title">퍼즐 %1$s개를 구매했어요.</string>
284+
<string name="store_purchase_success_dialog_subtext">지금 바로 새로운 인연을 만나보세요!</string>
285+
<string name="store_purchase_success_dialog_btn_label">홈으로</string>
286+
<string name="store_description_1">구매한 퍼즐은 새로운 매칭 조각 열기, 연락처 확인하기, 사진 보기, 매칭 수락하기 등에 사용할 수 있습니다.</string>
287+
<string name="store_description_2">사용하지 않은 퍼즐에 한해, 구매일로부터 7일 이내 청약 철회가 가능합니다.</string>
288+
<string name="store_description_3">결제에 문제가 있으신 경우, </string>
289+
<string name="store_description_4">고객센터</string>
290+
<string name="store_description_5">로 문의 주세요.</string>
281291
</resources>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.puzzle.domain.model.payment
2+
3+
data class VerifyPurchaseProduct (
4+
val rewardPuzzleCount: Int
5+
)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.puzzle.domain.model.user
2+
3+
data class UserPuzzle (
4+
val count: Int
5+
)

core/domain/src/main/java/com/puzzle/domain/repository/UserRepository.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.puzzle.domain.repository
22

33
import com.puzzle.domain.model.user.RejectReason
44
import com.puzzle.domain.model.user.UserInfo
5+
import com.puzzle.domain.model.user.UserPuzzle
56
import com.puzzle.domain.model.user.UserRole
67
import com.puzzle.domain.model.user.UserSetting
78
import kotlinx.coroutines.flow.Flow
@@ -13,6 +14,7 @@ interface UserRepository {
1314
suspend fun getUserSettingInfo(): UserSetting
1415
suspend fun getBlockSyncTime(): LocalDateTime
1516
suspend fun getUserInfo(): UserInfo
17+
suspend fun getUserPuzzle(): UserPuzzle
1618
suspend fun updatePushNotification(toggle: Boolean)
1719
suspend fun updateBlockAcquaintances(toggle: Boolean)
1820
}

0 commit comments

Comments
 (0)