diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 8bbc36b..8c90386 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -34,6 +34,8 @@
+
+
(FragmentMyBinding::inflat
binding.ivEdit.setOnClickListener {}
- binding.llTotalCoin.setOnClickListener {
+ binding.llTotalCan.setOnClickListener {
startActivity(
Intent(
requireActivity(),
@@ -56,7 +57,14 @@ class MyPageFragment : BaseFragment(FragmentMyBinding::inflat
)
}
- binding.tvChargeCoin.setOnClickListener {}
+ binding.tvChargeCan.setOnClickListener {
+ startActivity(
+ Intent(
+ requireActivity(),
+ CanChargeActivity::class.java
+ )
+ )
+ }
binding.llReservationSuda.setOnClickListener {}
@@ -144,8 +152,8 @@ class MyPageFragment : BaseFragment(FragmentMyBinding::inflat
}
}
- binding.tvTotalCoin.text = (it.chargeCoin + it.rewardCoin).moneyFormat()
- binding.tvReservationSuda.text = "${it.sudaReservationCount}"
+ binding.tvTotalCan.text = (it.chargeCan + it.rewardCan).moneyFormat()
+ binding.tvReservationSuda.text = "${it.liveReservationCount}"
}
}
}
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/mypage/MyPageResponse.kt b/app/src/main/java/kr/co/vividnext/sodalive/mypage/MyPageResponse.kt
index a502b7f..04e8f01 100644
--- a/app/src/main/java/kr/co/vividnext/sodalive/mypage/MyPageResponse.kt
+++ b/app/src/main/java/kr/co/vividnext/sodalive/mypage/MyPageResponse.kt
@@ -5,15 +5,13 @@ import com.google.gson.annotations.SerializedName
data class MyPageResponse(
@SerializedName("nickname") val nickname: String,
@SerializedName("profileUrl") val profileUrl: String,
- @SerializedName("chargeCoin") val chargeCoin: Int,
- @SerializedName("rewardCoin") val rewardCoin: Int,
+ @SerializedName("chargeCan") val chargeCan: Int,
+ @SerializedName("rewardCan") val rewardCan: Int,
@SerializedName("youtubeUrl") val youtubeUrl: String?,
@SerializedName("instagramUrl") val instagramUrl: String?,
@SerializedName("websiteUrl") val websiteUrl: String?,
@SerializedName("blogUrl") val blogUrl: String?,
- @SerializedName("sudaReservationCount") val sudaReservationCount: Int,
- @SerializedName("counselingReservationCount") val counselingReservationCount: Int,
+ @SerializedName("liveReservationCount") val liveReservationCount: Int,
@SerializedName("likeCount") val likeCount: Int,
- @SerializedName("reviewCount") val reviewCount: Int,
@SerializedName("isAuth") val isAuth: Boolean,
)
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/CanApi.kt b/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/CanApi.kt
index 83f1d4b..a3ce8c7 100644
--- a/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/CanApi.kt
+++ b/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/CanApi.kt
@@ -2,14 +2,37 @@ 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.CanResponse
+import kr.co.vividnext.sodalive.mypage.can.charge.ChargeRequest
+import kr.co.vividnext.sodalive.mypage.can.charge.ChargeResponse
+import kr.co.vividnext.sodalive.mypage.can.charge.VerifyRequest
import kr.co.vividnext.sodalive.mypage.can.status.GetCanStatusResponse
import kr.co.vividnext.sodalive.mypage.can.status.charge.GetCanChargeStatusResponseItem
import kr.co.vividnext.sodalive.mypage.can.status.use.GetCanUseStatusResponseItem
+import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.Header
+import retrofit2.http.POST
import retrofit2.http.Query
interface CanApi {
+ @POST("/charge")
+ fun chargeCan(
+ @Body chargeRequest: ChargeRequest,
+ @Header("Authorization") authHeader: String
+ ): Single>
+
+ @POST("/charge/verify")
+ fun verifyCharge(
+ @Body request: VerifyRequest,
+ @Header("Authorization") authHeader: String
+ ): Single>
+
+ @GET("/can")
+ fun getCans(
+ @Header("Authorization") authHeader: String
+ ): Single>>
+
@GET("/can/status")
fun getCanStatus(
@Query("container") container: String = "aos",
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/CanRepository.kt b/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/CanRepository.kt
index a8f939b..37ddf6d 100644
--- a/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/CanRepository.kt
+++ b/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/CanRepository.kt
@@ -1,8 +1,22 @@
package kr.co.vividnext.sodalive.mypage.can
+import kr.co.vividnext.sodalive.mypage.can.charge.ChargeRequest
+import kr.co.vividnext.sodalive.mypage.can.charge.VerifyRequest
import java.util.TimeZone
class CanRepository(private val api: CanApi) {
+ fun chargeCan(
+ chargeRequest: ChargeRequest,
+ token: String
+ ) = api.chargeCan(chargeRequest, authHeader = token)
+
+ fun verify(
+ request: VerifyRequest,
+ token: String
+ ) = api.verifyCharge(request, authHeader = token)
+
+ fun getCans(token: String) = api.getCans(authHeader = token)
+
fun getCanStatus(token: String) = api.getCanStatus(authHeader = token)
fun getCanUseStatus(
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/charge/CanChargeActivity.kt b/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/charge/CanChargeActivity.kt
new file mode 100644
index 0000000..4938104
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/charge/CanChargeActivity.kt
@@ -0,0 +1,126 @@
+package kr.co.vividnext.sodalive.mypage.can.charge
+
+import android.annotation.SuppressLint
+import android.app.Activity
+import android.content.Intent
+import android.graphics.Rect
+import android.os.Bundle
+import android.view.View
+import android.widget.Toast
+import androidx.activity.result.ActivityResultLauncher
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import kr.co.vividnext.sodalive.base.BaseActivity
+import kr.co.vividnext.sodalive.common.Constants
+import kr.co.vividnext.sodalive.common.LoadingDialog
+import kr.co.vividnext.sodalive.databinding.ActivityCanChargeBinding
+import kr.co.vividnext.sodalive.extensions.dpToPx
+import kr.co.vividnext.sodalive.mypage.can.payment.CanPaymentActivity
+import org.koin.android.ext.android.inject
+
+class CanChargeActivity : BaseActivity(
+ ActivityCanChargeBinding::inflate
+) {
+
+ private val viewModel: CanChargeViewModel by inject()
+ private var prevLiveRoom: Boolean = false
+
+ private lateinit var adapter: CanChargeAdapter
+ private lateinit var loadingDialog: LoadingDialog
+ private lateinit var activityResultLauncher: ActivityResultLauncher
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ activityResultLauncher = registerForActivityResult(
+ ActivityResultContracts.StartActivityForResult()
+ ) {
+ if (it.resultCode == Activity.RESULT_OK) {
+ finish()
+ }
+ }
+
+ super.onCreate(savedInstanceState)
+ bindData()
+
+ viewModel.getCanCharges()
+ }
+
+ override fun setupView() {
+ loadingDialog = LoadingDialog(this, layoutInflater)
+
+ binding.toolbar.tvBack.text = "충전하기"
+ binding.toolbar.tvBack.setOnClickListener { finish() }
+
+ prevLiveRoom = intent.getBooleanExtra(
+ Constants.EXTRA_PREV_LIVE_ROOM,
+ false
+ )
+
+ val recyclerView = binding.rvChargeCan
+ adapter = CanChargeAdapter {
+ val intent = Intent(applicationContext, CanPaymentActivity::class.java)
+ intent.putExtra(Constants.EXTRA_CAN, it)
+ intent.putExtra(Constants.EXTRA_PREV_LIVE_ROOM, prevLiveRoom)
+ activityResultLauncher.launch(intent)
+ }
+
+ recyclerView.layoutManager = LinearLayoutManager(
+ applicationContext,
+ 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
+ }
+
+ @SuppressLint("NotifyDataSetChanged")
+ private fun bindData() {
+ viewModel.canChargeLiveData.observe(this) {
+ adapter.items.addAll(it)
+ adapter.notifyDataSetChanged()
+ }
+
+ viewModel.toastLiveData.observe(this) {
+ it?.let { Toast.makeText(applicationContext, it, Toast.LENGTH_LONG).show() }
+ }
+
+ viewModel.isLoading.observe(this) {
+ if (it) {
+ loadingDialog.show(screenWidth)
+ } else {
+ loadingDialog.dismiss()
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/charge/CanChargeAdapter.kt b/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/charge/CanChargeAdapter.kt
new file mode 100644
index 0000000..55a58e3
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/charge/CanChargeAdapter.kt
@@ -0,0 +1,52 @@
+package kr.co.vividnext.sodalive.mypage.can.charge
+
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.core.content.res.ResourcesCompat
+import androidx.recyclerview.widget.RecyclerView
+import kr.co.vividnext.sodalive.R
+import kr.co.vividnext.sodalive.databinding.ItemCanChargeBinding
+import kr.co.vividnext.sodalive.extensions.fontSpan
+import kr.co.vividnext.sodalive.extensions.moneyFormat
+
+class CanChargeAdapter(
+ private val onClick: (CanResponse) -> Unit
+) : RecyclerView.Adapter() {
+
+ val items = mutableListOf()
+
+ inner class ViewHolder(
+ private val context: Context,
+ private val binding: ItemCanChargeBinding
+ ) : RecyclerView.ViewHolder(binding.root) {
+ fun bind(canCharge: CanResponse) {
+ binding.tvPrice.text = canCharge.price.moneyFormat()
+
+ val typeface = ResourcesCompat.getFont(context, R.font.gmarket_sans_medium)
+ binding.tvTitle.text = canCharge.title.fontSpan(
+ typeface,
+ "캔"
+ )
+
+ binding.root.setOnClickListener { onClick(canCharge) }
+ }
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+ return 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()
+}
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/charge/CanChargeViewModel.kt b/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/charge/CanChargeViewModel.kt
new file mode 100644
index 0000000..e177de5
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/charge/CanChargeViewModel.kt
@@ -0,0 +1,54 @@
+package kr.co.vividnext.sodalive.mypage.can.charge
+
+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 CanChargeViewModel(private val repository: CanRepository) : BaseViewModel() {
+ private val _canChargesLiveData = MutableLiveData>()
+ val canChargeLiveData: LiveData>
+ get() = _canChargesLiveData
+
+ private val _toastLiveData = MutableLiveData()
+ val toastLiveData: LiveData
+ get() = _toastLiveData
+
+ private var _isLoading = MutableLiveData(false)
+ val isLoading: LiveData
+ get() = _isLoading
+
+ fun getCanCharges() {
+ _isLoading.value = true
+ compositeDisposable.add(
+ repository.getCans("Bearer ${SharedPreferenceManager.token}")
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(
+ {
+ _isLoading.value = false
+ if (it.success && it.data != null) {
+ _canChargesLiveData.postValue(it.data!!)
+ } else {
+ if (it.message != null) {
+ _toastLiveData.postValue(it.message)
+ } else {
+ _toastLiveData.postValue(
+ "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
+ )
+ }
+ }
+ },
+ {
+ _isLoading.value = false
+ it.message?.let { message -> Logger.e(message) }
+ _toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
+ }
+ )
+ )
+ }
+}
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/charge/CanResponse.kt b/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/charge/CanResponse.kt
new file mode 100644
index 0000000..4251309
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/charge/CanResponse.kt
@@ -0,0 +1,19 @@
+package kr.co.vividnext.sodalive.mypage.can.charge
+
+import android.os.Parcelable
+import com.google.gson.annotations.SerializedName
+import kotlinx.parcelize.Parcelize
+
+@Parcelize
+data class CanResponse(
+ @SerializedName("id")
+ val id: Long,
+ @SerializedName("title")
+ val title: String,
+ @SerializedName("can")
+ val can: Int,
+ @SerializedName("rewardCan")
+ val rewardCan: Int,
+ @SerializedName("price")
+ val price: Int
+) : Parcelable
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/charge/ChargeData.kt b/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/charge/ChargeData.kt
new file mode 100644
index 0000000..ec53798
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/charge/ChargeData.kt
@@ -0,0 +1,23 @@
+package kr.co.vividnext.sodalive.mypage.can.charge
+
+import com.google.gson.annotations.SerializedName
+import kr.co.vividnext.sodalive.mypage.can.payment.PaymentGateway
+
+data class ChargeRequest(
+ @SerializedName("canId")
+ val canId: Long,
+ @SerializedName("paymentGateway")
+ val paymentGateway: PaymentGateway
+)
+
+data class ChargeResponse(
+ @SerializedName("chargeId")
+ val chargeId: Long
+)
+
+data class VerifyRequest(
+ @SerializedName("receipt_id")
+ val receiptId: String,
+ @SerializedName("order_id")
+ val orderId: String
+)
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/payment/CanPaymentActivity.kt b/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/payment/CanPaymentActivity.kt
new file mode 100644
index 0000000..c1473ed
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/payment/CanPaymentActivity.kt
@@ -0,0 +1,227 @@
+package kr.co.vividnext.sodalive.mypage.can.payment
+
+import android.annotation.SuppressLint
+import android.content.Intent
+import android.os.Handler
+import android.os.Looper
+import android.widget.TextView
+import android.widget.Toast
+import androidx.core.content.ContextCompat
+import androidx.core.content.IntentCompat
+import androidx.core.content.res.ResourcesCompat
+import com.google.gson.Gson
+import com.orhanobut.logger.Logger
+import kr.co.bootpay.android.Bootpay
+import kr.co.bootpay.android.events.BootpayEventListener
+import kr.co.bootpay.android.models.Payload
+import kr.co.vividnext.sodalive.BuildConfig
+import kr.co.vividnext.sodalive.R
+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.ActivityCanPaymentBinding
+import kr.co.vividnext.sodalive.extensions.fontSpan
+import kr.co.vividnext.sodalive.extensions.moneyFormat
+import kr.co.vividnext.sodalive.mypage.auth.BootpayResponse
+import kr.co.vividnext.sodalive.mypage.can.charge.CanResponse
+import kr.co.vividnext.sodalive.mypage.can.charge.VerifyRequest
+import kr.co.vividnext.sodalive.mypage.can.status.CanStatusActivity
+import org.koin.android.ext.android.inject
+
+class CanPaymentActivity : BaseActivity(
+ ActivityCanPaymentBinding::inflate
+) {
+ enum class PaymentMethod(val method: String) {
+ CARD("디지털카드"), BANK("디지털계좌이체")
+ }
+
+ private val viewModel: CanPaymentViewModel by inject()
+
+ private var canResponse: CanResponse? = null
+ private var prevLiveRoom: Boolean = false
+
+ private val handler = Handler(Looper.getMainLooper())
+
+ @SuppressLint("SetTextI18n")
+ override fun setupView() {
+ canResponse = IntentCompat.getParcelableExtra(
+ intent,
+ Constants.EXTRA_CAN,
+ CanResponse::class.java
+ )
+
+ if (canResponse == null) {
+ Toast.makeText(
+ applicationContext,
+ "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다.",
+ Toast.LENGTH_LONG
+ ).show()
+
+ finish()
+ }
+
+ prevLiveRoom = intent.getBooleanExtra(
+ Constants.EXTRA_PREV_LIVE_ROOM,
+ false
+ )
+
+ binding.toolbar.tvBack.text = "결제하기"
+ binding.toolbar.tvBack.setOnClickListener { finish() }
+
+ binding.tvChargeCanTitle.text = canResponse!!.title
+ binding.tvPrice.text = canResponse!!.price.moneyFormat()
+ binding.tvPaymentPrice.text = "${canResponse!!.price.moneyFormat()}원".fontSpan(
+ ResourcesCompat.getFont(applicationContext, R.font.gmarket_sans_light),
+ "원"
+ )
+
+ binding.tvAgree.setOnClickListener {
+ binding.tvAgree.isSelected = !binding.tvAgree.isSelected
+ }
+
+ binding.tvPayment.setOnClickListener {
+ if (viewModel.paymentMethodLiveData.value == null) {
+ Toast.makeText(
+ applicationContext,
+ "결제수단을 선택해 주세요.",
+ Toast.LENGTH_LONG
+ ).show()
+ return@setOnClickListener
+ }
+
+ if (!binding.tvAgree.isSelected) {
+ Toast.makeText(
+ applicationContext,
+ "결제 진행에 동의하셔야 결제가 가능합니다.",
+ Toast.LENGTH_LONG
+ ).show()
+ return@setOnClickListener
+ }
+
+ requestCharge()
+ }
+
+ binding.tvMethodCard.setOnClickListener { viewModel.setPaymentMethod(PaymentMethod.CARD) }
+ binding.tvMethodBank.setOnClickListener { viewModel.setPaymentMethod(PaymentMethod.BANK) }
+
+ viewModel.paymentMethodLiveData.observe(this) {
+ allPaymentMethodSelectFalse()
+
+ if (it != null) {
+ when (it) {
+ PaymentMethod.CARD -> paymentMethodSelect(binding.tvMethodCard)
+ PaymentMethod.BANK -> paymentMethodSelect(binding.tvMethodBank)
+ }
+ }
+ }
+ }
+
+ private fun allPaymentMethodSelectFalse() {
+ paymentMethodSelectFalse(binding.tvMethodBank)
+ paymentMethodSelectFalse(binding.tvMethodCard)
+ }
+
+ private fun paymentMethodSelectFalse(view: TextView) {
+ view.typeface = ResourcesCompat.getFont(
+ applicationContext,
+ R.font.gmarket_sans_medium
+ )
+
+ view.setTextColor(ContextCompat.getColor(applicationContext, R.color.color_eeeeee))
+ view.setBackgroundResource(R.drawable.bg_round_corner_10_232323_777777)
+ }
+
+ private fun paymentMethodSelect(view: TextView) {
+ view.typeface = ResourcesCompat.getFont(
+ applicationContext,
+ R.font.gmarket_sans_bold
+ )
+
+ view.setTextColor(ContextCompat.getColor(applicationContext, R.color.color_9970ff))
+ view.setBackgroundResource(R.drawable.bg_round_corner_10_4d9970ff_9970ff)
+ }
+
+ private fun requestCharge() {
+ viewModel.chargeCan(
+ canId = canResponse!!.id,
+ paymentGateway = PaymentGateway.PG,
+ onSuccess = {
+ requestPayment(chargeId = it)
+ },
+ onFailure = {
+ Toast.makeText(applicationContext, it, Toast.LENGTH_LONG).show()
+ }
+ )
+ }
+
+ private fun requestPayment(chargeId: Long) {
+ val payload = Payload()
+ .setApplicationId(BuildConfig.BOOTPAY_APP_ID)
+ .setOrderId("$chargeId")
+ .setOrderName(canResponse!!.title)
+ .setPrice(canResponse!!.price.toDouble())
+ .setTaxFree(0.toDouble())
+ .setPg("웰컴페이먼츠")
+ .setMethod(viewModel.paymentMethodLiveData.value!!.method)
+
+ Bootpay.init(this, this)
+ .setPayload(payload)
+ .setEventListener(object : BootpayEventListener {
+ override fun onCancel(data: String) {
+ Logger.e("onCancel: $data")
+ }
+
+ override fun onError(data: String) {
+ Logger.e("onError: $data")
+ Toast.makeText(applicationContext, data, Toast.LENGTH_LONG).show()
+ }
+
+ override fun onClose() {
+ Logger.e("onClose")
+ Bootpay.removePaymentWindow()
+ }
+
+ override fun onIssued(data: String) {
+ Logger.e("onIssued: $data")
+ }
+
+ override fun onConfirm(data: String): Boolean {
+ Logger.e("onConfirm: $data")
+ return true
+ }
+
+ override fun onDone(data: String) {
+ Logger.e("onDone: $data")
+ handler.post {
+ verifyPayment(data)
+ Bootpay.removePaymentWindow()
+ }
+ }
+ }).requestPayment()
+ }
+
+ private fun verifyPayment(data: String) {
+ val bootpayResponse = Gson().fromJson(data, BootpayResponse::class.java)
+ val request = VerifyRequest(bootpayResponse.data.receiptId, bootpayResponse.data.orderId)
+
+ viewModel.verify(
+ request,
+ onSuccess = {
+ Toast.makeText(applicationContext, "코인이 충전되었습니다", Toast.LENGTH_LONG).show()
+ if (prevLiveRoom) {
+ setResult(RESULT_OK)
+ } else {
+ val intent = Intent(applicationContext, CanStatusActivity::class.java)
+ startActivity(intent)
+ }
+
+ SharedPreferenceManager.can += (canResponse!!.rewardCan + canResponse!!.can)
+
+ finish()
+ },
+ onFailure = {
+ Toast.makeText(applicationContext, it, Toast.LENGTH_LONG).show()
+ }
+ )
+ }
+}
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/payment/CanPaymentViewModel.kt b/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/payment/CanPaymentViewModel.kt
new file mode 100644
index 0000000..ca825ce
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/payment/CanPaymentViewModel.kt
@@ -0,0 +1,93 @@
+package kr.co.vividnext.sodalive.mypage.can.payment
+
+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
+import kr.co.vividnext.sodalive.mypage.can.charge.ChargeRequest
+import kr.co.vividnext.sodalive.mypage.can.charge.VerifyRequest
+
+class CanPaymentViewModel(private val repository: CanRepository) : BaseViewModel() {
+
+ private val _paymentMethodLiveData = MutableLiveData()
+ val paymentMethodLiveData: LiveData
+ get() = _paymentMethodLiveData
+
+ private var _isLoading = MutableLiveData(false)
+ val isLoading: LiveData
+ get() = _isLoading
+
+ fun chargeCan(
+ canId: Long,
+ paymentGateway: PaymentGateway,
+ onSuccess: (Long) -> Unit,
+ onFailure: (String) -> Unit
+ ) {
+ _isLoading.value = true
+ val request = ChargeRequest(canId = canId, paymentGateway = paymentGateway)
+ compositeDisposable.add(
+ repository.chargeCan(
+ chargeRequest = request,
+ "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) {
+ onFailure(it.message)
+ } else {
+ onFailure("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
+ }
+ }
+ },
+ {
+ _isLoading.value = false
+ it.message?.let { message -> Logger.e(message) }
+ onFailure("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
+ }
+ )
+ )
+ }
+
+ fun verify(request: VerifyRequest, onSuccess: () -> Unit, onFailure: (String) -> Unit) {
+ _isLoading.value = true
+ compositeDisposable.add(
+ repository.verify(
+ request = request,
+ "Bearer ${SharedPreferenceManager.token}"
+ ).subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(
+ {
+ _isLoading.value = false
+ if (it.success) {
+ onSuccess()
+ } else {
+ if (it.message != null) {
+ onFailure(it.message)
+ } else {
+ onFailure("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
+ }
+ }
+ },
+ {
+ _isLoading.value = false
+ it.message?.let { message -> Logger.e(message) }
+ onFailure("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
+ }
+ )
+ )
+ }
+
+ fun setPaymentMethod(paymentMethod: CanPaymentActivity.PaymentMethod) {
+ _paymentMethodLiveData.value = paymentMethod
+ }
+}
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/payment/PaymentGateway.kt b/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/payment/PaymentGateway.kt
new file mode 100644
index 0000000..cd164f5
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/payment/PaymentGateway.kt
@@ -0,0 +1,8 @@
+package kr.co.vividnext.sodalive.mypage.can.payment
+
+import com.google.gson.annotations.SerializedName
+
+enum class PaymentGateway {
+ @SerializedName("PG") PG,
+ @SerializedName("GOOGLE_IAP") GOOGLE_IAP
+}
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/status/CanStatusActivity.kt b/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/status/CanStatusActivity.kt
index 2a82c9f..518e317 100644
--- a/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/status/CanStatusActivity.kt
+++ b/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/status/CanStatusActivity.kt
@@ -12,6 +12,7 @@ import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.databinding.ActivityCanStatusBinding
import kr.co.vividnext.sodalive.extensions.moneyFormat
import kr.co.vividnext.sodalive.main.MainActivity
+import kr.co.vividnext.sodalive.mypage.can.charge.CanChargeActivity
import kr.co.vividnext.sodalive.mypage.can.status.charge.CanChargeStatusFragment
import kr.co.vividnext.sodalive.mypage.can.status.use.CanUseStatusFragment
import org.koin.android.ext.android.inject
@@ -40,7 +41,14 @@ class CanStatusActivity : BaseActivity(
override fun setupView() {
binding.toolbar.tvBack.text = "코인내역"
binding.toolbar.tvBack.setOnClickListener { onClickBackButton() }
- binding.llChargeCoin.setOnClickListener {}
+ binding.llChargeCan.setOnClickListener {
+ startActivity(
+ Intent(
+ applicationContext,
+ CanChargeActivity::class.java
+ )
+ )
+ }
loadingDialog = LoadingDialog(this, layoutInflater)
@@ -93,16 +101,16 @@ class CanStatusActivity : BaseActivity(
@SuppressLint("SetTextI18n")
private fun bindData() {
- viewModel.totalCoinLiveData.observe(this) {
- binding.tvTotalCoin.text = it.moneyFormat()
+ viewModel.totalCanLiveData.observe(this) {
+ binding.tvTotalCan.text = it.moneyFormat()
}
- viewModel.paidCoinLiveData.observe(this) {
- binding.tvPaidCoin.text = it.moneyFormat()
+ viewModel.paidCanLiveData.observe(this) {
+ binding.tvPaidCan.text = it.moneyFormat()
}
- viewModel.rewardCoinLiveData.observe(this) {
- binding.tvRewardCoin.text = it.moneyFormat()
+ viewModel.rewardCanLiveData.observe(this) {
+ binding.tvRewardCan.text = it.moneyFormat()
}
viewModel.toastLiveData.observe(this) {
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/status/CanStatusViewModel.kt b/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/status/CanStatusViewModel.kt
index 557d19f..336c731 100644
--- a/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/status/CanStatusViewModel.kt
+++ b/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/status/CanStatusViewModel.kt
@@ -12,25 +12,25 @@ import kr.co.vividnext.sodalive.mypage.can.status.charge.GetCanChargeStatusRespo
import kr.co.vividnext.sodalive.mypage.can.status.use.GetCanUseStatusResponseItem
class CanStatusViewModel(private val repository: CanRepository) : BaseViewModel() {
- private val _totalCoinLiveData = MutableLiveData()
- val totalCoinLiveData: LiveData
- get() = _totalCoinLiveData
+ private val _totalCanLiveData = MutableLiveData()
+ val totalCanLiveData: LiveData
+ get() = _totalCanLiveData
- private val _paidCoinLiveData = MutableLiveData()
- val paidCoinLiveData: LiveData
- get() = _paidCoinLiveData
+ private val _paidCanLiveData = MutableLiveData()
+ val paidCanLiveData: LiveData
+ get() = _paidCanLiveData
- private val _rewardCoinLiveData = MutableLiveData()
- val rewardCoinLiveData: LiveData
- get() = _rewardCoinLiveData
+ private val _rewardCanLiveData = MutableLiveData()
+ val rewardCanLiveData: LiveData
+ get() = _rewardCanLiveData
- private val _coinUseStatusLiveData = MutableLiveData>()
- val coinUseStatusLiveData: LiveData>
- get() = _coinUseStatusLiveData
+ private val _canUseStatusLiveData = MutableLiveData>()
+ val canUseStatusLiveData: LiveData>
+ get() = _canUseStatusLiveData
- private val _coinChargeStatusLiveData = MutableLiveData>()
- val coinChargeStatusLiveData: LiveData>
- get() = _coinChargeStatusLiveData
+ private val _canChargeStatusLiveData = MutableLiveData>()
+ val canChargeStatusLiveData: LiveData>
+ get() = _canChargeStatusLiveData
private val _toastLiveData = MutableLiveData()
val toastLiveData: LiveData
@@ -53,9 +53,9 @@ class CanStatusViewModel(private val repository: CanRepository) : BaseViewModel(
{
_isLoading.value = false
if (it.success && it.data != null) {
- _totalCoinLiveData.postValue(it.data.chargeCan + it.data.rewardCan)
- _paidCoinLiveData.postValue(it.data.chargeCan)
- _rewardCoinLiveData.postValue(it.data.rewardCan)
+ _totalCanLiveData.postValue(it.data.chargeCan + it.data.rewardCan)
+ _paidCanLiveData.postValue(it.data.chargeCan)
+ _rewardCanLiveData.postValue(it.data.rewardCan)
} else {
if (it.message != null) {
_toastLiveData.postValue(it.message)
@@ -75,7 +75,7 @@ class CanStatusViewModel(private val repository: CanRepository) : BaseViewModel(
)
}
- fun getCoinUseStatus() {
+ fun getCanUseStatus() {
_isLoading.value = true
compositeDisposable.add(
repository.getCanUseStatus(
@@ -89,7 +89,7 @@ class CanStatusViewModel(private val repository: CanRepository) : BaseViewModel(
{
_isLoading.value = false
if (it.success && it.data != null) {
- _coinUseStatusLiveData.postValue(it.data!!)
+ _canUseStatusLiveData.postValue(it.data!!)
} else {
if (it.message != null) {
_toastLiveData.postValue(it.message)
@@ -123,7 +123,7 @@ class CanStatusViewModel(private val repository: CanRepository) : BaseViewModel(
{
_isLoading.value = false
if (it.success && it.data != null) {
- _coinChargeStatusLiveData.postValue(it.data!!)
+ _canChargeStatusLiveData.postValue(it.data!!)
} else {
if (it.message != null) {
_toastLiveData.postValue(it.message)
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/status/charge/CanChargeStatusAdapter.kt b/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/status/charge/CanChargeStatusAdapter.kt
index 29f0da0..6608194 100644
--- a/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/status/charge/CanChargeStatusAdapter.kt
+++ b/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/status/charge/CanChargeStatusAdapter.kt
@@ -13,7 +13,7 @@ class CanChargeStatusAdapter : RecyclerView.Adapter
fun bind(item: GetCanUseStatusResponseItem) {
binding.tvTitle.text = item.title
binding.tvDate.text = item.date
- binding.tvCoin.text = "${item.can}"
+ binding.tvCan.text = "${item.can}"
}
}
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/status/use/CanUseStatusFragment.kt b/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/status/use/CanUseStatusFragment.kt
index d1fa376..b86d098 100644
--- a/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/status/use/CanUseStatusFragment.kt
+++ b/app/src/main/java/kr/co/vividnext/sodalive/mypage/can/status/use/CanUseStatusFragment.kt
@@ -25,11 +25,11 @@ class CanUseStatusFragment(
setupView()
bindData()
- viewModel.getCoinUseStatus()
+ viewModel.getCanUseStatus()
}
private fun setupView() {
- val recyclerView = binding.rvCoinStatus
+ val recyclerView = binding.rvCanStatus
adapter = CanUseStatusAdapter()
recyclerView.layoutManager = LinearLayoutManager(
@@ -71,7 +71,7 @@ class CanUseStatusFragment(
@SuppressLint("NotifyDataSetChanged")
private fun bindData() {
- viewModel.coinUseStatusLiveData.observe(viewLifecycleOwner) {
+ viewModel.canUseStatusLiveData.observe(viewLifecycleOwner) {
adapter.items.addAll(it)
adapter.notifyDataSetChanged()
}
diff --git a/app/src/main/res/drawable/bg_round_corner_10_232323_777777.xml b/app/src/main/res/drawable/bg_round_corner_10_232323_777777.xml
new file mode 100644
index 0000000..9b82a2b
--- /dev/null
+++ b/app/src/main/res/drawable/bg_round_corner_10_232323_777777.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/bg_round_corner_10_4d9970ff_9970ff.xml b/app/src/main/res/drawable/bg_round_corner_10_4d9970ff_9970ff.xml
new file mode 100644
index 0000000..ffe4bab
--- /dev/null
+++ b/app/src/main/res/drawable/bg_round_corner_10_4d9970ff_9970ff.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_can_charge.xml b/app/src/main/res/layout/activity_can_charge.xml
new file mode 100644
index 0000000..cc89b85
--- /dev/null
+++ b/app/src/main/res/layout/activity_can_charge.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_can_payment.xml b/app/src/main/res/layout/activity_can_payment.xml
new file mode 100644
index 0000000..3f050e4
--- /dev/null
+++ b/app/src/main/res/layout/activity_can_payment.xml
@@ -0,0 +1,210 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_can_status.xml b/app/src/main/res/layout/activity_can_status.xml
index 41ae6b0..e5169e8 100644
--- a/app/src/main/res/layout/activity_can_status.xml
+++ b/app/src/main/res/layout/activity_can_status.xml
@@ -13,7 +13,7 @@
diff --git a/app/src/main/res/layout/fragment_my.xml b/app/src/main/res/layout/fragment_my.xml
index 13f8d31..da41b9e 100644
--- a/app/src/main/res/layout/fragment_my.xml
+++ b/app/src/main/res/layout/fragment_my.xml
@@ -166,7 +166,7 @@
android:padding="13.3dp">
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/item_can_use_status.xml b/app/src/main/res/layout/item_can_use_status.xml
index 421879a..feff05b 100644
--- a/app/src/main/res/layout/item_can_use_status.xml
+++ b/app/src/main/res/layout/item_can_use_status.xml
@@ -33,7 +33,7 @@
tools:text="2021.07.22 | 21:02:45" />
#FF000000
#FFFFFFFF
+ #80DFFF
+ #1313BC
#9970FF
#EEEEEE
#777777
@@ -24,11 +26,11 @@
#fdca2f
#352953
#664aab
+ #232323
#B3909090
#88909090
#339970FF
#7FE2E2E2
- #80DFFF
- #1313BC
+ #4D9970FF