1.增加信用卡支付信息展示
This commit is contained in:
@@ -28,9 +28,9 @@ android {
|
|||||||
applicationId "com.abbidot.tracker"
|
applicationId "com.abbidot.tracker"
|
||||||
minSdkVersion 23
|
minSdkVersion 23
|
||||||
targetSdkVersion 35
|
targetSdkVersion 35
|
||||||
versionCode 2211
|
versionCode 2212
|
||||||
versionName "2.2.11"
|
// versionName "2.2.12"
|
||||||
// versionName "2.2.11-Beta1"
|
versionName "2.2.12-Beta1"
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class CreditCardAdapter(
|
|||||||
}
|
}
|
||||||
primary.visibility = if (item.isPrimary) View.VISIBLE else View.GONE
|
primary.visibility = if (item.isPrimary) View.VISIBLE else View.GONE
|
||||||
holder.getTextView(R.id.tv_credit_card_number_item).apply {
|
holder.getTextView(R.id.tv_credit_card_number_item).apply {
|
||||||
val formatCardNumber = Util.formatCardNumber(item.cardNumber)
|
val formatCardNumber = maskString(Util.formatCardNumber(item.cardNumber))
|
||||||
val cardLogoImageId = Util.getCreditCardType(item.cardNumber)
|
val cardLogoImageId = Util.getCreditCardType(item.cardNumber)
|
||||||
text = formatCardNumber
|
text = formatCardNumber
|
||||||
if (cardLogoImageId == 0) setCompoundDrawablesWithIntrinsicBounds(
|
if (cardLogoImageId == 0) setCompoundDrawablesWithIntrinsicBounds(
|
||||||
@@ -50,4 +50,24 @@ class CreditCardAdapter(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun maskString(input: String): String {
|
||||||
|
if (input.isBlank()) return input
|
||||||
|
// 先去除原有所有空格,统一重新4位分隔
|
||||||
|
val noSpace = input.replace(" ", "")
|
||||||
|
// 每4位分组加空格
|
||||||
|
val splitStr = buildString {
|
||||||
|
for (i in noSpace.indices step 4) {
|
||||||
|
val end = minOf(i + 4, noSpace.length)
|
||||||
|
append(noSpace.substring(i, end))
|
||||||
|
if (end != noSpace.length) append(" ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 再对分隔后的字符串脱敏(仅最后4位明文,其余非空格变*)
|
||||||
|
if (splitStr.length <= 4) return splitStr
|
||||||
|
val hidePart = splitStr.dropLast(4)
|
||||||
|
val showPart = splitStr.takeLast(4)
|
||||||
|
val maskHide = hidePart.map { if (it == ' ') ' ' else '*' }.joinToString("")
|
||||||
|
return maskHide + showPart
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -56,8 +56,11 @@ interface INetworkService {
|
|||||||
|
|
||||||
//亚马逊服务器(国外ip)
|
//亚马逊服务器(国外ip)
|
||||||
const val BASE_URL_ABROAD = "https://aws.abbidot.com/abbidot/"
|
const val BASE_URL_ABROAD = "https://aws.abbidot.com/abbidot/"
|
||||||
// const val BASE_URL_ABROAD = "http://192.168.0.220:8080/abbidot/"
|
|
||||||
// const val BASE_URL_ABROAD = "$IP_SERVER:8443/abbidotServer/"
|
//测试服务器
|
||||||
|
const val BASE_URL_TEST = "https://aws.abbidot.com:8443/abbidot/"
|
||||||
|
// const val BASE_URL_TEST = "http://aws.abbidot.com:8089/abbidot/"
|
||||||
|
// const val BASE_URL_ABROAD = "http://192.168.0.220:8080/abbidot/"
|
||||||
|
|
||||||
//亚马逊服务器(国内ip)
|
//亚马逊服务器(国内ip)
|
||||||
// const val BASE_URL_CN = "$IP_SERVER:8443/abbidotServer/"
|
// const val BASE_URL_CN = "$IP_SERVER:8443/abbidotServer/"
|
||||||
@@ -1133,6 +1136,16 @@ interface INetworkService {
|
|||||||
@Field("iccid") iccid: String
|
@Field("iccid") iccid: String
|
||||||
): BaseResponse<String>
|
): BaseResponse<String>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存支付信息
|
||||||
|
*/
|
||||||
|
@FormUrlEncoded
|
||||||
|
@POST("pay$STRIPE_VERSION_NUMBER/savePaymentMethodInfo")
|
||||||
|
suspend fun savePaymentMethodInfo(
|
||||||
|
@Field("userId") orderId: String,
|
||||||
|
@Field("paymentMethodID") paymentMethodID: String
|
||||||
|
): BaseResponse<String>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stripe支付 Rsa算法解密测试
|
* Stripe支付 Rsa算法解密测试
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package com.abbidot.tracker.retrofit2
|
package com.abbidot.tracker.retrofit2
|
||||||
|
|
||||||
import com.abbidot.baselibrary.constant.MMKVKey
|
|
||||||
import com.abbidot.baselibrary.network.base.BaseNetworkApi
|
import com.abbidot.baselibrary.network.base.BaseNetworkApi
|
||||||
import com.abbidot.baselibrary.util.MMKVUtil
|
|
||||||
import com.abbidot.tracker.bean.FencesBean
|
import com.abbidot.tracker.bean.FencesBean
|
||||||
import com.abbidot.tracker.bean.PayResultBean
|
import com.abbidot.tracker.bean.PayResultBean
|
||||||
import com.abbidot.tracker.bean.SetMealBean
|
import com.abbidot.tracker.bean.SetMealBean
|
||||||
@@ -1008,9 +1006,8 @@ object NetworkApi : BaseNetworkApi<INetworkService>(INetworkService.BASE_URL) {
|
|||||||
* Stripe支付创建消费用户
|
* Stripe支付创建消费用户
|
||||||
*/
|
*/
|
||||||
suspend fun createCustomer(
|
suspend fun createCustomer(
|
||||||
param: String, userId: String, userName: String, email: String
|
param: String, userId: String, userName: String, email: String, paymentMethodID: String
|
||||||
) = getResult {
|
) = getResult {
|
||||||
val paymentMethodID = MMKVUtil.getString(MMKVKey.PaymentMethodID)
|
|
||||||
service.createCustomer(param, userId, userName, email, paymentMethodID)
|
service.createCustomer(param, userId, userName, email, paymentMethodID)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1062,6 +1059,13 @@ object NetworkApi : BaseNetworkApi<INetworkService>(INetworkService.BASE_URL) {
|
|||||||
service.cancelStripeSubscription(orderId, subscriptionId, iccid)
|
service.cancelStripeSubscription(orderId, subscriptionId, iccid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存支付信息
|
||||||
|
*/
|
||||||
|
suspend fun savePaymentMethodInfo(userId: String, paymentMethodID: String) = getResult {
|
||||||
|
service.savePaymentMethodInfo(userId, paymentMethodID)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stripe支付 Rsa算法解密测试
|
* Stripe支付 Rsa算法解密测试
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -81,11 +81,12 @@ class SplashActivity : QMUIActivity() {
|
|||||||
Utils.SECRET_KEY = Util.getMetadata(applicationContext, KeyNames.HTTP_REQUEST_KEY)
|
Utils.SECRET_KEY = Util.getMetadata(applicationContext, KeyNames.HTTP_REQUEST_KEY)
|
||||||
INetworkService.apply {
|
INetworkService.apply {
|
||||||
//国内外服务器切换域名
|
//国内外服务器切换域名
|
||||||
BASE_URL = if (AppUtils.isChina()) {
|
BASE_URL = if (AppUtils.isDebug()) BASE_URL_TEST
|
||||||
|
else if (AppUtils.isChina())
|
||||||
BASE_URL_CN
|
BASE_URL_CN
|
||||||
} else {
|
else
|
||||||
BASE_URL_ABROAD
|
BASE_URL_ABROAD
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SRBleUtil.instance.init(application)
|
SRBleUtil.instance.init(application)
|
||||||
|
|||||||
@@ -267,7 +267,8 @@ class PetProfileActivity :
|
|||||||
private fun setPetData() {
|
private fun setPetData() {
|
||||||
mViewBinding.apply {
|
mViewBinding.apply {
|
||||||
mPetBean?.let {
|
mPetBean?.let {
|
||||||
ViewUtil.instance.setPetTypeHead(mContext,
|
ViewUtil.instance.setPetTypeHead(
|
||||||
|
mContext,
|
||||||
ilPetProfileHeadLayout.ilPetProfileHead.appHeadImage, it.imgurl, it.petType
|
ilPetProfileHeadLayout.ilPetProfileHead.appHeadImage, it.imgurl, it.petType
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -332,7 +333,8 @@ class PetProfileActivity :
|
|||||||
val dataBean = typeList[pos]
|
val dataBean = typeList[pos]
|
||||||
mPetBean?.apply {
|
mPetBean?.apply {
|
||||||
petType = dataBean.menuType
|
petType = dataBean.menuType
|
||||||
if (TextUtils.isEmpty(mSelectPetHeadPath) && TextUtils.isEmpty(imgurl)) ViewUtil.instance.setPetTypeHead(mContext,
|
if (TextUtils.isEmpty(mSelectPetHeadPath) && TextUtils.isEmpty(imgurl)) ViewUtil.instance.setPetTypeHead(
|
||||||
|
mContext,
|
||||||
mViewBinding.ilPetProfileHeadLayout.ilPetProfileHead.appHeadImage,
|
mViewBinding.ilPetProfileHeadLayout.ilPetProfileHead.appHeadImage,
|
||||||
imgurl,
|
imgurl,
|
||||||
petType
|
petType
|
||||||
|
|||||||
@@ -6,20 +6,30 @@ import android.text.InputType
|
|||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.View.OnFocusChangeListener
|
import android.view.View.OnFocusChangeListener
|
||||||
|
import androidx.activity.viewModels
|
||||||
import androidx.appcompat.widget.AppCompatEditText
|
import androidx.appcompat.widget.AppCompatEditText
|
||||||
import androidx.core.widget.addTextChangedListener
|
import androidx.core.widget.addTextChangedListener
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.abbidot.baselibrary.constant.ResultCode
|
import com.abbidot.baselibrary.constant.ResultCode
|
||||||
import com.abbidot.baselibrary.util.AppUtils
|
import com.abbidot.baselibrary.util.AppUtils
|
||||||
|
import com.abbidot.baselibrary.util.LogUtil
|
||||||
import com.abbidot.tracker.R
|
import com.abbidot.tracker.R
|
||||||
import com.abbidot.tracker.base.BaseActivity
|
import com.abbidot.tracker.base.BaseActivity
|
||||||
import com.abbidot.tracker.base.BaseDialog
|
import com.abbidot.tracker.base.BaseDialog
|
||||||
import com.abbidot.tracker.bean.CreditCardBean
|
import com.abbidot.tracker.bean.CreditCardBean
|
||||||
|
import com.abbidot.tracker.constant.ConstantInt
|
||||||
import com.abbidot.tracker.constant.ConstantString
|
import com.abbidot.tracker.constant.ConstantString
|
||||||
|
import com.abbidot.tracker.constant.GetResultCallback
|
||||||
import com.abbidot.tracker.database.MyDatabase
|
import com.abbidot.tracker.database.MyDatabase
|
||||||
import com.abbidot.tracker.databinding.ActivityAddCreditCardPaymentBinding
|
import com.abbidot.tracker.databinding.ActivityAddCreditCardPaymentBinding
|
||||||
|
import com.abbidot.tracker.util.ThirdPartyUtil
|
||||||
import com.abbidot.tracker.util.Util
|
import com.abbidot.tracker.util.Util
|
||||||
import com.abbidot.tracker.util.ViewUtil
|
import com.abbidot.tracker.util.ViewUtil
|
||||||
|
import com.abbidot.tracker.vm.SubscriptionPayViewModel
|
||||||
|
import com.stripe.android.ApiResultCallback
|
||||||
|
import com.stripe.android.Stripe
|
||||||
|
import com.stripe.android.model.PaymentMethod
|
||||||
|
import com.stripe.android.model.PaymentMethodCreateParams
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@@ -28,6 +38,8 @@ class AddCreditCardPaymentActivity :
|
|||||||
BaseActivity<ActivityAddCreditCardPaymentBinding>(ActivityAddCreditCardPaymentBinding::inflate),
|
BaseActivity<ActivityAddCreditCardPaymentBinding>(ActivityAddCreditCardPaymentBinding::inflate),
|
||||||
OnFocusChangeListener {
|
OnFocusChangeListener {
|
||||||
|
|
||||||
|
private val mSubscriptionPayViewModel: SubscriptionPayViewModel by viewModels()
|
||||||
|
|
||||||
private var mCreditCard: CreditCardBean? = null
|
private var mCreditCard: CreditCardBean? = null
|
||||||
private var mOldCard: CreditCardBean? = null
|
private var mOldCard: CreditCardBean? = null
|
||||||
private var isEdit = false
|
private var isEdit = false
|
||||||
@@ -47,7 +59,7 @@ class AddCreditCardPaymentActivity :
|
|||||||
if (isEdit) {
|
if (isEdit) {
|
||||||
mOldCard = mCreditCard
|
mOldCard = mCreditCard
|
||||||
setTopBarTitle(R.string.txt_edit_pay_method)
|
setTopBarTitle(R.string.txt_edit_pay_method)
|
||||||
mRightImageButton = addRightImageButton(R.drawable.icon_delete_svg)
|
// mRightImageButton = addRightImageButton(R.drawable.icon_delete_svg)
|
||||||
} else {
|
} else {
|
||||||
setTopBarTitle(R.string.txt_add_payment)
|
setTopBarTitle(R.string.txt_add_payment)
|
||||||
}
|
}
|
||||||
@@ -116,6 +128,21 @@ class AddCreditCardPaymentActivity :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun liveDataObserve() {
|
||||||
|
mSubscriptionPayViewModel.mSavePaymentMethodIDLiveData.observe(this) {
|
||||||
|
dealRequestResult(it, object : GetResultCallback {
|
||||||
|
override fun onResult(any: Any) {
|
||||||
|
setResult(ResultCode.ResultCode_1, null)
|
||||||
|
showToast(R.string.txt_save_successful, isFinish = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRequestError(exceptionCode: String?) {
|
||||||
|
setButtonEnabled(mViewBinding.btnSaveNewCreditCard, ConstantInt.Type1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 编辑时显示还原内容
|
* 编辑时显示还原内容
|
||||||
*/
|
*/
|
||||||
@@ -215,7 +242,6 @@ class AddCreditCardPaymentActivity :
|
|||||||
}
|
}
|
||||||
|
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
|
||||||
val list = MyDatabase.creditCardDao().findAll(MyDatabase.CREDIT_CARD_TABLE)
|
val list = MyDatabase.creditCardDao().findAll(MyDatabase.CREDIT_CARD_TABLE)
|
||||||
var existCard: CreditCardBean? = null
|
var existCard: CreditCardBean? = null
|
||||||
list?.apply {
|
list?.apply {
|
||||||
@@ -318,6 +344,90 @@ class AddCreditCardPaymentActivity :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun confirmSaveCardV2() {
|
||||||
|
mViewBinding.apply {
|
||||||
|
val cardNumber = ilAddCardNumber.etInputView2Content.text.toString().replace(" ", "")
|
||||||
|
val cardName = ilAddCardNameOnCard.etInputView2Content.text.toString()
|
||||||
|
val creditCardValidity = etAddCardMmDdContent.text.toString()
|
||||||
|
val cvv = etAddCardCvcContent.text.toString()
|
||||||
|
|
||||||
|
if (TextUtils.isEmpty(cardNumber) || TextUtils.isEmpty(cardName) || TextUtils.isEmpty(
|
||||||
|
creditCardValidity
|
||||||
|
) || TextUtils.isEmpty(cvv)
|
||||||
|
) {
|
||||||
|
showToast(R.string.txt_not_null)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!creditCardValidity.contains("/")) {
|
||||||
|
showToast(R.string.txt_card_validity_format)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
val dates = creditCardValidity.split("/")
|
||||||
|
try {
|
||||||
|
if (dates[0].toInt() > 12) {
|
||||||
|
showToast(R.string.txt_card_validity_format)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
showToast(R.string.txt_card_validity_format)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Util.getCreditCardType(cardNumber) == 0 || cardNumber.length < 9) {
|
||||||
|
showToast(R.string.txt_card_number_format)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setButtonEnabled(btnSaveNewCreditCard, ConstantInt.Type0)
|
||||||
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
mCreditCard?.let {
|
||||||
|
MyDatabase.creditCardDao().deleteAll(MyDatabase.CREDIT_CARD_TABLE)
|
||||||
|
it.cardNumber = cardNumber
|
||||||
|
it.cardName = cardName
|
||||||
|
it.expirationDate = creditCardValidity
|
||||||
|
it.cvv = cvv
|
||||||
|
val insertResult = MyDatabase.creditCardDao().insert(it)
|
||||||
|
if (insertResult > 0) {
|
||||||
|
if (isEdit) {
|
||||||
|
val dates = creditCardValidity.split("/")
|
||||||
|
// 用 PaymentMethodCreateParams 封装银行卡,不再直接new Card
|
||||||
|
val cardParams =
|
||||||
|
PaymentMethodCreateParams.Card.Builder().setNumber(cardNumber)
|
||||||
|
.setExpiryMonth(dates[0].toInt())
|
||||||
|
.setExpiryYear(dates[1].toInt()).setCvc(cvv).build()
|
||||||
|
val paymentMethodParams = PaymentMethodCreateParams.create(cardParams)
|
||||||
|
val stripeKey = ThirdPartyUtil.instance.getStripeKey(mContext)
|
||||||
|
LogUtil.e("支付stripeKey=$stripeKey")
|
||||||
|
Stripe(mContext, stripeKey).createPaymentMethod(
|
||||||
|
paymentMethodParams,
|
||||||
|
callback = object : ApiResultCallback<PaymentMethod> {
|
||||||
|
override fun onError(e: Exception) {
|
||||||
|
showToast(R.string.txt_missing_param)
|
||||||
|
setButtonEnabled(btnSaveNewCreditCard, ConstantInt.Type1)
|
||||||
|
LogUtil.e("PaymentMethodCreateParams,${e.message}")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSuccess(result: PaymentMethod) {
|
||||||
|
LogUtil.e(result.toString())
|
||||||
|
val paymentMethodID = "${result.id}"
|
||||||
|
mSubscriptionPayViewModel.savePaymentMethodInfo(
|
||||||
|
paymentMethodID
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
runOnUiThread {
|
||||||
|
setResult(ResultCode.ResultCode_1, null)
|
||||||
|
showToast(R.string.txt_save_successful, isFinish = true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun deleteCard() {
|
private fun deleteCard() {
|
||||||
ViewUtil.instance.showDialog(
|
ViewUtil.instance.showDialog(
|
||||||
mContext, R.string.txt_sure_delete_card, object : BaseDialog.OnDialogOkListener {
|
mContext, R.string.txt_sure_delete_card, object : BaseDialog.OnDialogOkListener {
|
||||||
@@ -338,7 +448,7 @@ class AddCreditCardPaymentActivity :
|
|||||||
override fun onClick(v: View?) {
|
override fun onClick(v: View?) {
|
||||||
mViewBinding.apply {
|
mViewBinding.apply {
|
||||||
when (v!!) {
|
when (v!!) {
|
||||||
btnSaveNewCreditCard -> confirmSaveCard()
|
btnSaveNewCreditCard -> confirmSaveCardV2()
|
||||||
llAddCardMmDdLayout -> setClickEditViewVisible(etAddCardMmDdContent)
|
llAddCardMmDdLayout -> setClickEditViewVisible(etAddCardMmDdContent)
|
||||||
llAddCardCvcLayout -> setClickEditViewVisible(etAddCardCvcContent)
|
llAddCardCvcLayout -> setClickEditViewVisible(etAddCardCvcContent)
|
||||||
ilAddCardNameOnCard.root -> setClickEditViewVisible(ilAddCardNameOnCard.etInputView2Content)
|
ilAddCardNameOnCard.root -> setClickEditViewVisible(ilAddCardNameOnCard.etInputView2Content)
|
||||||
|
|||||||
@@ -46,26 +46,6 @@ class PaymentMethodActivity :
|
|||||||
setTopBarTitle(R.string.txt_payment_method)
|
setTopBarTitle(R.string.txt_payment_method)
|
||||||
setLeftBackImage(R.drawable.icon_white_back_svg)
|
setLeftBackImage(R.drawable.icon_white_back_svg)
|
||||||
|
|
||||||
// 用 PaymentMethodCreateParams 封装银行卡,不再直接new Card
|
|
||||||
// val cardParams = PaymentMethodCreateParams.Card.Builder()
|
|
||||||
// .setNumber("4242424242424242")
|
|
||||||
// .setExpiryMonth(12)
|
|
||||||
// .setExpiryYear(2028)
|
|
||||||
// .setCvc("123")
|
|
||||||
// .build()
|
|
||||||
// val paymentMethodParams = PaymentMethodCreateParams.create(cardParams)
|
|
||||||
// val stripeKey = ThirdPartyUtil.instance.getStripeKey(mContext)
|
|
||||||
// Stripe(mContext, stripeKey).createPaymentMethod(
|
|
||||||
// paymentMethodParams, callback = object : ApiResultCallback<PaymentMethod> {
|
|
||||||
// override fun onError(e: Exception) {
|
|
||||||
// LogUtil.e("ApiResultCallback,${e.message}")
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// override fun onSuccess(result: PaymentMethod) {
|
|
||||||
// LogUtil.e(result.toString())
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
|
|
||||||
intent.extras?.apply {
|
intent.extras?.apply {
|
||||||
mOrderBean = Util.getParcelableAdaptive(
|
mOrderBean = Util.getParcelableAdaptive(
|
||||||
intent, ConstantString.LkSetMeal, SubscriptionsOrderBean::class.java
|
intent, ConstantString.LkSetMeal, SubscriptionsOrderBean::class.java
|
||||||
@@ -103,7 +83,7 @@ class PaymentMethodActivity :
|
|||||||
getUserPaymentMethodID()
|
getUserPaymentMethodID()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getUserPaymentMethodID(){
|
fun getUserPaymentMethodID() {
|
||||||
mSubscriptionPayViewModel.getUserPaymentMethodID()
|
mSubscriptionPayViewModel.getUserPaymentMethodID()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,6 +97,7 @@ class PaymentMethodActivity :
|
|||||||
override fun onResult(any: Any) {
|
override fun onResult(any: Any) {
|
||||||
it.getOrNull()?.let { p ->
|
it.getOrNull()?.let { p ->
|
||||||
mPaymentIDBean = p
|
mPaymentIDBean = p
|
||||||
|
(mFragments[0] as CreditCardPaymentFragment).getCardData(p.stripeMethodInfo)
|
||||||
if (mFragments.size > 1) {
|
if (mFragments.size > 1) {
|
||||||
(mFragments[1] as PaypalPaymentFragment).showPaypalInfo()
|
(mFragments[1] as PaypalPaymentFragment).showPaypalInfo()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -786,7 +786,7 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
|
|||||||
MMKVUtil.putBoolean(MMKVKey.isGpsToGCJ02, !isOutOfChina)
|
MMKVUtil.putBoolean(MMKVKey.isGpsToGCJ02, !isOutOfChina)
|
||||||
}
|
}
|
||||||
|
|
||||||
showNoSetWifiDialog(this)
|
// showNoSetWifiDialog(this)
|
||||||
|
|
||||||
mHomeMapCommon.refreshPetCurrentLocation(latitude, longitude, isMoveCamera)
|
mHomeMapCommon.refreshPetCurrentLocation(latitude, longitude, isMoveCamera)
|
||||||
isMoveCamera = false
|
isMoveCamera = false
|
||||||
|
|||||||
@@ -2,16 +2,15 @@ package com.abbidot.tracker.ui.fragment.subscribe
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.text.TextUtils
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.abbidot.baselibrary.constant.MMKVKey
|
|
||||||
import com.abbidot.baselibrary.constant.ResultCode
|
import com.abbidot.baselibrary.constant.ResultCode
|
||||||
import com.abbidot.baselibrary.list.BaseRecyclerAdapter
|
import com.abbidot.baselibrary.list.BaseRecyclerAdapter
|
||||||
import com.abbidot.baselibrary.util.AppUtils
|
import com.abbidot.baselibrary.util.AppUtils
|
||||||
import com.abbidot.baselibrary.util.LogUtil
|
import com.abbidot.baselibrary.util.LogUtil
|
||||||
import com.abbidot.baselibrary.util.MMKVUtil
|
|
||||||
import com.abbidot.tracker.R
|
import com.abbidot.tracker.R
|
||||||
import com.abbidot.tracker.adapter.CreditCardAdapter
|
import com.abbidot.tracker.adapter.CreditCardAdapter
|
||||||
import com.abbidot.tracker.base.BaseFragment
|
import com.abbidot.tracker.base.BaseFragment
|
||||||
@@ -90,20 +89,46 @@ class CreditCardPaymentFragment : BaseFragment<FragmentCreditCardPaymentBinding>
|
|||||||
|
|
||||||
setOnClickListenerViews(btnCreditCardPaymentAdd, btnMakePaymentCreditCard)
|
setOnClickListenerViews(btnCreditCardPaymentAdd, btnMakePaymentCreditCard)
|
||||||
}
|
}
|
||||||
getCardData()
|
// getCardData()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getCardData() {
|
fun getCardData(stripeMethodInfo: CreditCardBean) {
|
||||||
viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
|
if (TextUtils.isEmpty(stripeMethodInfo.lastFourNumber)) {
|
||||||
val list = MyDatabase.creditCardDao().findAll(MyDatabase.CREDIT_CARD_TABLE)
|
viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
|
||||||
list?.let {
|
val list = MyDatabase.creditCardDao().findAll(MyDatabase.CREDIT_CARD_TABLE)
|
||||||
mActivity?.runOnUiThread {
|
list?.let {
|
||||||
val sortedByList = list.sortedByDescending { l -> l.isPrimary }.toMutableList()
|
mActivity?.runOnUiThread {
|
||||||
setCheckAndPrimaryState(sortedByList)
|
val sortedByList =
|
||||||
mCreditCardAdapter.setData(sortedByList, true)
|
list.sortedByDescending { l -> l.isPrimary }.toMutableList()
|
||||||
|
setCheckAndPrimaryState(sortedByList)
|
||||||
|
mCreditCardAdapter.setData(sortedByList, true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
stripeMethodInfo.apply {
|
||||||
|
expirationDate = "$expMonth/$expYear"
|
||||||
|
cardNumber = lastFourNumber
|
||||||
|
cardName = "****"
|
||||||
|
cvv = "****"
|
||||||
|
}
|
||||||
|
mViewBinding.apply {
|
||||||
|
tvCreditCardPaymentChoose.visibility = View.VISIBLE
|
||||||
|
btnCreditCardPaymentAdd.visibility = View.INVISIBLE
|
||||||
|
//卡管理 不需要点击效果
|
||||||
|
if (null == getHostActivity(PaymentMethodActivity::class.java)?.mOrderBean) {
|
||||||
|
btnMakePaymentCreditCard.visibility = View.GONE
|
||||||
|
} else {
|
||||||
|
stripeMethodInfo.checked = true
|
||||||
|
btnMakePaymentCreditCard.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mutableListOf<CreditCardBean>().apply {
|
||||||
|
add(stripeMethodInfo)
|
||||||
|
mCreditCardAdapter.setData(this, true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
ViewUtil.instance.viewShow(mViewBinding.rvCreditCardPaymentList)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun goEditCard(cardBean: CreditCardBean) {
|
fun goEditCard(cardBean: CreditCardBean) {
|
||||||
@@ -181,7 +206,7 @@ class CreditCardPaymentFragment : BaseFragment<FragmentCreditCardPaymentBinding>
|
|||||||
}
|
}
|
||||||
mViewBinding.apply {
|
mViewBinding.apply {
|
||||||
tvCreditCardPaymentChoose.visibility = View.VISIBLE
|
tvCreditCardPaymentChoose.visibility = View.VISIBLE
|
||||||
btnCreditCardPaymentAdd.visibility = View.VISIBLE
|
btnCreditCardPaymentAdd.visibility = View.INVISIBLE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,7 +237,8 @@ class CreditCardPaymentFragment : BaseFragment<FragmentCreditCardPaymentBinding>
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
if (it.resultCode == ResultCode.ResultCode_1) {
|
if (it.resultCode == ResultCode.ResultCode_1) {
|
||||||
getCardData()
|
// getCardData()
|
||||||
|
getHostActivity(PaymentMethodActivity::class.java)?.getUserPaymentMethodID()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,38 +254,43 @@ class CreditCardPaymentFragment : BaseFragment<FragmentCreditCardPaymentBinding>
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
private fun startCreditCardPayment() {
|
private fun startCreditCardPayment() {
|
||||||
val list = mCreditCardAdapter.getData()
|
getHostActivity(PaymentMethodActivity::class.java)?.let {
|
||||||
for (card in list) {
|
val list = mCreditCardAdapter.getData()
|
||||||
if (card.checked) {
|
for (card in list) {
|
||||||
showNoCancelableLoading(true)
|
if (card.checked) {
|
||||||
|
showNoCancelableLoading(true)
|
||||||
|
if (null == it.mPaymentIDBean || TextUtils.isEmpty(it.mPaymentIDBean?.stripeMethodInfo?.lastFourNumber)) {
|
||||||
|
val dates = card.expirationDate.split("/")
|
||||||
|
// 用 PaymentMethodCreateParams 封装银行卡,不再直接new Card
|
||||||
|
val cardParams =
|
||||||
|
PaymentMethodCreateParams.Card.Builder().setNumber(card.cardNumber)
|
||||||
|
.setExpiryMonth(dates[0].toInt()).setExpiryYear(dates[1].toInt())
|
||||||
|
.setCvc(card.cvv).build()
|
||||||
|
val paymentMethodParams = PaymentMethodCreateParams.create(cardParams)
|
||||||
|
val stripeKey = ThirdPartyUtil.instance.getStripeKey(mContext!!)
|
||||||
|
LogUtil.e("支付stripeKey=$stripeKey")
|
||||||
|
Stripe(mContext!!, stripeKey).createPaymentMethod(
|
||||||
|
paymentMethodParams,
|
||||||
|
callback = object : ApiResultCallback<PaymentMethod> {
|
||||||
|
override fun onError(e: Exception) {
|
||||||
|
showToast(R.string.txt_missing_param)
|
||||||
|
showNoCancelableLoading(false)
|
||||||
|
LogUtil.e("ApiResultCallback,${e.message}")
|
||||||
|
}
|
||||||
|
|
||||||
val dates = card.expirationDate.split("/")
|
override fun onSuccess(result: PaymentMethod) {
|
||||||
// 用 PaymentMethodCreateParams 封装银行卡,不再直接new Card
|
LogUtil.e(result.toString())
|
||||||
val cardParams = PaymentMethodCreateParams.Card.Builder()
|
val paymentMethodID = "${result.id}"
|
||||||
.setNumber(card.cardNumber)
|
mSubscriptionPayViewModel.createCustomer(card, paymentMethodID)
|
||||||
.setExpiryMonth(dates[0].toInt())
|
}
|
||||||
.setExpiryYear(dates[1].toInt())
|
})
|
||||||
.setCvc(card.cvv)
|
} else {
|
||||||
.build()
|
mSubscriptionPayViewModel.createCustomer(card, "")
|
||||||
val paymentMethodParams = PaymentMethodCreateParams.create(cardParams)
|
}
|
||||||
val stripeKey = ThirdPartyUtil.instance.getStripeKey(mContext!!)
|
break
|
||||||
Stripe(mContext!!, stripeKey).createPaymentMethod(
|
}
|
||||||
paymentMethodParams, callback = object : ApiResultCallback<PaymentMethod> {
|
|
||||||
override fun onError(e: Exception) {
|
|
||||||
showToast(R.string.txt_missing_param)
|
|
||||||
showNoCancelableLoading(false)
|
|
||||||
LogUtil.e("ApiResultCallback,${e.message}")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onSuccess(result: PaymentMethod) {
|
|
||||||
LogUtil.e(result.toString())
|
|
||||||
val paymentMethodID = "${result.id}"
|
|
||||||
MMKVUtil.putString(MMKVKey.PaymentMethodID, paymentMethodID)
|
|
||||||
mSubscriptionPayViewModel.createCustomer(card)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,14 +39,17 @@ class PaypalPaymentFragment :
|
|||||||
tvPaypalPaymentGoTip.visibility = View.GONE
|
tvPaypalPaymentGoTip.visibility = View.GONE
|
||||||
btnSureRedirectPaypal.visibility = View.GONE
|
btnSureRedirectPaypal.visibility = View.GONE
|
||||||
ivSureRedirectPaypalBg.visibility = View.GONE
|
ivSureRedirectPaypalBg.visibility = View.GONE
|
||||||
|
showPaypalInfo()
|
||||||
} else {
|
} else {
|
||||||
tvNoPaypalPaymentEmail.visibility = View.GONE
|
tvNoPaypalPaymentEmail.visibility = View.GONE
|
||||||
}
|
}
|
||||||
showPaypalInfo()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun showPaypalInfo() {
|
fun showPaypalInfo() {
|
||||||
|
if (null == getHostActivity(PaymentMethodActivity::class.java)?.mOrderBean) {
|
||||||
|
return
|
||||||
|
}
|
||||||
getHostActivity(PaymentMethodActivity::class.java)?.let {
|
getHostActivity(PaymentMethodActivity::class.java)?.let {
|
||||||
it.mPaymentIDBean?.let { pId ->
|
it.mPaymentIDBean?.let { pId ->
|
||||||
mViewBinding.tvPaypalPaymentEmail.text = pId.paypalMethodInfo.email
|
mViewBinding.tvPaypalPaymentEmail.text = pId.paypalMethodInfo.email
|
||||||
|
|||||||
@@ -28,17 +28,21 @@ class SocketUtilManageV2 {
|
|||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
fun initEasySocket(context: Context, mac: String, data: ByteArray) {
|
fun initEasySocket(context: Context, mac: String, data: ByteArray) {
|
||||||
val data1 = SRBleCmdUtil.instance.byteToInt(data[1])
|
try {
|
||||||
val data2 = SRBleCmdUtil.instance.byteToInt(data[2])
|
val data1 = SRBleCmdUtil.instance.byteToInt(data[1])
|
||||||
val data3 = SRBleCmdUtil.instance.byteToInt(data[3])
|
val data2 = SRBleCmdUtil.instance.byteToInt(data[2])
|
||||||
val data4 = SRBleCmdUtil.instance.byteToInt(data[4])
|
val data3 = SRBleCmdUtil.instance.byteToInt(data[3])
|
||||||
val ip = "$data1.$data2.$data3.$data4"
|
val data4 = SRBleCmdUtil.instance.byteToInt(data[4])
|
||||||
val port = SRBleCmdUtil.instance.byte2ArrayToInt(data.sliceArray(5..6))
|
val ip = "$data1.$data2.$data3.$data4"
|
||||||
val socketAddress = "$ip:$port"
|
val port = SRBleCmdUtil.instance.byte2ArrayToInt(data.sliceArray(5..6))
|
||||||
LogUtil.e(socketAddress)
|
val socketAddress = "$ip:$port"
|
||||||
mMac = mac
|
LogUtil.e(socketAddress)
|
||||||
mNeedSendMessage = data.sliceArray(8..data.size - 2)
|
mMac = mac
|
||||||
initEasySocket(context, ip, port)
|
mNeedSendMessage = data.sliceArray(8..data.size - 2)
|
||||||
|
initEasySocket(context, ip, port)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
LogUtil.e("initEasySocket 异常:${e.message}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -873,17 +873,38 @@ class Util {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 限制limitLetterLength个字母或limitLetterLength/2个中文,限制空格输入
|
* 字符串截断 + 空格规则:
|
||||||
* 截断到最大limitLetterLength单位
|
* 1. 首位不能是空格
|
||||||
* @param limitLetterLength 限制字母的个数
|
* 2. 首位之后,只允许连续 1 个空格
|
||||||
|
* 3. 按[字符计算长度]截断,不超过限制长度
|
||||||
|
* @param limitLetterLength 最大字符单位长度
|
||||||
|
* @return 处理后的字符串
|
||||||
*/
|
*/
|
||||||
fun String.limitLetterChinese(limitLetterLength: Int): String {
|
fun String.limitLetterChinese(limitLetterLength: Int): String {
|
||||||
val sb = StringBuilder()
|
val sb = StringBuilder()
|
||||||
|
// 标记:上一个字符是否是空格
|
||||||
|
var lastIsSpace = false
|
||||||
|
|
||||||
for (c in this) {
|
for (c in this) {
|
||||||
if (c == ' ') break
|
// 规则1:首位直接拦截空格
|
||||||
|
if (sb.isEmpty() && c == ' ') {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 规则2:已存在一个连续空格,再遇到空格直接跳过(只保留单个空格)
|
||||||
|
if (c == ' ' && lastIsSpace) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拼接后判断是否超出长度限制,超出则终止
|
||||||
val temp = sb.toString() + c
|
val temp = sb.toString() + c
|
||||||
if (temp.calcLengthUnit() > limitLetterLength) break
|
if (temp.calcLengthUnit() > limitLetterLength) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// 追加字符,并更新空格标记
|
||||||
sb.append(c)
|
sb.append(c)
|
||||||
|
lastIsSpace = (c == ' ')
|
||||||
}
|
}
|
||||||
return sb.toString()
|
return sb.toString()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,11 +28,12 @@ class SubscriptionPayViewModel : ViewModel() {
|
|||||||
val mCreateStripeOrderLiveData = MutableLiveData<Result<PayResultBean>>()
|
val mCreateStripeOrderLiveData = MutableLiveData<Result<PayResultBean>>()
|
||||||
val mCreatePaypalOrderLiveData = MutableLiveData<Result<PayResultBean>>()
|
val mCreatePaypalOrderLiveData = MutableLiveData<Result<PayResultBean>>()
|
||||||
val mPaymentMethodIDLiveData = MutableLiveData<Result<PaymentIDBean>>()
|
val mPaymentMethodIDLiveData = MutableLiveData<Result<PaymentIDBean>>()
|
||||||
|
val mSavePaymentMethodIDLiveData = MutableLiveData<Result<String>>()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stripe支付创建消费用户
|
* Stripe支付创建消费用户
|
||||||
*/
|
*/
|
||||||
fun createCustomer(card: CreditCardBean) {
|
fun createCustomer(card: CreditCardBean,paymentMethodID: String) {
|
||||||
// activity.showLoading(true)
|
// activity.showLoading(true)
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
val userId = MMKVUtil.getString(MMKVKey.UserId)
|
val userId = MMKVUtil.getString(MMKVKey.UserId)
|
||||||
@@ -52,7 +53,7 @@ class SubscriptionPayViewModel : ViewModel() {
|
|||||||
|
|
||||||
val rsaKey = RSA.encrypt(cardJso, b)
|
val rsaKey = RSA.encrypt(cardJso, b)
|
||||||
LogUtil.e(cardJso)
|
LogUtil.e(cardJso)
|
||||||
val result = NetworkApi.createCustomer(rsaKey, userId, userName, email)
|
val result = NetworkApi.createCustomer(rsaKey, userId, userName, email,paymentMethodID)
|
||||||
mSubscriptionCustomerLiveData.postValue(result)
|
mSubscriptionCustomerLiveData.postValue(result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -80,4 +81,12 @@ class SubscriptionPayViewModel : ViewModel() {
|
|||||||
mPaymentMethodIDLiveData.value = result
|
mPaymentMethodIDLiveData.value = result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun savePaymentMethodInfo(paymentMethodID: String) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
val userId = MMKVUtil.getString(MMKVKey.UserId)
|
||||||
|
val result = NetworkApi.savePaymentMethodInfo(userId, paymentMethodID)
|
||||||
|
mSavePaymentMethodIDLiveData.value = result
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -41,6 +41,7 @@
|
|||||||
android:id="@+id/rv_credit_card_payment_list"
|
android:id="@+id/rv_credit_card_payment_list"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
android:visibility="gone"
|
||||||
android:layout_above="@id/btn_make_payment_credit_card"
|
android:layout_above="@id/btn_make_payment_credit_card"
|
||||||
android:layout_below="@id/btn_credit_card_payment_add"
|
android:layout_below="@id/btn_credit_card_payment_add"
|
||||||
android:layout_marginTop="@dimen/dp_12" />
|
android:layout_marginTop="@dimen/dp_12" />
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ import androidx.annotation.StringDef
|
|||||||
MMKVKey.MapType,
|
MMKVKey.MapType,
|
||||||
MMKVKey.ShowFence,
|
MMKVKey.ShowFence,
|
||||||
MMKVKey.ShowDashedLine,
|
MMKVKey.ShowDashedLine,
|
||||||
MMKVKey.PaymentMethodID,
|
|
||||||
MMKVKey.ShowAllPet,
|
MMKVKey.ShowAllPet,
|
||||||
MMKVKey.isCrash,
|
MMKVKey.isCrash,
|
||||||
MMKVKey.AvailableOrder,
|
MMKVKey.AvailableOrder,
|
||||||
@@ -60,7 +59,6 @@ annotation class MMKVKey {
|
|||||||
const val Phone = "phone"
|
const val Phone = "phone"
|
||||||
const val ActivityGoal = "activityGoal"
|
const val ActivityGoal = "activityGoal"
|
||||||
const val Location = "location"
|
const val Location = "location"
|
||||||
const val PaymentMethodID = "paymentMethodID"
|
|
||||||
const val Gender = "gender"
|
const val Gender = "gender"
|
||||||
const val BirthdayDate = "birthdayDate"
|
const val BirthdayDate = "birthdayDate"
|
||||||
const val CountryCode = "countryCode"
|
const val CountryCode = "countryCode"
|
||||||
|
|||||||
Reference in New Issue
Block a user