parent
79cb4b995a
commit
6e3a4e1125
|
@ -40,8 +40,8 @@ android {
|
|||
applicationId "kr.co.vividnext.sodalive"
|
||||
minSdk 23
|
||||
targetSdk 33
|
||||
versionCode 27
|
||||
versionName "1.8.2"
|
||||
versionCode 28
|
||||
versionName "1.8.3"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
|
@ -149,4 +149,7 @@ dependencies {
|
|||
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
|
||||
|
||||
implementation "com.michalsvec:single-row-calednar:1.0.0"
|
||||
|
||||
// google in-app-purchase
|
||||
implementation "com.android.billingclient:billing-ktx:6.2.0"
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-permission android:name="com.android.vending.BILLING" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
|
|
@ -74,6 +74,7 @@ import kr.co.vividnext.sodalive.mypage.auth.AuthApi
|
|||
import kr.co.vividnext.sodalive.mypage.auth.AuthRepository
|
||||
import kr.co.vividnext.sodalive.mypage.can.CanApi
|
||||
import kr.co.vividnext.sodalive.mypage.can.CanRepository
|
||||
import kr.co.vividnext.sodalive.mypage.can.charge.iap.CanChargeIapViewModel
|
||||
import kr.co.vividnext.sodalive.mypage.can.charge.pg.CanChargePgViewModel
|
||||
import kr.co.vividnext.sodalive.mypage.can.coupon.CanCouponViewModel
|
||||
import kr.co.vividnext.sodalive.mypage.can.payment.CanPaymentViewModel
|
||||
|
@ -231,6 +232,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
|||
viewModel { CreatorCommunityWriteViewModel(get()) }
|
||||
viewModel { CreatorCommunityModifyViewModel(get()) }
|
||||
viewModel { CanCouponViewModel(get()) }
|
||||
viewModel { CanChargeIapViewModel(get()) }
|
||||
}
|
||||
|
||||
private val repositoryModule = module {
|
||||
|
|
|
@ -2,6 +2,8 @@ package kr.co.vividnext.sodalive.mypage.can
|
|||
|
||||
import io.reactivex.rxjava3.core.Single
|
||||
import kr.co.vividnext.sodalive.common.ApiResponse
|
||||
import kr.co.vividnext.sodalive.mypage.can.charge.iap.GoogleChargeRequest
|
||||
import kr.co.vividnext.sodalive.mypage.can.charge.iap.GoogleVerifyRequest
|
||||
import kr.co.vividnext.sodalive.mypage.can.charge.pg.CanResponse
|
||||
import kr.co.vividnext.sodalive.mypage.can.charge.pg.ChargeRequest
|
||||
import kr.co.vividnext.sodalive.mypage.can.charge.pg.ChargeResponse
|
||||
|
@ -17,6 +19,18 @@ import retrofit2.http.POST
|
|||
import retrofit2.http.Query
|
||||
|
||||
interface CanApi {
|
||||
@POST("/charge/google")
|
||||
fun googleChargeCan(
|
||||
@Body request: GoogleChargeRequest,
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<ChargeResponse>>
|
||||
|
||||
@POST("/charge/google/verify")
|
||||
fun googleChargeVerify(
|
||||
@Body request: GoogleVerifyRequest,
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<Any>>
|
||||
|
||||
@POST("/charge")
|
||||
fun chargeCan(
|
||||
@Body chargeRequest: ChargeRequest,
|
||||
|
|
|
@ -1,11 +1,23 @@
|
|||
package kr.co.vividnext.sodalive.mypage.can
|
||||
|
||||
import kr.co.vividnext.sodalive.mypage.can.charge.iap.GoogleChargeRequest
|
||||
import kr.co.vividnext.sodalive.mypage.can.charge.iap.GoogleVerifyRequest
|
||||
import kr.co.vividnext.sodalive.mypage.can.charge.pg.ChargeRequest
|
||||
import kr.co.vividnext.sodalive.mypage.can.charge.pg.VerifyRequest
|
||||
import kr.co.vividnext.sodalive.mypage.can.coupon.UseCanCouponRequest
|
||||
import java.util.TimeZone
|
||||
|
||||
class CanRepository(private val api: CanApi) {
|
||||
fun googleChargeCan(
|
||||
request: GoogleChargeRequest,
|
||||
token: String
|
||||
) = api.googleChargeCan(request, authHeader = token)
|
||||
|
||||
fun googleChargeVerify(
|
||||
request: GoogleVerifyRequest,
|
||||
token: String
|
||||
) = api.googleChargeVerify(request, authHeader = token)
|
||||
|
||||
fun chargeCan(
|
||||
chargeRequest: ChargeRequest,
|
||||
token: String
|
||||
|
|
|
@ -12,9 +12,11 @@ import kr.co.vividnext.sodalive.base.BaseActivity
|
|||
import kr.co.vividnext.sodalive.common.Constants
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.databinding.ActivityCanChargeBinding
|
||||
import kr.co.vividnext.sodalive.mypage.can.charge.iap.CanChargeIapFragment
|
||||
import kr.co.vividnext.sodalive.mypage.can.charge.pg.CanChargePgFragment
|
||||
import kr.co.vividnext.sodalive.mypage.can.charge.pg.CanResponse
|
||||
import kr.co.vividnext.sodalive.mypage.can.payment.CanPaymentActivity
|
||||
import kr.co.vividnext.sodalive.mypage.can.status.CanStatusActivity
|
||||
|
||||
class CanChargeActivity : BaseActivity<ActivityCanChargeBinding>(
|
||||
ActivityCanChargeBinding::inflate
|
||||
|
@ -39,7 +41,7 @@ class CanChargeActivity : BaseActivity<ActivityCanChargeBinding>(
|
|||
false
|
||||
)
|
||||
|
||||
changeFragment(PG_TAG_KEY)
|
||||
changeFragment(IAP_TAG_KEY)
|
||||
}
|
||||
|
||||
override fun setupView() {
|
||||
|
@ -56,7 +58,7 @@ class CanChargeActivity : BaseActivity<ActivityCanChargeBinding>(
|
|||
if (SharedPreferenceManager.isAuth) {
|
||||
val tabs = binding.tabs
|
||||
|
||||
tabs.visibility = View.GONE
|
||||
tabs.visibility = View.VISIBLE
|
||||
tabs.addTab(tabs.newTab().setText("인 앱 결제").setTag(IAP_TAG_KEY))
|
||||
tabs.addTab(tabs.newTab().setText("PG").setTag(PG_TAG_KEY))
|
||||
|
||||
|
@ -91,7 +93,7 @@ class CanChargeActivity : BaseActivity<ActivityCanChargeBinding>(
|
|||
fragment = if (tag == PG_TAG_KEY) {
|
||||
CanChargePgFragment()
|
||||
} else {
|
||||
CanChargePgFragment()
|
||||
CanChargeIapFragment()
|
||||
}
|
||||
|
||||
fragmentTransaction.add(R.id.fl_container, fragment, tag)
|
||||
|
@ -111,6 +113,16 @@ class CanChargeActivity : BaseActivity<ActivityCanChargeBinding>(
|
|||
activityResultLauncher.launch(intent)
|
||||
}
|
||||
|
||||
fun successIapCharge() {
|
||||
if (gotoPrevPage) {
|
||||
setResult(RESULT_OK)
|
||||
finish()
|
||||
} else {
|
||||
val intent = Intent(applicationContext, CanStatusActivity::class.java)
|
||||
startActivity(intent)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val IAP_TAG_KEY = "iap"
|
||||
const val PG_TAG_KEY = "pg"
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
package kr.co.vividnext.sodalive.mypage.can.charge.iap
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.android.billingclient.api.ProductDetails
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.databinding.ItemCanChargeBinding
|
||||
import kr.co.vividnext.sodalive.extensions.fontSpan
|
||||
|
||||
class CanChargeIapAdapter(
|
||||
private val onClick: (ProductDetails) -> Unit
|
||||
) : RecyclerView.Adapter<CanChargeIapAdapter.ViewHolder>() {
|
||||
|
||||
val items = mutableListOf<ProductDetails>()
|
||||
|
||||
inner class ViewHolder(
|
||||
private val context: Context,
|
||||
private val binding: ItemCanChargeBinding
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
fun bind(item: ProductDetails) {
|
||||
binding.tvPrice.text = item.oneTimePurchaseOfferDetails?.formattedPrice
|
||||
|
||||
val typeface = ResourcesCompat.getFont(context, R.font.gmarket_sans_medium)
|
||||
binding.tvTitle.text = item.name.fontSpan(
|
||||
typeface,
|
||||
"캔"
|
||||
)
|
||||
|
||||
binding.root.setOnClickListener { onClick(item) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
|
||||
parent.context,
|
||||
ItemCanChargeBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
)
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
holder.bind(items[position])
|
||||
}
|
||||
|
||||
override fun getItemCount() = items.count()
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
fun addItems(items: List<ProductDetails>) {
|
||||
this.items.addAll(items.sortedBy { it.description.toInt() })
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,221 @@
|
|||
package kr.co.vividnext.sodalive.mypage.can.charge.iap
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.graphics.Rect
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.android.billingclient.api.BillingClient
|
||||
import com.android.billingclient.api.BillingClientStateListener
|
||||
import com.android.billingclient.api.BillingFlowParams
|
||||
import com.android.billingclient.api.BillingResult
|
||||
import com.android.billingclient.api.ProductDetails
|
||||
import com.android.billingclient.api.PurchasesUpdatedListener
|
||||
import com.android.billingclient.api.QueryProductDetailsParams
|
||||
import kr.co.vividnext.sodalive.base.BaseFragment
|
||||
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.databinding.FragmentCanChargeIapBinding
|
||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||
import kr.co.vividnext.sodalive.mypage.can.charge.CanChargeActivity
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
class CanChargeIapFragment : BaseFragment<FragmentCanChargeIapBinding>(
|
||||
FragmentCanChargeIapBinding::inflate
|
||||
) {
|
||||
private val viewModel: CanChargeIapViewModel by inject()
|
||||
|
||||
private lateinit var adapter: CanChargeIapAdapter
|
||||
private lateinit var loadingDialog: LoadingDialog
|
||||
private lateinit var billingClient: BillingClient
|
||||
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
|
||||
private var chargeId: Long = 0
|
||||
private var chargeCan: Int = 0
|
||||
|
||||
private val purchaseUpdateListener = PurchasesUpdatedListener { billingResult, purchases ->
|
||||
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && purchases != null) {
|
||||
for (purchase in purchases) {
|
||||
viewModel.verifyPayment(
|
||||
productId = purchase.products[0],
|
||||
purchaseToken = purchase.purchaseToken,
|
||||
chargeId = chargeId
|
||||
) {
|
||||
SharedPreferenceManager.can += chargeCan
|
||||
(requireActivity() as CanChargeActivity).successIapCharge()
|
||||
}
|
||||
}
|
||||
} else if (billingResult.responseCode == BillingClient.BillingResponseCode.USER_CANCELED) {
|
||||
chargeId = 0
|
||||
chargeCan = 0
|
||||
showToast("구매를 취소했습니다.")
|
||||
} else {
|
||||
chargeId = 0
|
||||
chargeCan = 0
|
||||
showToast("구매를 하지 못했습니다.\n다시 시도해 주세요.")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
loadingDialog = LoadingDialog(requireActivity(), layoutInflater)
|
||||
|
||||
bindData()
|
||||
setupRecyclerView()
|
||||
setupBillingClient()
|
||||
}
|
||||
|
||||
private fun bindData() {
|
||||
viewModel.isLoading.observe(viewLifecycleOwner) {
|
||||
if (it) {
|
||||
loadingDialog.show(screenWidth)
|
||||
} else {
|
||||
loadingDialog.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
val recyclerView = binding.rvChargeCan
|
||||
adapter = CanChargeIapAdapter { productDetails ->
|
||||
chargeCan = productDetails.description.toInt()
|
||||
viewModel.chargeCan(
|
||||
title = productDetails.name,
|
||||
chargeCan = chargeCan,
|
||||
price = (
|
||||
productDetails.oneTimePurchaseOfferDetails?.priceAmountMicros ?: 0L
|
||||
).toDouble() / 1000000,
|
||||
currencyCode = productDetails.oneTimePurchaseOfferDetails?.priceCurrencyCode
|
||||
?: "KRW"
|
||||
) { chargeId ->
|
||||
this.chargeId = chargeId
|
||||
launchPurchaseFlow(productDetails)
|
||||
}
|
||||
}
|
||||
|
||||
recyclerView.layoutManager = LinearLayoutManager(
|
||||
requireContext(),
|
||||
LinearLayoutManager.VERTICAL,
|
||||
false
|
||||
)
|
||||
|
||||
recyclerView.addItemDecoration(object : RecyclerView.ItemDecoration() {
|
||||
override fun getItemOffsets(
|
||||
outRect: Rect,
|
||||
view: View,
|
||||
parent: RecyclerView,
|
||||
state: RecyclerView.State
|
||||
) {
|
||||
super.getItemOffsets(outRect, view, parent, state)
|
||||
|
||||
outRect.left = 13.3f.dpToPx().toInt()
|
||||
outRect.right = 13.3f.dpToPx().toInt()
|
||||
|
||||
when (parent.getChildAdapterPosition(view)) {
|
||||
0 -> {
|
||||
outRect.top = 13.3f.dpToPx().toInt()
|
||||
outRect.bottom = 6.7f.dpToPx().toInt()
|
||||
}
|
||||
|
||||
adapter.itemCount - 1 -> {
|
||||
outRect.top = 6.7f.dpToPx().toInt()
|
||||
outRect.bottom = 26.7f.dpToPx().toInt()
|
||||
}
|
||||
|
||||
else -> {
|
||||
outRect.top = 6.7f.dpToPx().toInt()
|
||||
outRect.bottom = 6.7f.dpToPx().toInt()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
recyclerView.adapter = adapter
|
||||
}
|
||||
|
||||
private fun setupBillingClient() {
|
||||
billingClient = BillingClient.newBuilder(requireContext())
|
||||
.enablePendingPurchases()
|
||||
.setListener(purchaseUpdateListener)
|
||||
.build()
|
||||
|
||||
loadingDialog.show(screenWidth)
|
||||
billingClient.startConnection(object : BillingClientStateListener {
|
||||
override fun onBillingServiceDisconnected() {
|
||||
loadingDialog.dismiss()
|
||||
}
|
||||
|
||||
override fun onBillingSetupFinished(billingResult: BillingResult) {
|
||||
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
|
||||
queryAvailableCans()
|
||||
} else {
|
||||
showToast("인 앱 결제 이용이 불가능 합니다. 다시 시도해 주세요.")
|
||||
loadingDialog.dismiss()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private fun queryAvailableCans() {
|
||||
val skuList = listOf(
|
||||
"${requireContext().packageName}.can_35",
|
||||
"${requireContext().packageName}.can_55",
|
||||
"${requireContext().packageName}.can_105",
|
||||
"${requireContext().packageName}.can_350",
|
||||
"${requireContext().packageName}.can_550",
|
||||
"${requireContext().packageName}.can_1170"
|
||||
)
|
||||
|
||||
val params = QueryProductDetailsParams.newBuilder()
|
||||
.setProductList(
|
||||
skuList.map {
|
||||
QueryProductDetailsParams.Product.newBuilder()
|
||||
.setProductId(it)
|
||||
.setProductType(BillingClient.ProductType.INAPP) // Use SUBS for subscriptions
|
||||
.build()
|
||||
}
|
||||
)
|
||||
.build()
|
||||
|
||||
billingClient.queryProductDetailsAsync(params) { billingResult, productDetailsList ->
|
||||
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
|
||||
handler.post {
|
||||
adapter.addItems(productDetailsList)
|
||||
productDetailsList.forEach {
|
||||
Toast.makeText(
|
||||
requireContext(),
|
||||
"${it.name}, ${it.description}, ${it.productId}, ${it.productType}, ${
|
||||
it.oneTimePurchaseOfferDetails?.priceAmountMicros
|
||||
}, ${it.oneTimePurchaseOfferDetails?.priceCurrencyCode}",
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
handler.post { showToast("인 앱 결제 이용이 불가능 합니다. 다시 시도해 주세요.") }
|
||||
}
|
||||
|
||||
handler.post { loadingDialog.dismiss() }
|
||||
}
|
||||
}
|
||||
|
||||
private fun launchPurchaseFlow(productDetails: ProductDetails) {
|
||||
val billingFlowParams = BillingFlowParams.newBuilder()
|
||||
.setProductDetailsParamsList(
|
||||
listOf(
|
||||
BillingFlowParams.ProductDetailsParams.newBuilder()
|
||||
.setProductDetails(productDetails)
|
||||
.build()
|
||||
)
|
||||
).build()
|
||||
|
||||
billingClient.launchBillingFlow(requireActivity(), billingFlowParams)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
package kr.co.vividnext.sodalive.mypage.can.charge.iap
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.orhanobut.logger.Logger
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.mypage.can.CanRepository
|
||||
|
||||
class CanChargeIapViewModel(private val repository: CanRepository) : BaseViewModel() {
|
||||
private val _toastLiveData = MutableLiveData<String?>()
|
||||
val toastLiveData: LiveData<String?>
|
||||
get() = _toastLiveData
|
||||
|
||||
private var _isLoading = MutableLiveData(false)
|
||||
val isLoading: LiveData<Boolean>
|
||||
get() = _isLoading
|
||||
|
||||
fun chargeCan(
|
||||
title: String,
|
||||
chargeCan: Int,
|
||||
price: Double,
|
||||
currencyCode: String,
|
||||
onSuccess: (Long) -> Unit
|
||||
) {
|
||||
_isLoading.value = true
|
||||
|
||||
compositeDisposable.add(
|
||||
repository.googleChargeCan(
|
||||
request = GoogleChargeRequest(
|
||||
title = title,
|
||||
chargeCan = chargeCan,
|
||||
price = price,
|
||||
currencyCode = currencyCode
|
||||
),
|
||||
token = "Bearer ${SharedPreferenceManager.token}"
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{
|
||||
_isLoading.value = false
|
||||
if (it.success && it.data != null) {
|
||||
onSuccess(it.data.chargeId)
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.value = it.message
|
||||
} else {
|
||||
_toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun verifyPayment(
|
||||
productId: String,
|
||||
purchaseToken: String,
|
||||
chargeId: Long,
|
||||
onSuccess: () -> Unit
|
||||
) {
|
||||
_isLoading.value = true
|
||||
|
||||
compositeDisposable.add(
|
||||
repository.googleChargeVerify(
|
||||
request = GoogleVerifyRequest(
|
||||
productId = productId,
|
||||
purchaseToken = purchaseToken,
|
||||
chargeId = chargeId
|
||||
),
|
||||
token = "Bearer ${SharedPreferenceManager.token}"
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{
|
||||
_isLoading.value = false
|
||||
if (it.success) {
|
||||
onSuccess()
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.value = it.message
|
||||
} else {
|
||||
_toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package kr.co.vividnext.sodalive.mypage.can.charge.iap
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kr.co.vividnext.sodalive.mypage.can.payment.PaymentGateway
|
||||
|
||||
data class GoogleChargeRequest(
|
||||
@SerializedName("title") val title: String,
|
||||
@SerializedName("chargeCan") val chargeCan: Int,
|
||||
@SerializedName("price") val price: Double,
|
||||
@SerializedName("currencyCode") val currencyCode: String,
|
||||
@SerializedName("paymentGateway") val paymentGateway: PaymentGateway = PaymentGateway.GOOGLE_IAP
|
||||
)
|
||||
|
||||
data class GoogleVerifyRequest(
|
||||
@SerializedName("productId") val productId: String,
|
||||
@SerializedName("purchaseToken") val purchaseToken: String,
|
||||
@SerializedName("chargeId") val chargeId: Long
|
||||
)
|
|
@ -81,16 +81,16 @@ class CanChargePgFragment : BaseFragment<FragmentCanChargePgBinding>(
|
|||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private fun bindData() {
|
||||
viewModel.canChargeLiveData.observe(this) {
|
||||
viewModel.canChargeLiveData.observe(viewLifecycleOwner) {
|
||||
adapter.items.addAll(it)
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
viewModel.toastLiveData.observe(this) {
|
||||
viewModel.toastLiveData.observe(viewLifecycleOwner) {
|
||||
it?.let { Toast.makeText(requireActivity(), it, Toast.LENGTH_LONG).show() }
|
||||
}
|
||||
|
||||
viewModel.isLoading.observe(this) {
|
||||
viewModel.isLoading.observe(viewLifecycleOwner) {
|
||||
if (it) {
|
||||
loadingDialog.show(screenWidth)
|
||||
} else {
|
||||
|
|
|
@ -140,8 +140,8 @@ class CanPaymentActivity : BaseActivity<ActivityCanPaymentBinding>(
|
|||
R.font.gmarket_sans_bold
|
||||
)
|
||||
|
||||
view.setTextColor(ContextCompat.getColor(applicationContext, R.color.color_9970ff))
|
||||
view.setBackgroundResource(R.drawable.bg_round_corner_10_4d9970ff_9970ff)
|
||||
view.setTextColor(ContextCompat.getColor(applicationContext, R.color.color_3bb9f1))
|
||||
view.setBackgroundResource(R.drawable.bg_round_corner_10_13181b_3bb9f1)
|
||||
}
|
||||
|
||||
private fun requestCharge() {
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/color_4d9970ff" />
|
||||
<corners android:radius="10dp" />
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="@color/color_9970ff" />
|
||||
</shape>
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/color_4d9970ff" />
|
||||
<corners android:radius="6.7dp" />
|
||||
<stroke
|
||||
android:width="1.3dp"
|
||||
android:color="@color/color_9970ff" />
|
||||
</shape>
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_charge_can"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -21,15 +21,6 @@
|
|||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="5000 캔 + 1000 캔" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_price"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_price"
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -37,15 +28,8 @@
|
|||
android:fontFamily="@font/gmarket_sans_bold"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textSize="15.3sp"
|
||||
tools:text="3,300" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:text=" 원"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textSize="15.3sp" />
|
||||
|
||||
</LinearLayout>
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="₩3,300" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
Loading…
Reference in New Issue