diff --git a/app/src/main/java/com/sw/dualscreen/activity/PayActivity.kt b/app/src/main/java/com/sw/dualscreen/activity/PayActivity.kt index 6c691e6..2b26a16 100644 --- a/app/src/main/java/com/sw/dualscreen/activity/PayActivity.kt +++ b/app/src/main/java/com/sw/dualscreen/activity/PayActivity.kt @@ -14,11 +14,10 @@ import com.sw.dualscreen.ext.gone import com.sw.dualscreen.model.response.FoodInfo import com.sw.dualscreen.model.response.MemberInfo import com.sw.dualscreen.model.response.PaySuccessEvent -import com.sw.dualscreen.presentation.pay.ScanQrCodePayPresentation +import com.sw.dualscreen.presentation.pay.PayPresentation import com.sw.dualscreen.utils.SPUtil import com.sw.dualscreen.viewmodel.BaseViewModel import com.sw.dualscreen.viewmodel.UserViewModel -import com.sw.plate.utils.ToastUtils import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel import org.greenrobot.eventbus.EventBus @@ -62,9 +61,19 @@ class PayActivity : BaseActivity() { var foodOrderId: String = "" var eatNum: Int = 1 + val presentation by lazy { + PayPresentation( + activity = this@PayActivity, + userViewModel = userViewModel, + recognizeViewModel = recognizeViewModel, + display = displays[1] + ) + } + @Suppress("DEPRECATION") override fun initialize() { super.initialize() + presentation.show() foodInfo = intent.getParcelableExtra(FOOD_INFO) foodOrderId = intent.getStringExtra(FOOD_ORDER_ID) ?: "" eatNum = intent.getIntExtra(FOOD_EAT_NUM, 1) @@ -101,7 +110,6 @@ class PayActivity : BaseActivity() { } showFacePay() } - showScanQrCodePay() } @@ -136,39 +144,43 @@ class PayActivity : BaseActivity() { } override fun onDestroy() { - qrCodePayFragment?.presentation?.dismiss() - cashPayFragment?.presentation?.dismiss() - numberPayFragment?.presentation?.dismiss() - facePayFragment?.presentation?.dismiss() - scanQrCodePayPresentation?.dismiss() + presentation?.dismiss() super.onDestroy() } - private var scanQrCodePayPresentation: ScanQrCodePayPresentation? = null var memberInfo: MemberInfo? = null fun showPayInfo(type: Int = 1, isVip: Boolean = false, memberInfo: MemberInfo? = null) { this.memberInfo = memberInfo payResultFragment = PayResultFragment.instance(type, memberInfo) showFragment(payResultFragment!!, TAG_PAY_RESULT) - if (displays.size > 1) { - scanQrCodePayPresentation = ScanQrCodePayPresentation( - activity = this, - display = displays[1], - type = type - ) { - scanQrCodePayPresentation?.dismiss() - }.also { - it.foodName = foodInfo?.foodName - //确认使用vipPrice 还是 specPrice - val onePrice = if (isVip) foodInfo?.vipPrice else foodInfo?.specPrice - it.totalPrice = (onePrice ?: 0.0) * eatNum - } - scanQrCodePayPresentation?.show() +// if (displays.size > 1) { +// scanQrCodePayPresentation = ScanQrCodePayPresentation( +// activity = this, +// display = displays[1], +// type = type +// ) { +// scanQrCodePayPresentation?.dismiss() +// }.also { +// it.foodName = foodInfo?.foodName +// //确认使用vipPrice 还是 specPrice +// val onePrice = if (isVip) foodInfo?.vipPrice else foodInfo?.specPrice +// it.totalPrice = (onePrice ?: 0.0) * eatNum +// } +// scanQrCodePayPresentation?.show() +// } + presentation.let { + it.type = type + it.foodName = foodInfo?.foodName + //确认使用vipPrice 还是 specPrice + val onePrice = if (isVip) foodInfo?.vipPrice else foodInfo?.specPrice + it.totalPrice = (onePrice ?: 0.0) * eatNum + presentation.initView() } } fun updateQrCodeImage(qrCodeUrl: String?) { - scanQrCodePayPresentation?.loadQrCodeImage(qrCodeUrl) +// scanQrCodePayPresentation?.loadQrCodeImage(qrCodeUrl) + presentation?.loadQrCodeImage(qrCodeUrl) } fun showPaySuccess(isVip: Boolean) { diff --git a/app/src/main/java/com/sw/dualscreen/activity/fragment/pay/CashPayFragment.kt b/app/src/main/java/com/sw/dualscreen/activity/fragment/pay/CashPayFragment.kt index e91f076..d62a74c 100644 --- a/app/src/main/java/com/sw/dualscreen/activity/fragment/pay/CashPayFragment.kt +++ b/app/src/main/java/com/sw/dualscreen/activity/fragment/pay/CashPayFragment.kt @@ -8,7 +8,7 @@ import com.sw.dualscreen.activity.PayActivity import com.sw.dualscreen.activity.fragment.BaseFragment import com.sw.dualscreen.databinding.FragmentCashPayBinding import com.sw.dualscreen.ext.format2String -import com.sw.dualscreen.presentation.pay.CashPayPresentation +import com.sw.dualscreen.presentation.pay.PayPresentation import com.sw.plate.utils.ToastUtils class CashPayFragment : BaseFragment() { @@ -17,8 +17,6 @@ class CashPayFragment : BaseFragment() { private var foodName: String? = null private var payAmount: Double? = null - var presentation: CashPayPresentation? = null - override fun inflateViewBinding(): FragmentCashPayBinding { return FragmentCashPayBinding.inflate(layoutInflater) } @@ -27,63 +25,73 @@ class CashPayFragment : BaseFragment() { payActivity = requireActivity() as PayActivity payActivity.foodInfo?.let { foodName = it.foodName - payAmount = (it.specPrice?:0.0) * payActivity.eatNum + payAmount = (it.specPrice ?: 0.0) * payActivity.eatNum } binding.tvRealAmount.text = getAmountText(payAmount.format2String(2)) binding.btnConfirmPayFinish.setOnClickListener { - payActivity.cashPay(hashMapOf( - //标价金额(单位为元) - "totalFee" to payAmount.format2String(2), - //订单类型(0付款1会员充值) - "orderType" to "0", - //商户订单号 - "orderNo" to payActivity.foodOrderId, - //支付来源:0线下收款 、3:线上纯会员支付 101:支付宝主动、102:支付宝被动、201:微信主动、202:微信被动 - "paySource" to "0" - )) { paySuccess -> + payActivity.cashPay( + hashMapOf( + //标价金额(单位为元) + "totalFee" to payAmount.format2String(2), + //订单类型(0付款1会员充值) + "orderType" to "0", + //商户订单号 + "orderNo" to payActivity.foodOrderId, + //支付来源:0线下收款 、3:线上纯会员支付 101:支付宝主动、102:支付宝被动、201:微信主动、202:微信被动 + "paySource" to "0" + ) + ) { paySuccess -> if (paySuccess.not()) { ToastUtils.showToast("接口调用失败") return@cashPay } - payActivity.showPaySuccess( false) + payActivity.showPaySuccess(false) } } showSubScreen() } - override fun onHiddenChanged(hidden: Boolean) { - super.onHiddenChanged(hidden) - if (hidden) { - dismissSubScreen() - return - } - //showSubScreen() - } - override fun onDestroy() { - dismissSubScreen() - super.onDestroy() - } - - private fun dismissSubScreen() { - presentation?.let { - if (it.isShowing) { - it.dismiss() - } - } - } +// override fun onHiddenChanged(hidden: Boolean) { +// super.onHiddenChanged(hidden) +// if (hidden) { +// dismissSubScreen() +// return +// } +// //showSubScreen() +// } +// +// override fun onDestroy() { +// dismissSubScreen() +// super.onDestroy() +// } +// +// private fun dismissSubScreen() { +// } private fun showSubScreen() { - // 查找副屏(通常索引为1) - if (displays.size > 1) { - dismissSubScreen() - presentation = CashPayPresentation(activity = payActivity, display = displays[1]) { - presentation?.dismiss() - }.also { - it.foodName = foodName - it.payAmount = payAmount.format2String(2) - } - presentation?.show() +// // 查找副屏(通常索引为1) +// if (displays.size > 1) { +// dismissSubScreen() +// presentation = PayPresentation( +// activity = payActivity, +// pageType = PayPresentation.CASH_PAY, +// userViewModel = payActivity.userViewModel, +// recognizeViewModel = payActivity.recognizeViewModel, +// display = displays[1] +// ) { +// presentation?.dismiss() +// }.also { +// it.foodName = foodName +// it.payAmount = payAmount.format2String(2) +// } +// presentation?.show() +// } + payActivity.presentation.let { + it.pageType = PayPresentation.CASH_PAY + it.foodName = foodName + it.payAmount = payAmount.format2String(2) + it.initView() } } diff --git a/app/src/main/java/com/sw/dualscreen/activity/fragment/pay/FacePayFragment.kt b/app/src/main/java/com/sw/dualscreen/activity/fragment/pay/FacePayFragment.kt index 32bdb44..215020d 100644 --- a/app/src/main/java/com/sw/dualscreen/activity/fragment/pay/FacePayFragment.kt +++ b/app/src/main/java/com/sw/dualscreen/activity/fragment/pay/FacePayFragment.kt @@ -5,14 +5,13 @@ import com.sw.dualscreen.activity.PayActivity import com.sw.dualscreen.activity.fragment.BaseFragment import com.sw.dualscreen.databinding.FragmentFacePayBinding import com.sw.dualscreen.ext.format2String -import com.sw.dualscreen.presentation.pay.FacePayPresentation +import com.sw.dualscreen.presentation.pay.PayPresentation class FacePayFragment : BaseFragment() { private lateinit var payActivity: PayActivity private var foodName: String? = null private var payAmount: Double? = null - var presentation: FacePayPresentation? = null override fun inflateViewBinding(): FragmentFacePayBinding { return FragmentFacePayBinding.inflate(layoutInflater) } @@ -32,24 +31,26 @@ class FacePayFragment : BaseFragment() { override fun onHiddenChanged(hidden: Boolean) { super.onHiddenChanged(hidden) if (hidden) { - dismissSubScreen() +// dismissSubScreen() + payActivity.presentation.pauseCamera() return } + payActivity.presentation.resumeCamera() //showSubScreen() } - override fun onDestroy() { - dismissSubScreen() - super.onDestroy() - } +// override fun onDestroy() { +// dismissSubScreen() +// super.onDestroy() +// } - private fun dismissSubScreen() { - presentation?.let { - if (it.isShowing) { - it.dismiss() - } - } - } +// private fun dismissSubScreen() { +// presentation?.let { +// if (it.isShowing) { +// it.dismiss() +// } +// } +// } fun loadBitmap(frame: Bitmap) { binding.ivFaceImage.setImageBitmap(frame) @@ -57,21 +58,28 @@ class FacePayFragment : BaseFragment() { private fun showSubScreen() { // 查找副屏(通常索引为1) - if (displays.size > 1) { - dismissSubScreen() - presentation = FacePayPresentation( - activity = payActivity, - display = displays[1], - userViewModel = payActivity.userViewModel, - recognizeViewModel = payActivity.recognizeViewModel, -// parentTextureView = binding.parentTextureView, - ) { - presentation?.dismiss() - }.also { - it.foodName = foodName - it.payAmount = payAmount.format2String(2) - } - presentation?.show() +// if (displays.size > 1) { +// dismissSubScreen() +// presentation = PayPresentation( +// activity = payActivity, +// pageType = PayPresentation.FACE_PAY, +// userViewModel = payActivity.userViewModel, +// recognizeViewModel = payActivity.recognizeViewModel, +// display = displays[1] +// ) { +// presentation?.dismiss() +// }.also { +// it.foodName = foodName +// it.payAmount = payAmount.format2String(2) +// } +// presentation?.show() +// } + payActivity.presentation.let { + it.pageType = PayPresentation.FACE_PAY + it.foodName = foodName + it.payAmount = payAmount.format2String(2) + it.initView() } + } } \ No newline at end of file diff --git a/app/src/main/java/com/sw/dualscreen/activity/fragment/pay/NumberPayFragment.kt b/app/src/main/java/com/sw/dualscreen/activity/fragment/pay/NumberPayFragment.kt index b13c469..3dc5c6b 100644 --- a/app/src/main/java/com/sw/dualscreen/activity/fragment/pay/NumberPayFragment.kt +++ b/app/src/main/java/com/sw/dualscreen/activity/fragment/pay/NumberPayFragment.kt @@ -5,7 +5,7 @@ import com.sw.dualscreen.activity.fragment.BaseFragment import com.sw.dualscreen.databinding.FragmentNumberPayBinding import com.sw.dualscreen.ext.format2String import com.sw.dualscreen.ext.hideKeyboard -import com.sw.dualscreen.presentation.pay.CashPayPresentation +import com.sw.dualscreen.presentation.pay.PayPresentation import com.sw.plate.utils.ToastUtils class NumberPayFragment : BaseFragment() { @@ -13,7 +13,6 @@ class NumberPayFragment : BaseFragment() { private lateinit var payActivity: PayActivity private var foodName: String? = null private var payAmount: Double? = null - var presentation: CashPayPresentation? = null override fun inflateViewBinding(): FragmentNumberPayBinding { return FragmentNumberPayBinding.inflate(layoutInflater) } @@ -79,39 +78,49 @@ class NumberPayFragment : BaseFragment() { showSubScreen() } - override fun onHiddenChanged(hidden: Boolean) { - super.onHiddenChanged(hidden) - if (hidden) { - dismissSubScreen() - return - } - //showSubScreen() - } +// override fun onHiddenChanged(hidden: Boolean) { +// super.onHiddenChanged(hidden) +// if (hidden) { +// dismissSubScreen() +// return +// } +// //showSubScreen() +// } +// +// override fun onDestroy() { +// dismissSubScreen() +// super.onDestroy() +// } - override fun onDestroy() { - dismissSubScreen() - super.onDestroy() - } - - private fun dismissSubScreen() { - presentation?.let { - if (it.isShowing) { - it.dismiss() - } - } - } +// private fun dismissSubScreen() { +// presentation?.let { +// if (it.isShowing) { +// it.dismiss() +// } +// } +// } private fun showSubScreen() { // 查找副屏(通常索引为1) - if (displays.size > 1) { - dismissSubScreen() - presentation = CashPayPresentation(activity = payActivity, display = displays[1]) { - presentation?.dismiss() - }.also { - it.foodName = foodName - it.payAmount = payAmount.format2String(2) - } - presentation?.show() +// if (displays.size > 1) { +// dismissSubScreen() +// presentation = PayPresentation( +// activity = payActivity, +// pageType = PayPresentation.CASH_PAY, +// userViewModel = payActivity.userViewModel, +// recognizeViewModel = payActivity.recognizeViewModel, +// display = displays[1] +// ).also { +// it.foodName = foodName +// it.payAmount = payAmount.format2String(2) +// } +// presentation?.show() +// } + payActivity.presentation.let { + it.pageType = PayPresentation.CASH_PAY + it.foodName = foodName + it.payAmount = payAmount.format2String(2) + it.initView() } } diff --git a/app/src/main/java/com/sw/dualscreen/activity/fragment/pay/ScanQrCodePayFragment.kt b/app/src/main/java/com/sw/dualscreen/activity/fragment/pay/ScanQrCodePayFragment.kt index 3bad0af..3d9602c 100644 --- a/app/src/main/java/com/sw/dualscreen/activity/fragment/pay/ScanQrCodePayFragment.kt +++ b/app/src/main/java/com/sw/dualscreen/activity/fragment/pay/ScanQrCodePayFragment.kt @@ -8,11 +8,11 @@ import androidx.lifecycle.lifecycleScope import com.sw.dualscreen.activity.PayActivity import com.sw.dualscreen.activity.fragment.BaseFragment import com.sw.dualscreen.ext.load -import com.sw.dualscreen.presentation.pay.ScanQrCodePayPresentation import com.sw.dualscreen.utils.countDownByFlow import kotlinx.coroutines.Job import com.sw.dualscreen.databinding.FragmentScanQrcodePayBinding import com.sw.dualscreen.ext.format2String +import com.sw.dualscreen.presentation.pay.PayPresentation import com.sw.dualscreen.utils.IntervalExecutor class ScanQrCodePayFragment : BaseFragment() { @@ -25,7 +25,6 @@ class ScanQrCodePayFragment : BaseFragment() { private var foodName: String? = null private var payAmount: Double? = null private var payQrCodePic: String? = null - var presentation: ScanQrCodePayPresentation? = null private var countDownJob: Job? = null override fun inflateViewBinding(): FragmentScanQrcodePayBinding { @@ -37,7 +36,7 @@ class ScanQrCodePayFragment : BaseFragment() { payActivity.foodInfo?.let { foodName = it.foodName - payAmount = (it.specPrice?:0.0)*payActivity.eatNum + payAmount = (it.specPrice ?: 0.0) * payActivity.eatNum } binding.tvRealAmount.text = getAmountText(payAmount.format2String(2)) //不需要绑定会员id @@ -60,41 +59,48 @@ class ScanQrCodePayFragment : BaseFragment() { override fun onHiddenChanged(hidden: Boolean) { super.onHiddenChanged(hidden) - if (hidden) { - dismissSubScreen() - return - } +// if (hidden) { +//// dismissSubScreen() +// return +// } //showSubScreen() } override fun onDestroy() { - dismissSubScreen() +// dismissSubScreen() countDownJob?.cancel() // 自动取消订阅,防止内存泄漏 payTaskJob?.cancel() super.onDestroy() } private fun dismissSubScreen() { - presentation?.let { - if (it.isShowing) { - it.dismiss() - } - } +// presentation?.let { +// if (it.isShowing) { +// it.dismiss() +// } +// } } private fun showSubScreen() { - // 查找副屏(通常索引为1) - if (displays.size > 1) { - dismissSubScreen() - presentation = - ScanQrCodePayPresentation(activity = payActivity, type = 0, display = displays[1]) { - presentation?.dismiss() - }.also { - it.foodName = foodName - it.totalPrice = payAmount ?: 0.0 - it.payQrCodePic = payQrCodePic - } - presentation?.show() +// // 查找副屏(通常索引为1) +// if (displays.size > 1) { +// dismissSubScreen() +// presentation = +// ScanQrCodePayPresentation(activity = payActivity, type = 0, display = displays[1]) { +// presentation?.dismiss() +// }.also { +// it.foodName = foodName +// it.totalPrice = payAmount ?: 0.0 +// it.payQrCodePic = payQrCodePic +// } +// presentation?.show() +// } + payActivity.presentation.let { + it.pageType = PayPresentation.QR_CODE_PAY + it.foodName = foodName + it.totalPrice = payAmount ?: 0.0 + it.payQrCodePic = payQrCodePic + it.initView() } } diff --git a/app/src/main/java/com/sw/dualscreen/model/response/DataBean.kt b/app/src/main/java/com/sw/dualscreen/model/response/DataBean.kt index 8a09813..5c0e500 100644 --- a/app/src/main/java/com/sw/dualscreen/model/response/DataBean.kt +++ b/app/src/main/java/com/sw/dualscreen/model/response/DataBean.kt @@ -54,7 +54,8 @@ data class MemberInfo( //赠送余额 val rewardBalance: Double?, //积分余额 - val integralBalance: Int? + val integralBalance: Int?, + val member: Boolean ) : Parcelable data class TextBean( diff --git a/app/src/main/java/com/sw/dualscreen/presentation/pay/CashPayPresentation.kt b/app/src/main/java/com/sw/dualscreen/presentation/pay/CashPayPresentation.kt index 9670c61..ef9a76b 100644 --- a/app/src/main/java/com/sw/dualscreen/presentation/pay/CashPayPresentation.kt +++ b/app/src/main/java/com/sw/dualscreen/presentation/pay/CashPayPresentation.kt @@ -1,49 +1,49 @@ -package com.sw.dualscreen.presentation.pay - -import android.R -import android.app.Presentation -import android.os.Bundle -import android.text.Spanned -import android.text.SpannedString -import android.text.style.AbsoluteSizeSpan -import android.view.Display -import androidx.core.text.buildSpannedString -import com.sw.dualscreen.activity.PayActivity -import com.sw.dualscreen.databinding.PresentationCashPayBinding -import com.sw.dualscreen.ext.load - -class CashPayPresentation( - val activity: PayActivity, - display: Display, - private val onDismissListener: () -> Unit = {} -) : Presentation(activity, display) { - - private lateinit var binding: PresentationCashPayBinding - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - binding = PresentationCashPayBinding.inflate(layoutInflater) - setContentView(binding.root) - window?.setBackgroundDrawableResource(R.color.transparent) - initView() - } - - var foodName: String? = null - var payAmount: String? = null - private fun initView() { - binding.tvFoodName.text = foodName - binding.tvRealAmount.text = getAmountText(payAmount ?: "") - } - - private fun getAmountText(amount: String): SpannedString { - return buildSpannedString { - append("¥", AbsoluteSizeSpan(32, true), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) - append(amount, AbsoluteSizeSpan(48, true), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) - } - } - - override fun onDisplayRemoved() { - super.onDisplayRemoved() - onDismissListener() - } -} \ No newline at end of file +//package com.sw.dualscreen.presentation.pay +// +//import android.R +//import android.app.Presentation +//import android.os.Bundle +//import android.text.Spanned +//import android.text.SpannedString +//import android.text.style.AbsoluteSizeSpan +//import android.view.Display +//import androidx.core.text.buildSpannedString +//import com.sw.dualscreen.activity.PayActivity +//import com.sw.dualscreen.databinding.PresentationCashPayBinding +//import com.sw.dualscreen.ext.load +// +//class CashPayPresentation( +// val activity: PayActivity, +// display: Display, +// private val onDismissListener: () -> Unit = {} +//) : Presentation(activity, display) { +// +// private lateinit var binding: PresentationCashPayBinding +// +// override fun onCreate(savedInstanceState: Bundle?) { +// super.onCreate(savedInstanceState) +// binding = PresentationCashPayBinding.inflate(layoutInflater) +// setContentView(binding.root) +// window?.setBackgroundDrawableResource(R.color.transparent) +// initView() +// } +// +// var foodName: String? = null +// var payAmount: String? = null +// private fun initView() { +// binding.tvFoodName.text = foodName +// binding.tvRealAmount.text = getAmountText(payAmount ?: "") +// } +// +// private fun getAmountText(amount: String): SpannedString { +// return buildSpannedString { +// append("¥", AbsoluteSizeSpan(32, true), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) +// append(amount, AbsoluteSizeSpan(48, true), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) +// } +// } +// +// override fun onDisplayRemoved() { +// super.onDisplayRemoved() +// onDismissListener() +// } +//} \ No newline at end of file diff --git a/app/src/main/java/com/sw/dualscreen/presentation/pay/FacePayPresentation.kt b/app/src/main/java/com/sw/dualscreen/presentation/pay/FacePayPresentation.kt index d295c8a..681f22c 100644 --- a/app/src/main/java/com/sw/dualscreen/presentation/pay/FacePayPresentation.kt +++ b/app/src/main/java/com/sw/dualscreen/presentation/pay/FacePayPresentation.kt @@ -1,585 +1,585 @@ -package com.sw.dualscreen.presentation.pay - -import android.Manifest -import android.app.Dialog -import android.app.Presentation -import android.content.pm.PackageManager -import android.graphics.Point -import android.hardware.Camera -import android.os.Build -import android.os.Bundle -import android.text.TextUtils -import android.view.Display -import android.view.View -import android.view.ViewGroup -import android.view.ViewTreeObserver -import android.widget.FrameLayout -import android.widget.TextView -import androidx.annotation.RequiresApi -import androidx.core.content.ContextCompat -import androidx.lifecycle.Observer -import androidx.lifecycle.lifecycleScope -import com.arcsoft.face.ErrorInfo -import com.sw.dualscreen.GlobalKey -import com.sw.dualscreen.R -import com.sw.dualscreen.activity.PayActivity -import com.sw.dualscreen.databinding.PresentationFacePayBinding -import com.sw.dualscreen.ext.dp -import com.sw.dualscreen.model.response.MemberInfo -import com.sw.dualscreen.model.response.TextBean -import com.sw.dualscreen.utils.SPUtil -import com.sw.dualscreen.utils.SpannedUtils -import com.sw.dualscreen.view.CustomDialog -import com.sw.dualscreen.viewmodel.UserViewModel -import com.sw.plate.utils.ToastUtils -import com.sw.plate.utils.arcface.ConfigUtil -import com.sw.plate.utils.arcface.ErrorCodeUtil -import com.sw.plate.utils.arcface.FaceRectTransformer -import com.sw.plate.utils.arcface.FaceRectView -import com.sw.plate.utils.arcface.FaceRectView.DrawInfo -import com.sw.plate.utils.arcface.PreviewConfig -import com.sw.plate.utils.arcface.camera.CameraListener -import com.sw.plate.utils.arcface.camera.DualCameraHelper -import com.sw.plate.utils.arcface.face.constants.LivenessType -import com.sw.plate.utils.arcface.face.model.CompareResult -import com.sw.plate.utils.arcface.face.model.FacePreviewInfo -import com.sw.plate.utils.arcface.face.model.RecognizeConfiguration -import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel -import kotlinx.coroutines.launch -import timber.log.Timber - -class FacePayPresentation( - val activity: PayActivity, - display: Display, - val userViewModel: UserViewModel, - val recognizeViewModel: RecognizeViewModel, -// val //parentTextureView: TextureView, - private val onDismissListener: () -> Unit = {} -) : Presentation(activity, display), ViewTreeObserver.OnGlobalLayoutListener { - - companion object { - private const val TAG = "FacePayPresentation" - } - - private lateinit var binding: PresentationFacePayBinding - - // 虹软人脸配置 ⬇ - private var isRecognition = false - private var rgbCameraHelper: DualCameraHelper? = null - private var rgbFaceRectTransformer: FaceRectTransformer? = null - private val livenessType = LivenessType.IR - private var openRectInfoDraw = false - - private var irCameraHelper: DualCameraHelper? = null - private var irFaceRectTransformer: FaceRectTransformer? = null - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - binding = PresentationFacePayBinding.inflate(layoutInflater) - setContentView(binding.root) - window?.setBackgroundDrawableResource(android.R.color.white) - initView() - setupArcCamera() - registerDataChange() - - pauseCamera() - } - - override fun show() { - super.show() - - binding.root.postDelayed({ - resumeCamera() - }, 1500) - } - - var foodName: String? = null - var payAmount: String? = null - private fun initView() { - binding.tvFoodName.text = foodName - binding.tvRealAmount.text = SpannedUtils.getAmountText( - listOf( - TextBean(text = "¥", textSize = 32), - TextBean(text = payAmount ?: "", textSize = 48), - ) - ) -// binding.ivPreviewImage.let { -// it.outlineProvider = object : ViewOutlineProvider() { -// override fun getOutline(view: View, outline: Outline) { -// outline.setRoundRect(0, 0, view.width, view.height, 12f.dp) +//package com.sw.dualscreen.presentation.pay +// +//import android.Manifest +//import android.app.Dialog +//import android.app.Presentation +//import android.content.pm.PackageManager +//import android.graphics.Point +//import android.hardware.Camera +//import android.os.Build +//import android.os.Bundle +//import android.text.TextUtils +//import android.view.Display +//import android.view.View +//import android.view.ViewGroup +//import android.view.ViewTreeObserver +//import android.widget.FrameLayout +//import android.widget.TextView +//import androidx.annotation.RequiresApi +//import androidx.core.content.ContextCompat +//import androidx.lifecycle.Observer +//import androidx.lifecycle.lifecycleScope +//import com.arcsoft.face.ErrorInfo +//import com.sw.dualscreen.GlobalKey +//import com.sw.dualscreen.R +//import com.sw.dualscreen.activity.PayActivity +//import com.sw.dualscreen.databinding.PresentationFacePayBinding +//import com.sw.dualscreen.ext.dp +//import com.sw.dualscreen.model.response.MemberInfo +//import com.sw.dualscreen.model.response.TextBean +//import com.sw.dualscreen.utils.SPUtil +//import com.sw.dualscreen.utils.SpannedUtils +//import com.sw.dualscreen.view.CustomDialog +//import com.sw.dualscreen.viewmodel.UserViewModel +//import com.sw.plate.utils.ToastUtils +//import com.sw.plate.utils.arcface.ConfigUtil +//import com.sw.plate.utils.arcface.ErrorCodeUtil +//import com.sw.plate.utils.arcface.FaceRectTransformer +//import com.sw.plate.utils.arcface.FaceRectView +//import com.sw.plate.utils.arcface.FaceRectView.DrawInfo +//import com.sw.plate.utils.arcface.PreviewConfig +//import com.sw.plate.utils.arcface.camera.CameraListener +//import com.sw.plate.utils.arcface.camera.DualCameraHelper +//import com.sw.plate.utils.arcface.face.constants.LivenessType +//import com.sw.plate.utils.arcface.face.model.CompareResult +//import com.sw.plate.utils.arcface.face.model.FacePreviewInfo +//import com.sw.plate.utils.arcface.face.model.RecognizeConfiguration +//import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel +//import kotlinx.coroutines.launch +//import timber.log.Timber +// +//class FacePayPresentation( +// val activity: PayActivity, +// display: Display, +// val userViewModel: UserViewModel, +// val recognizeViewModel: RecognizeViewModel, +//// val //parentTextureView: TextureView, +// private val onDismissListener: () -> Unit = {} +//) : Presentation(activity, display), ViewTreeObserver.OnGlobalLayoutListener { +// +// companion object { +// private const val TAG = "FacePayPresentation" +// } +// +// private lateinit var binding: PresentationFacePayBinding +// +// // 虹软人脸配置 ⬇ +// private var isRecognition = false +// private var rgbCameraHelper: DualCameraHelper? = null +// private var rgbFaceRectTransformer: FaceRectTransformer? = null +// private val livenessType = LivenessType.IR +// private var openRectInfoDraw = false +// +// private var irCameraHelper: DualCameraHelper? = null +// private var irFaceRectTransformer: FaceRectTransformer? = null +// +// override fun onCreate(savedInstanceState: Bundle?) { +// super.onCreate(savedInstanceState) +// binding = PresentationFacePayBinding.inflate(layoutInflater) +// setContentView(binding.root) +// window?.setBackgroundDrawableResource(android.R.color.white) +// initView() +// setupArcCamera() +// registerDataChange() +// +// pauseCamera() +// } +// +// override fun show() { +// super.show() +// +// binding.root.postDelayed({ +// resumeCamera() +// }, 1500) +// } +// +// var foodName: String? = null +// var payAmount: String? = null +// private fun initView() { +// binding.tvFoodName.text = foodName +// binding.tvRealAmount.text = SpannedUtils.getAmountText( +// listOf( +// TextBean(text = "¥", textSize = 32), +// TextBean(text = payAmount ?: "", textSize = 48), +// ) +// ) +//// binding.ivPreviewImage.let { +//// it.outlineProvider = object : ViewOutlineProvider() { +//// override fun getOutline(view: View, outline: Outline) { +//// outline.setRoundRect(0, 0, view.width, view.height, 12f.dp) +//// } +//// } +//// it.clipToOutline = true +//// } +// } +// +// override fun onGlobalLayout() { +// Timber.tag(TAG).d("onGlobalLayout") +// binding.dualCameraTexturePreviewRgb.getViewTreeObserver().removeOnGlobalLayoutListener(this) +// //parentTextureView.getViewTreeObserver().removeOnGlobalLayoutListener(this) +// openCamera() +// } +// +// private fun openCamera() { +// Timber.tag(TAG).d("openCamera") +// if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != +// PackageManager.PERMISSION_GRANTED +// ) { +// ToastUtils.showToast("无摄像头权限") +// return +// } +// try { +// val cameraCount = Camera.getNumberOfCameras() +// if (cameraCount < 3) { +// ToastUtils.showToast("摄像头数量异常") +// return +// } +// recognizeViewModel.init( +// PreviewConfig( +// 2, 1, 90, 90 +// ) +// ) +// initRgbCamera() +// if (DualCameraHelper.hasDualCamera() && livenessType === LivenessType.IR) { +// initIrCamera() +// } +// } catch (e: Exception) { +// Timber.tag(TAG).e(e, "打开摄像头失败") +// } +// } +// +// /** +// * 启用虹软人脸失败 +// */ +// private fun setupArcCamera() { +// initArcViewModel() +// initArcView() +// openRectInfoDraw = true +// } +// +// private fun registerDataChange() { +// activity.lifecycleScope.launch { +// userViewModel.loadFaceResult.collect { needUpdate -> +// if (needUpdate) { +// recognizeViewModel.refreshFaceList() // } // } -// it.clipToOutline = true // } - } - - override fun onGlobalLayout() { - Timber.tag(TAG).d("onGlobalLayout") - binding.dualCameraTexturePreviewRgb.getViewTreeObserver().removeOnGlobalLayoutListener(this) - //parentTextureView.getViewTreeObserver().removeOnGlobalLayoutListener(this) - openCamera() - } - - private fun openCamera() { - Timber.tag(TAG).d("openCamera") - if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != - PackageManager.PERMISSION_GRANTED - ) { - ToastUtils.showToast("无摄像头权限") - return - } - try { - val cameraCount = Camera.getNumberOfCameras() - if (cameraCount < 3) { - ToastUtils.showToast("摄像头数量异常") - return - } - recognizeViewModel.init( - PreviewConfig( - 2, 1, 90, 90 - ) - ) - initRgbCamera() - if (DualCameraHelper.hasDualCamera() && livenessType === LivenessType.IR) { - initIrCamera() - } - } catch (e: Exception) { - Timber.tag(TAG).e(e, "打开摄像头失败") - } - } - - /** - * 启用虹软人脸失败 - */ - private fun setupArcCamera() { - initArcViewModel() - initArcView() - openRectInfoDraw = true - } - - private fun registerDataChange() { - activity.lifecycleScope.launch { - userViewModel.loadFaceResult.collect { needUpdate -> - if (needUpdate) { - recognizeViewModel.refreshFaceList() - } - } - } - } - - override fun onStop() { - rgbCameraHelper?.release() - rgbCameraHelper = null - irCameraHelper?.release() - irCameraHelper = null - recognizeViewModel.destroy() - super.onStop() - } - - fun resumeCamera() { - Timber.tag(TAG).d("resumeCamera isRecognition = $isRecognition") - isRecognition = true - if (rgbCameraHelper?.isStopped == true) { - rgbCameraHelper?.start() - } - } - - fun pauseCamera() { - Timber.tag(TAG).d("pauseCamera isRecognition = $isRecognition") - isRecognition = false - - recognizeViewModel.onPreviewFrame(ByteArray(1382400), true) - } - - private fun initArcViewModel() { - recognizeViewModel.setLiveType(livenessType) - recognizeViewModel.ftInitCode.observe(activity, Observer { ftInitCode: Int? -> - if (ftInitCode != ErrorInfo.MOK) { - val error: String? = context.getString( - R.string.specific_engine_init_failed, "ftEngine", - ftInitCode, ErrorCodeUtil.arcFaceErrorCodeToFieldName(ftInitCode!!) - ) - Timber.tag(TAG).e("ftInitCode observe = $error") - ToastUtils.showToast(error) - } - }) - recognizeViewModel.frInitCode.observe(activity, Observer { frInitCode: Int? -> - if (frInitCode != ErrorInfo.MOK) { - val error: String? = context.getString( - R.string.specific_engine_init_failed, "frEngine", - frInitCode, ErrorCodeUtil.arcFaceErrorCodeToFieldName(frInitCode!!) - ) - Timber.tag(TAG).e("frInitCode observe = $error") - ToastUtils.showToast(error) - } - }) - recognizeViewModel.flInitCode.observe(activity, Observer { flInitCode: Int? -> - if (flInitCode != ErrorInfo.MOK) { - val error: String? = context.getString( - R.string.specific_engine_init_failed, "flEngine", - flInitCode, ErrorCodeUtil.arcFaceErrorCodeToFieldName(flInitCode!!) - ) - Timber.tag(TAG).e("flInitCode observe = $error") - ToastUtils.showToast(error) - } - }) - - recognizeViewModel.recognizeConfiguration - .observe(activity, Observer { recognizeConfiguration: RecognizeConfiguration? -> - Timber.tag(TAG) - .i("recognizeConfiguration: observe = ${recognizeConfiguration.toString()}") - }) - recognizeViewModel.recognizeNotice.observe(activity, Observer { notice: String? -> - Timber.tag(TAG).i("recognizeNotice observe notice = $notice") - }) - - recognizeViewModel.recognizeUserId.observe( - activity, - Observer { compareResult: CompareResult -> - Timber.tag(TAG) - .i("recognizeUserId observe compareResult = ${compareResult.trackId}, userId = ${compareResult.faceEntity.userName}") -// recognitionTime = System.currentTimeMillis() -// recognitionWeight = lastWeight - lastFaceTrackId = compareResult.trackId - val faceEntity = compareResult.faceEntity - val userId = faceEntity.userName - if (userId == null) return@Observer - // TODO: 测试支付用户id -// userId = "1987710988425662466" - faceRecSuccess(userId) - }) - - recognizeViewModel.drawRectInfoText.observe(activity, Observer { info -> - Timber.tag(TAG).i("drawRectInfoText observe info = $info") - }) - } - - private fun initArcView() { - //在布局结束后才做初始化操作 - binding.dualCameraTexturePreviewRgb.getViewTreeObserver().addOnGlobalLayoutListener(this) - //parentTextureView.getViewTreeObserver().addOnGlobalLayoutListener(this) - recognizeViewModel.getCompareResultList().getValue() - } - - /** - * 调整View的宽高,使预览显示正常且采集框固定为 - * - * @param rgbPreview RGB预览View - * @param previewView 显示预览数据的view - * @param faceRectView 画框的view - * @param previewSize 预览大小 - * @param displayOrientation 相机旋转角度 - * @param scale 缩放比例 - * @return 调整后的LayoutParams - */ - private fun adjustPreviewViewSize( - rgbPreview: View, - previewView: View, - faceRectView: FaceRectView, - previewSize: Camera.Size, - displayOrientation: Int, - scale: Float - ): ViewGroup.LayoutParams { - val w = (600.dp * 1.5).toInt() - val h = 1068.dp - val layoutParams = FrameLayout.LayoutParams(w, h) - - previewView.setLayoutParams(layoutParams) - faceRectView.setLayoutParams(layoutParams) - return layoutParams - } - - private fun initRgbCamera() { - val cameraListener: CameraListener = object : CameraListener { - override fun onCameraOpened( - camera: Camera, - cameraId: Int, - displayOrientation: Int, - isMirror: Boolean - ) { - Timber.tag(TAG) - .d("initRgbCamera Rgb onCameraOpened: cameraId = $cameraId, displayOrientation = $displayOrientation") - activity.runOnUiThread({ - val previewSizeRgb = camera.getParameters().getPreviewSize() - val layoutParams = adjustPreviewViewSize( - binding.dualCameraTexturePreviewRgb, - binding.dualCameraTexturePreviewRgb, binding.dualCameraFaceRectView, - previewSizeRgb, displayOrientation, 0.6F - ) - - Timber.tag(TAG) - .d("initRgbCamera previewSizeRgb = ${previewSizeRgb.width}-${previewSizeRgb.height}") - Timber.tag(TAG) - .d("initRgbCamera layoutParams = ${layoutParams.width}-${layoutParams.height}") - Timber.tag(TAG).d( - "initRgbCamera isMirror = ${isMirror}, isDrawRgbRectHorizontalMirror = ${ - ConfigUtil.isDrawRgbRectHorizontalMirror( - context - ) - }, isDrawRgbRectVerticalMirror = ${ - ConfigUtil.isDrawRgbRectVerticalMirror( - context - ) - }" - ) - // 调整识别窗口位置 - rgbFaceRectTransformer = FaceRectTransformer( - previewSizeRgb.width, - previewSizeRgb.height, +// } +// +// override fun onStop() { +// rgbCameraHelper?.release() +// rgbCameraHelper = null +// irCameraHelper?.release() +// irCameraHelper = null +// recognizeViewModel.destroy() +// super.onStop() +// } +// +// fun resumeCamera() { +// Timber.tag(TAG).d("resumeCamera isRecognition = $isRecognition") +// isRecognition = true +// if (rgbCameraHelper?.isStopped == true) { +// rgbCameraHelper?.start() +// } +// } +// +// fun pauseCamera() { +// Timber.tag(TAG).d("pauseCamera isRecognition = $isRecognition") +// isRecognition = false +// +// recognizeViewModel.onPreviewFrame(ByteArray(1382400), true) +// } +// +// private fun initArcViewModel() { +// recognizeViewModel.setLiveType(livenessType) +// recognizeViewModel.ftInitCode.observe(activity, Observer { ftInitCode: Int? -> +// if (ftInitCode != ErrorInfo.MOK) { +// val error: String? = context.getString( +// R.string.specific_engine_init_failed, "ftEngine", +// ftInitCode, ErrorCodeUtil.arcFaceErrorCodeToFieldName(ftInitCode!!) +// ) +// Timber.tag(TAG).e("ftInitCode observe = $error") +// ToastUtils.showToast(error) +// } +// }) +// recognizeViewModel.frInitCode.observe(activity, Observer { frInitCode: Int? -> +// if (frInitCode != ErrorInfo.MOK) { +// val error: String? = context.getString( +// R.string.specific_engine_init_failed, "frEngine", +// frInitCode, ErrorCodeUtil.arcFaceErrorCodeToFieldName(frInitCode!!) +// ) +// Timber.tag(TAG).e("frInitCode observe = $error") +// ToastUtils.showToast(error) +// } +// }) +// recognizeViewModel.flInitCode.observe(activity, Observer { flInitCode: Int? -> +// if (flInitCode != ErrorInfo.MOK) { +// val error: String? = context.getString( +// R.string.specific_engine_init_failed, "flEngine", +// flInitCode, ErrorCodeUtil.arcFaceErrorCodeToFieldName(flInitCode!!) +// ) +// Timber.tag(TAG).e("flInitCode observe = $error") +// ToastUtils.showToast(error) +// } +// }) +// +// recognizeViewModel.recognizeConfiguration +// .observe(activity, Observer { recognizeConfiguration: RecognizeConfiguration? -> +// Timber.tag(TAG) +// .i("recognizeConfiguration: observe = ${recognizeConfiguration.toString()}") +// }) +// recognizeViewModel.recognizeNotice.observe(activity, Observer { notice: String? -> +// Timber.tag(TAG).i("recognizeNotice observe notice = $notice") +// }) +// +// recognizeViewModel.recognizeUserId.observe( +// activity, +// Observer { compareResult: CompareResult -> +// Timber.tag(TAG) +// .i("recognizeUserId observe compareResult = ${compareResult.trackId}, userId = ${compareResult.faceEntity.userName}") +//// recognitionTime = System.currentTimeMillis() +//// recognitionWeight = lastWeight +// lastFaceTrackId = compareResult.trackId +// val faceEntity = compareResult.faceEntity +// val userId = faceEntity.userName +// if (userId == null) return@Observer +// // TODO: 测试支付用户id +//// userId = "1987710988425662466" +// faceRecSuccess(userId) +// }) +// +// recognizeViewModel.drawRectInfoText.observe(activity, Observer { info -> +// Timber.tag(TAG).i("drawRectInfoText observe info = $info") +// }) +// } +// +// private fun initArcView() { +// //在布局结束后才做初始化操作 +// binding.dualCameraTexturePreviewRgb.getViewTreeObserver().addOnGlobalLayoutListener(this) +// //parentTextureView.getViewTreeObserver().addOnGlobalLayoutListener(this) +// recognizeViewModel.getCompareResultList().getValue() +// } +// +// /** +// * 调整View的宽高,使预览显示正常且采集框固定为 +// * +// * @param rgbPreview RGB预览View +// * @param previewView 显示预览数据的view +// * @param faceRectView 画框的view +// * @param previewSize 预览大小 +// * @param displayOrientation 相机旋转角度 +// * @param scale 缩放比例 +// * @return 调整后的LayoutParams +// */ +// private fun adjustPreviewViewSize( +// rgbPreview: View, +// previewView: View, +// faceRectView: FaceRectView, +// previewSize: Camera.Size, +// displayOrientation: Int, +// scale: Float +// ): ViewGroup.LayoutParams { +// val w = (600.dp * 1.5).toInt() +// val h = 1068.dp +// val layoutParams = FrameLayout.LayoutParams(w, h) +// +// previewView.setLayoutParams(layoutParams) +// faceRectView.setLayoutParams(layoutParams) +// return layoutParams +// } +// +// private fun initRgbCamera() { +// val cameraListener: CameraListener = object : CameraListener { +// override fun onCameraOpened( +// camera: Camera, +// cameraId: Int, +// displayOrientation: Int, +// isMirror: Boolean +// ) { +// Timber.tag(TAG) +// .d("initRgbCamera Rgb onCameraOpened: cameraId = $cameraId, displayOrientation = $displayOrientation") +// activity.runOnUiThread({ +// val previewSizeRgb = camera.getParameters().getPreviewSize() +// val layoutParams = adjustPreviewViewSize( +// binding.dualCameraTexturePreviewRgb, +// binding.dualCameraTexturePreviewRgb, binding.dualCameraFaceRectView, +// previewSizeRgb, displayOrientation, 0.6F +// ) +// +// Timber.tag(TAG) +// .d("initRgbCamera previewSizeRgb = ${previewSizeRgb.width}-${previewSizeRgb.height}") +// Timber.tag(TAG) +// .d("initRgbCamera layoutParams = ${layoutParams.width}-${layoutParams.height}") +// Timber.tag(TAG).d( +// "initRgbCamera isMirror = ${isMirror}, isDrawRgbRectHorizontalMirror = ${ +// ConfigUtil.isDrawRgbRectHorizontalMirror( +// context +// ) +// }, isDrawRgbRectVerticalMirror = ${ +// ConfigUtil.isDrawRgbRectVerticalMirror( +// context +// ) +// }" +// ) +// // 调整识别窗口位置 +// rgbFaceRectTransformer = FaceRectTransformer( +// previewSizeRgb.width, +// previewSizeRgb.height, +//// layoutParams.width, +//// layoutParams.height, // layoutParams.width, // layoutParams.height, - layoutParams.width, - layoutParams.height, - 90, - cameraId, - isMirror, - true, - true - ) - - recognizeViewModel.onRgbCameraOpened(camera) - recognizeViewModel.setRgbFaceRectTransformer(rgbFaceRectTransformer) - }) - } - - @RequiresApi(api = Build.VERSION_CODES.Q) - override fun onPreview(nv21: ByteArray?, camera: Camera?) { - if (!isRecognition) { - return - } - binding.dualCameraFaceRectView.clearFaceInfo() - val facePreviewInfoList: MutableList? = - recognizeViewModel.onPreviewFrame(nv21, true) - if (facePreviewInfoList != null && rgbFaceRectTransformer != null) { - drawPreviewInfo(facePreviewInfoList) - } - recognizeViewModel.clearLeftFace(facePreviewInfoList) - } - - override fun onCameraClosed() { - Timber.tag(TAG).i("initRgbCamera onCameraClosed: ") - } - - override fun onCameraError(e: java.lang.Exception) { - Timber.tag(TAG).i("initRgbCamera onCameraError: %s", e.message) - e.printStackTrace() - } - - override fun onCameraConfigurationChanged(cameraID: Int, displayOrientation: Int) { - Timber.tag(TAG) - .i("initRgbCamera onCameraConfigurationChanged: threadName = ${Thread.currentThread().name}") - if (rgbFaceRectTransformer != null) { - rgbFaceRectTransformer!!.cameraDisplayOrientation = displayOrientation - } - Timber.tag(TAG) - .i("initRgbCamera onCameraConfigurationChanged: $cameraID $displayOrientation") - } - } - val measuredWidth = binding.dualCameraTexturePreviewRgb.measuredWidth - val measuredHeight = binding.dualCameraTexturePreviewRgb.measuredHeight - Timber.tag(TAG) - .i("initRgbCamera measuredWidth=$measuredWidth,measuredHeight=$measuredHeight") - - val previewConfig: PreviewConfig = recognizeViewModel.previewConfig - rgbCameraHelper = DualCameraHelper.Builder() - .previewViewSize(Point(measuredWidth, measuredHeight)) - .rotation(activity.windowManager.defaultDisplay.rotation) - .additionalRotation(previewConfig.rgbAdditionalDisplayOrientation) // 角度 - .previewSize(recognizeViewModel.loadPreviewSize()) - .specificCameraId(previewConfig.rgbCameraId) - .isMirror(true) - .previewOn(binding.dualCameraTexturePreviewRgb) - .cameraListener(cameraListener) - .build() - rgbCameraHelper!!.setSurfaceFrameCallback { frame -> - activity.facePayFragment?.loadBitmap(frame) - } - rgbCameraHelper!!.init() -// rgbCameraHelper!!.start() - } - - /** - * 初始化红外相机,若活体检测类型是可见光活体检测或不启用活体,则不需要启用 - */ - private fun initIrCamera() { - Timber.tag(TAG).d("initIrCamera: livenessType = $livenessType") - if (livenessType === LivenessType.RGB) { - return - } - val irCameraListener: CameraListener = object : CameraListener { - override fun onCameraOpened( - camera: Camera, - cameraId: Int, - displayOrientation: Int, - isMirror: Boolean - ) { - Timber.tag(TAG) - .d("initIrCamera IR onCameraOpened: cameraId = $cameraId, displayOrientation = $displayOrientation") - val previewSizeIr = camera.getParameters().getPreviewSize() - val layoutParams = adjustPreviewViewSize( - binding.dualCameraTexturePreviewRgb, - binding.dualCameraTexturePreviewIr, binding.dualCameraFaceRectViewIr, - previewSizeIr, displayOrientation, 0.25f - ) - - irFaceRectTransformer = FaceRectTransformer( - previewSizeIr.width, previewSizeIr.height, +// 90, +// cameraId, +// isMirror, +// true, +// true +// ) +// +// recognizeViewModel.onRgbCameraOpened(camera) +// recognizeViewModel.setRgbFaceRectTransformer(rgbFaceRectTransformer) +// }) +// } +// +// @RequiresApi(api = Build.VERSION_CODES.Q) +// override fun onPreview(nv21: ByteArray?, camera: Camera?) { +// if (!isRecognition) { +// return +// } +// binding.dualCameraFaceRectView.clearFaceInfo() +// val facePreviewInfoList: MutableList? = +// recognizeViewModel.onPreviewFrame(nv21, true) +// if (facePreviewInfoList != null && rgbFaceRectTransformer != null) { +// drawPreviewInfo(facePreviewInfoList) +// } +// recognizeViewModel.clearLeftFace(facePreviewInfoList) +// } +// +// override fun onCameraClosed() { +// Timber.tag(TAG).i("initRgbCamera onCameraClosed: ") +// } +// +// override fun onCameraError(e: java.lang.Exception) { +// Timber.tag(TAG).i("initRgbCamera onCameraError: %s", e.message) +// e.printStackTrace() +// } +// +// override fun onCameraConfigurationChanged(cameraID: Int, displayOrientation: Int) { +// Timber.tag(TAG) +// .i("initRgbCamera onCameraConfigurationChanged: threadName = ${Thread.currentThread().name}") +// if (rgbFaceRectTransformer != null) { +// rgbFaceRectTransformer!!.cameraDisplayOrientation = displayOrientation +// } +// Timber.tag(TAG) +// .i("initRgbCamera onCameraConfigurationChanged: $cameraID $displayOrientation") +// } +// } +// val measuredWidth = binding.dualCameraTexturePreviewRgb.measuredWidth +// val measuredHeight = binding.dualCameraTexturePreviewRgb.measuredHeight +// Timber.tag(TAG) +// .i("initRgbCamera measuredWidth=$measuredWidth,measuredHeight=$measuredHeight") +// +// val previewConfig: PreviewConfig = recognizeViewModel.previewConfig +// rgbCameraHelper = DualCameraHelper.Builder() +// .previewViewSize(Point(measuredWidth, measuredHeight)) +// .rotation(activity.windowManager.defaultDisplay.rotation) +// .additionalRotation(previewConfig.rgbAdditionalDisplayOrientation) // 角度 +// .previewSize(recognizeViewModel.loadPreviewSize()) +// .specificCameraId(previewConfig.rgbCameraId) +// .isMirror(true) +// .previewOn(binding.dualCameraTexturePreviewRgb) +// .cameraListener(cameraListener) +// .build() +// rgbCameraHelper!!.setSurfaceFrameCallback { frame -> +// activity.facePayFragment?.loadBitmap(frame) +// } +// rgbCameraHelper!!.init() +//// rgbCameraHelper!!.start() +// } +// +// /** +// * 初始化红外相机,若活体检测类型是可见光活体检测或不启用活体,则不需要启用 +// */ +// private fun initIrCamera() { +// Timber.tag(TAG).d("initIrCamera: livenessType = $livenessType") +// if (livenessType === LivenessType.RGB) { +// return +// } +// val irCameraListener: CameraListener = object : CameraListener { +// override fun onCameraOpened( +// camera: Camera, +// cameraId: Int, +// displayOrientation: Int, +// isMirror: Boolean +// ) { +// Timber.tag(TAG) +// .d("initIrCamera IR onCameraOpened: cameraId = $cameraId, displayOrientation = $displayOrientation") +// val previewSizeIr = camera.getParameters().getPreviewSize() +// val layoutParams = adjustPreviewViewSize( +// binding.dualCameraTexturePreviewRgb, +// binding.dualCameraTexturePreviewIr, binding.dualCameraFaceRectViewIr, +// previewSizeIr, displayOrientation, 0.25f +// ) +// +// irFaceRectTransformer = FaceRectTransformer( +// previewSizeIr.width, previewSizeIr.height, +//// layoutParams.width, layoutParams.height, // layoutParams.width, layoutParams.height, - layoutParams.width, layoutParams.height, - displayOrientation, cameraId, isMirror, - ConfigUtil.isDrawIrRectHorizontalMirror(context), - ConfigUtil.isDrawIrRectVerticalMirror(context) - ) - - recognizeViewModel.onIrCameraOpened(camera) - recognizeViewModel.setIrFaceRectTransformer(irFaceRectTransformer) - } - - - override fun onPreview(nv21: ByteArray?, camera: Camera?) { - recognizeViewModel.refreshIrPreviewData(nv21) - } - - override fun onCameraClosed() { - Timber.tag(TAG).i("initIrCamera onCameraClosed: ") - } - - override fun onCameraError(e: java.lang.Exception) { - Timber.tag(TAG).i("initIrCamera onCameraError: ${e.message}") - e.printStackTrace() - } - - override fun onCameraConfigurationChanged( - cameraID: Int, - displayOrientation: Int - ) { - if (irFaceRectTransformer != null) { - irFaceRectTransformer!!.cameraDisplayOrientation = displayOrientation - } - Timber.tag(TAG) - .i("initIrCamera onCameraConfigurationChanged: cameraID = $cameraID, displayOrientation = $displayOrientation") - } - } - - val previewConfig = recognizeViewModel.previewConfig - irCameraHelper = DualCameraHelper.Builder() - .previewViewSize( - Point( - binding.dualCameraTexturePreviewIr.measuredWidth, - binding.dualCameraTexturePreviewIr.measuredHeight - ) - ) - .rotation(activity.windowManager.defaultDisplay.rotation) - .specificCameraId(previewConfig.irCameraId) - .previewOn(binding.dualCameraTexturePreviewIr) - .cameraListener(irCameraListener) - .isMirror(true) - .previewSize(recognizeViewModel.loadPreviewSize()) //相机预览大小设置,RGB与IR需使用相同大小 - .additionalRotation(previewConfig.irAdditionalDisplayOrientation) //额外旋转角度 - .build() - irCameraHelper!!.init() - try { - irCameraHelper!!.start() - } catch (e: RuntimeException) { - ToastUtils.showToast(e.message + context.getString(R.string.camera_error_notice)) - } - } - - /** - * 绘制RGB、IR画面的实时人脸信息 - * - * @param facePreviewInfoList RGB画面的实时人脸信息 - */ - private fun drawPreviewInfo(facePreviewInfoList: MutableList) { -// Timber.tag(TAG).d("drawPreviewInfo facePreviewInfoList = ${facePreviewInfoList.size}, rgbFaceRectTransformer = ${rgbFaceRectTransformer != null}") - if (rgbFaceRectTransformer != null) { - val rgbDrawInfoList: MutableList? = recognizeViewModel.getDrawInfo( - facePreviewInfoList, - LivenessType.RGB, - openRectInfoDraw - ) - // 识别成功 - binding.dualCameraFaceRectView.drawRealtimeFaceInfo(rgbDrawInfoList) - } - - if (facePreviewInfoList.isEmpty() || (lastFaceTrackId != facePreviewInfoList[0]!!.trackId)) { - if (lastFaceTrackId != -1) { - // mealPickupMode = SPUtil.getInstance().get(GlobalKey.KEY_PICKUP_MODE, 0) ?: 0 - // Timber.tag(TAG).i("$lastFaceTrackId 用户离开") - // lastFaceTrackId = -1 - // postUserData() - // if (mealPickupMode == 0) { - // step1FoodRecognizing() - // } else { - // step2FaceRecognizing(currentFood!!) - // } - - resumeCamera() - } - } - } - - private var lastFaceTrackId: Int = -1 // 上一次的人脸信息 - - override fun onDisplayRemoved() { - super.onDisplayRemoved() - onDismissListener() - } - - - private fun faceRecSuccess(userId: String) { - activity.runOnUiThread { - activity.showWaitingDialog("加载中,请稍后……") - } - activity.getMemberInfoById(userId) { memberInfo -> - if (memberInfo == null) { - activity.hideWaitingDialog() - //ToastUtils.showToast("查询会员信息失败,请稍后重试") - return@getMemberInfoById - } - activity.bindOrder(memberInfo.faceUserId?:"") { bindResult -> - if (bindResult.not()) { - activity.hideWaitingDialog() - //ToastUtils.showToast("订单绑定失败") - return@bindOrder - } - binding.root.postDelayed({ - activity.hideWaitingDialog() - activity.showPayInfo(type = 1, isVip = true, memberInfo = memberInfo) - activity.hidePayTab() - binding.root.postDelayed({ - dismiss() - }, 500) - }, 1000) - } - } - } - -// private fun bindOrder(userId: String, block: () -> Unit) { -// val pickupMode = SPUtil.getInstance().get(GlobalKey.KEY_PICKUP_MODE, 0) -// val mode = if (pickupMode == 1) 1 else 2 -// userViewModel.bindOrder(userId, activity.foodOrderId, mode = mode) { bindResult -> -// activity.runOnUiThread { +// displayOrientation, cameraId, isMirror, +// ConfigUtil.isDrawIrRectHorizontalMirror(context), +// ConfigUtil.isDrawIrRectVerticalMirror(context) +// ) +// +// recognizeViewModel.onIrCameraOpened(camera) +// recognizeViewModel.setIrFaceRectTransformer(irFaceRectTransformer) +// } +// +// +// override fun onPreview(nv21: ByteArray?, camera: Camera?) { +// recognizeViewModel.refreshIrPreviewData(nv21) +// } +// +// override fun onCameraClosed() { +// Timber.tag(TAG).i("initIrCamera onCameraClosed: ") +// } +// +// override fun onCameraError(e: java.lang.Exception) { +// Timber.tag(TAG).i("initIrCamera onCameraError: ${e.message}") +// e.printStackTrace() +// } +// +// override fun onCameraConfigurationChanged( +// cameraID: Int, +// displayOrientation: Int +// ) { +// if (irFaceRectTransformer != null) { +// irFaceRectTransformer!!.cameraDisplayOrientation = displayOrientation +// } +// Timber.tag(TAG) +// .i("initIrCamera onCameraConfigurationChanged: cameraID = $cameraID, displayOrientation = $displayOrientation") +// } +// } +// +// val previewConfig = recognizeViewModel.previewConfig +// irCameraHelper = DualCameraHelper.Builder() +// .previewViewSize( +// Point( +// binding.dualCameraTexturePreviewIr.measuredWidth, +// binding.dualCameraTexturePreviewIr.measuredHeight +// ) +// ) +// .rotation(activity.windowManager.defaultDisplay.rotation) +// .specificCameraId(previewConfig.irCameraId) +// .previewOn(binding.dualCameraTexturePreviewIr) +// .cameraListener(irCameraListener) +// .isMirror(true) +// .previewSize(recognizeViewModel.loadPreviewSize()) //相机预览大小设置,RGB与IR需使用相同大小 +// .additionalRotation(previewConfig.irAdditionalDisplayOrientation) //额外旋转角度 +// .build() +// irCameraHelper!!.init() +// try { +// irCameraHelper!!.start() +// } catch (e: RuntimeException) { +// ToastUtils.showToast(e.message + context.getString(R.string.camera_error_notice)) +// } +// } +// +// /** +// * 绘制RGB、IR画面的实时人脸信息 +// * +// * @param facePreviewInfoList RGB画面的实时人脸信息 +// */ +// private fun drawPreviewInfo(facePreviewInfoList: MutableList) { +//// Timber.tag(TAG).d("drawPreviewInfo facePreviewInfoList = ${facePreviewInfoList.size}, rgbFaceRectTransformer = ${rgbFaceRectTransformer != null}") +// if (rgbFaceRectTransformer != null) { +// val rgbDrawInfoList: MutableList? = recognizeViewModel.getDrawInfo( +// facePreviewInfoList, +// LivenessType.RGB, +// openRectInfoDraw +// ) +// // 识别成功 +// binding.dualCameraFaceRectView.drawRealtimeFaceInfo(rgbDrawInfoList) +// } +// +// if (facePreviewInfoList.isEmpty() || (lastFaceTrackId != facePreviewInfoList[0]!!.trackId)) { +// if (lastFaceTrackId != -1) { +// // mealPickupMode = SPUtil.getInstance().get(GlobalKey.KEY_PICKUP_MODE, 0) ?: 0 +// // Timber.tag(TAG).i("$lastFaceTrackId 用户离开") +// // lastFaceTrackId = -1 +// // postUserData() +// // if (mealPickupMode == 0) { +// // step1FoodRecognizing() +// // } else { +// // step2FaceRecognizing(currentFood!!) +// // } +// +// resumeCamera() +// } +// } +// } +// +// private var lastFaceTrackId: Int = -1 // 上一次的人脸信息 +// +// override fun onDisplayRemoved() { +// super.onDisplayRemoved() +// onDismissListener() +// } +// +// +// private fun faceRecSuccess(userId: String) { +// activity.runOnUiThread { +// activity.showWaitingDialog("加载中,请稍后……") +// } +// activity.getMemberInfoById(userId) { memberInfo -> +// if (memberInfo == null) { +// activity.hideWaitingDialog() +// //ToastUtils.showToast("查询会员信息失败,请稍后重试") +// return@getMemberInfoById +// } +// activity.bindOrder(memberInfo.faceUserId?:"") { bindResult -> // if (bindResult.not()) { // activity.hideWaitingDialog() // //ToastUtils.showToast("订单绑定失败") -// return@runOnUiThread +// return@bindOrder // } -// block() -// } -// } -// } -// private fun getMemberInfo(userId: String, block:(MemberInfo)-> Unit) { -// userViewModel.getMemberInfoById(memberId = userId) { memberInfo -> -// activity.runOnUiThread { -// if (memberInfo == null) { +// binding.root.postDelayed({ // activity.hideWaitingDialog() -// //ToastUtils.showToast("查询会员信息失败,请稍后重试") -// return@runOnUiThread -// } -// block(memberInfo) +// activity.showPayInfo(type = 1, isVip = true, memberInfo = memberInfo) +// activity.hidePayTab() +// binding.root.postDelayed({ +// dismiss() +// }, 500) +// }, 1000) // } // } // } - -} \ No newline at end of file +// +//// private fun bindOrder(userId: String, block: () -> Unit) { +//// val pickupMode = SPUtil.getInstance().get(GlobalKey.KEY_PICKUP_MODE, 0) +//// val mode = if (pickupMode == 1) 1 else 2 +//// userViewModel.bindOrder(userId, activity.foodOrderId, mode = mode) { bindResult -> +//// activity.runOnUiThread { +//// if (bindResult.not()) { +//// activity.hideWaitingDialog() +//// //ToastUtils.showToast("订单绑定失败") +//// return@runOnUiThread +//// } +//// block() +//// } +//// } +//// } +//// private fun getMemberInfo(userId: String, block:(MemberInfo)-> Unit) { +//// userViewModel.getMemberInfoById(memberId = userId) { memberInfo -> +//// activity.runOnUiThread { +//// if (memberInfo == null) { +//// activity.hideWaitingDialog() +//// //ToastUtils.showToast("查询会员信息失败,请稍后重试") +//// return@runOnUiThread +//// } +//// block(memberInfo) +//// } +//// } +//// } +// +//} \ No newline at end of file diff --git a/app/src/main/java/com/sw/dualscreen/presentation/pay/PayPresentation.kt b/app/src/main/java/com/sw/dualscreen/presentation/pay/PayPresentation.kt new file mode 100644 index 0000000..2392289 --- /dev/null +++ b/app/src/main/java/com/sw/dualscreen/presentation/pay/PayPresentation.kt @@ -0,0 +1,804 @@ +package com.sw.dualscreen.presentation.pay + +import android.Manifest +import android.annotation.SuppressLint +import android.app.Dialog +import android.app.Presentation +import android.content.pm.PackageManager +import android.graphics.Point +import android.hardware.Camera +import android.os.Build +import android.os.Bundle +import android.text.Spanned +import android.text.SpannedString +import android.text.TextUtils +import android.text.style.AbsoluteSizeSpan +import android.view.Display +import android.view.View +import android.view.ViewGroup +import android.view.ViewTreeObserver +import android.widget.FrameLayout +import android.widget.TextView +import androidx.annotation.RequiresApi +import androidx.core.content.ContextCompat +import androidx.core.text.buildSpannedString +import androidx.lifecycle.Observer +import androidx.lifecycle.lifecycleScope +import com.arcsoft.face.ErrorInfo +import com.sw.dualscreen.GlobalKey +import com.sw.dualscreen.R +import com.sw.dualscreen.activity.PayActivity +import com.sw.dualscreen.databinding.PresentationFacePayBinding +import com.sw.dualscreen.databinding.PresentationPayBinding +import com.sw.dualscreen.ext.dp +import com.sw.dualscreen.ext.format2String +import com.sw.dualscreen.ext.gone +import com.sw.dualscreen.ext.invisible +import com.sw.dualscreen.ext.load +import com.sw.dualscreen.ext.visible +import com.sw.dualscreen.model.response.MemberInfo +import com.sw.dualscreen.model.response.TextBean +import com.sw.dualscreen.utils.SPUtil +import com.sw.dualscreen.utils.SpannedUtils +import com.sw.dualscreen.view.CustomDialog +import com.sw.dualscreen.viewmodel.UserViewModel +import com.sw.plate.utils.ToastUtils +import com.sw.plate.utils.arcface.ConfigUtil +import com.sw.plate.utils.arcface.ErrorCodeUtil +import com.sw.plate.utils.arcface.FaceRectTransformer +import com.sw.plate.utils.arcface.FaceRectView +import com.sw.plate.utils.arcface.FaceRectView.DrawInfo +import com.sw.plate.utils.arcface.PreviewConfig +import com.sw.plate.utils.arcface.camera.CameraListener +import com.sw.plate.utils.arcface.camera.DualCameraHelper +import com.sw.plate.utils.arcface.face.constants.LivenessType +import com.sw.plate.utils.arcface.face.model.CompareResult +import com.sw.plate.utils.arcface.face.model.FacePreviewInfo +import com.sw.plate.utils.arcface.face.model.RecognizeConfiguration +import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel +import kotlinx.coroutines.launch +import timber.log.Timber + +class PayPresentation( + val activity: PayActivity, + display: Display, + val userViewModel: UserViewModel, + val recognizeViewModel: RecognizeViewModel, + private val onDismissListener: () -> Unit = {} +) : Presentation(activity, display), ViewTreeObserver.OnGlobalLayoutListener { + + companion object { + private const val TAG = "PayPresentation" + const val CASH_PAY = 100 + const val FACE_PAY = 200 + const val QR_CODE_PAY = 300 + } + + private lateinit var binding: PresentationPayBinding + + // 虹软人脸配置 ⬇ + private var isRecognition = false + private var rgbCameraHelper: DualCameraHelper? = null + private var rgbFaceRectTransformer: FaceRectTransformer? = null + private val livenessType = LivenessType.IR + private var openRectInfoDraw = false + + private var irCameraHelper: DualCameraHelper? = null + private var irFaceRectTransformer: FaceRectTransformer? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = PresentationPayBinding.inflate(layoutInflater) + setContentView(binding.root) + window?.setBackgroundDrawableResource(android.R.color.white) + + setupArcCamera() + registerDataChange() + initView() + } + + override fun show() { + super.show() + pauseCamera() + } + + var pageType: Int = 0 + var type: Int = 0 + +// fun updatePage(pageType:Int, type:Int = -1) { +// this.pageType == pageType +// this.type = type +// if (pageType == PayPresentation.CASH_PAY) { +// +// return +// } +// if (pageType == PayPresentation.FACE_PAY) { +// +// return +// } +// if (pageType == PayPresentation.QR_CODE_PAY) { +// +// return +// } +// } + + var foodName: String? = null + var payAmount: String? = null + fun initView() { + when (pageType) { + FACE_PAY -> { + //人脸识别 + binding.flCashPay.gone() + binding.flQrCodePay.gone() + binding.flFacePay.visible() + + binding.tvFoodName.text = foodName + binding.tvRealAmount.text = SpannedUtils.getAmountText( + listOf( + TextBean(text = "¥", textSize = 32), + TextBean(text = payAmount ?: "", textSize = 48), + ) + ) + + //pauseCamera() + resumeCamera() +// binding.root.postDelayed({ +// resumeCamera() +// }, 1000) + } + + QR_CODE_PAY -> { + //二维码 + binding.flCashPay.gone() + binding.flQrCodePay.visible() + binding.flFacePay.gone() + initQrCodeView() + } + + CASH_PAY -> { + binding.flCashPay.visible() + binding.flQrCodePay.gone() + binding.flFacePay.gone() + binding.tvFoodName2.text = foodName + binding.tvRealAmount2.text = getAmountText(payAmount ?: "") + } + } + } + + private fun getAmountText(amount: String): SpannedString { + return buildSpannedString { + append("¥", AbsoluteSizeSpan(32, true), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) + append(amount, AbsoluteSizeSpan(48, true), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) + } + } + + override fun onGlobalLayout() { + Timber.tag(TAG).d("onGlobalLayout") + binding.dualCameraTexturePreviewRgb.getViewTreeObserver().removeOnGlobalLayoutListener(this) + //parentTextureView.getViewTreeObserver().removeOnGlobalLayoutListener(this) + openCamera() + } + + private fun openCamera() { + Timber.tag(TAG).d("openCamera") + if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != + PackageManager.PERMISSION_GRANTED + ) { + ToastUtils.showToast("无摄像头权限") + return + } + try { + val cameraCount = Camera.getNumberOfCameras() + if (cameraCount < 3) { + ToastUtils.showToast("摄像头数量异常") + return + } + recognizeViewModel.init( + PreviewConfig( + 2, 1, 90, 90 + ) + ) + initRgbCamera() + if (DualCameraHelper.hasDualCamera() && livenessType === LivenessType.IR) { + initIrCamera() + } + } catch (e: Exception) { + Timber.tag(TAG).e(e, "打开摄像头失败") + } + } + + /** + * 启用虹软人脸失败 + */ + private fun setupArcCamera() { + initArcViewModel() + initArcView() + openRectInfoDraw = true + } + + private fun registerDataChange() { + activity.lifecycleScope.launch { + userViewModel.loadFaceResult.collect { needUpdate -> + if (needUpdate) { + recognizeViewModel.refreshFaceList() + } + } + } + } + + override fun onStop() { + rgbCameraHelper?.release() + rgbCameraHelper = null + irCameraHelper?.release() + irCameraHelper = null + recognizeViewModel.destroy() + super.onStop() + } + + fun resumeCamera() { + Timber.tag(TAG).d("resumeCamera isRecognition = $isRecognition") + isRecognition = true + if (rgbCameraHelper?.isStopped == true) { + rgbCameraHelper?.start() + } + } + + fun pauseCamera() { + Timber.tag(TAG).d("pauseCamera isRecognition = $isRecognition") + isRecognition = false + + recognizeViewModel.onPreviewFrame(ByteArray(1382400), true) + } + + private fun initArcViewModel() { + recognizeViewModel.setLiveType(livenessType) + recognizeViewModel.ftInitCode.observe(activity, Observer { ftInitCode: Int? -> + if (ftInitCode != ErrorInfo.MOK) { + val error: String? = context.getString( + R.string.specific_engine_init_failed, "ftEngine", + ftInitCode, ErrorCodeUtil.arcFaceErrorCodeToFieldName(ftInitCode!!) + ) + Timber.tag(TAG).e("ftInitCode observe = $error") + ToastUtils.showToast(error) + } + }) + recognizeViewModel.frInitCode.observe(activity, Observer { frInitCode: Int? -> + if (frInitCode != ErrorInfo.MOK) { + val error: String? = context.getString( + R.string.specific_engine_init_failed, "frEngine", + frInitCode, ErrorCodeUtil.arcFaceErrorCodeToFieldName(frInitCode!!) + ) + Timber.tag(TAG).e("frInitCode observe = $error") + ToastUtils.showToast(error) + } + }) + recognizeViewModel.flInitCode.observe(activity, Observer { flInitCode: Int? -> + if (flInitCode != ErrorInfo.MOK) { + val error: String? = context.getString( + R.string.specific_engine_init_failed, "flEngine", + flInitCode, ErrorCodeUtil.arcFaceErrorCodeToFieldName(flInitCode!!) + ) + Timber.tag(TAG).e("flInitCode observe = $error") + ToastUtils.showToast(error) + } + }) + + recognizeViewModel.recognizeConfiguration + .observe(activity, Observer { recognizeConfiguration: RecognizeConfiguration? -> + Timber.tag(TAG) + .i("recognizeConfiguration: observe = ${recognizeConfiguration.toString()}") + }) + recognizeViewModel.recognizeNotice.observe(activity, Observer { notice: String? -> + Timber.tag(TAG).i("recognizeNotice observe notice = $notice") + }) + + recognizeViewModel.recognizeUserId.observe( + activity, + Observer { compareResult: CompareResult -> + Timber.tag(TAG) + .i("recognizeUserId observe compareResult = ${compareResult.trackId}, userId = ${compareResult.faceEntity.userName}") +// recognitionTime = System.currentTimeMillis() +// recognitionWeight = lastWeight + lastFaceTrackId = compareResult.trackId + val faceEntity = compareResult.faceEntity + val userId = faceEntity.userName + if (userId == null) return@Observer + // TODO: 测试支付用户id +// userId = "1987710988425662466" + faceRecSuccess(userId) + }) + + recognizeViewModel.drawRectInfoText.observe(activity, Observer { info -> + Timber.tag(TAG).i("drawRectInfoText observe info = $info") + }) + } + + private fun initArcView() { + //在布局结束后才做初始化操作 + binding.dualCameraTexturePreviewRgb.getViewTreeObserver().addOnGlobalLayoutListener(this) + //parentTextureView.getViewTreeObserver().addOnGlobalLayoutListener(this) + recognizeViewModel.getCompareResultList().getValue() + } + + /** + * 调整View的宽高,使预览显示正常且采集框固定为 + * + * @param rgbPreview RGB预览View + * @param previewView 显示预览数据的view + * @param faceRectView 画框的view + * @param previewSize 预览大小 + * @param displayOrientation 相机旋转角度 + * @param scale 缩放比例 + * @return 调整后的LayoutParams + */ + private fun adjustPreviewViewSize( + rgbPreview: View, + previewView: View, + faceRectView: FaceRectView, + previewSize: Camera.Size, + displayOrientation: Int, + scale: Float + ): ViewGroup.LayoutParams { + val w = (600.dp * 1.5).toInt() + val h = 1068.dp + val layoutParams = FrameLayout.LayoutParams(w, h) + + previewView.setLayoutParams(layoutParams) + faceRectView.setLayoutParams(layoutParams) + return layoutParams + } + + private fun initRgbCamera() { + val cameraListener: CameraListener = object : CameraListener { + override fun onCameraOpened( + camera: Camera, + cameraId: Int, + displayOrientation: Int, + isMirror: Boolean + ) { + Timber.tag(TAG) + .d("initRgbCamera Rgb onCameraOpened: cameraId = $cameraId, displayOrientation = $displayOrientation") + activity.runOnUiThread({ + val previewSizeRgb = camera.getParameters().getPreviewSize() + val layoutParams = adjustPreviewViewSize( + binding.dualCameraTexturePreviewRgb, + binding.dualCameraTexturePreviewRgb, binding.dualCameraFaceRectView, + previewSizeRgb, displayOrientation, 0.6F + ) + + Timber.tag(TAG) + .d("initRgbCamera previewSizeRgb = ${previewSizeRgb.width}-${previewSizeRgb.height}") + Timber.tag(TAG) + .d("initRgbCamera layoutParams = ${layoutParams.width}-${layoutParams.height}") + Timber.tag(TAG).d( + "initRgbCamera isMirror = ${isMirror}, isDrawRgbRectHorizontalMirror = ${ + ConfigUtil.isDrawRgbRectHorizontalMirror( + context + ) + }, isDrawRgbRectVerticalMirror = ${ + ConfigUtil.isDrawRgbRectVerticalMirror( + context + ) + }" + ) + // 调整识别窗口位置 + rgbFaceRectTransformer = FaceRectTransformer( + previewSizeRgb.width, + previewSizeRgb.height, +// layoutParams.width, +// layoutParams.height, + layoutParams.width, + layoutParams.height, + 90, + cameraId, + isMirror, + true, + true + ) + + recognizeViewModel.onRgbCameraOpened(camera) + recognizeViewModel.setRgbFaceRectTransformer(rgbFaceRectTransformer) + }) + } + + @RequiresApi(api = Build.VERSION_CODES.Q) + override fun onPreview(nv21: ByteArray?, camera: Camera?) { + if (!isRecognition) { + return + } + binding.dualCameraFaceRectView.clearFaceInfo() + val facePreviewInfoList: MutableList? = + recognizeViewModel.onPreviewFrame(nv21, true) + if (facePreviewInfoList != null && rgbFaceRectTransformer != null) { + drawPreviewInfo(facePreviewInfoList) + } + recognizeViewModel.clearLeftFace(facePreviewInfoList) + } + + override fun onCameraClosed() { + Timber.tag(TAG).i("initRgbCamera onCameraClosed: ") + } + + override fun onCameraError(e: java.lang.Exception) { + Timber.tag(TAG).i("initRgbCamera onCameraError: %s", e.message) + e.printStackTrace() + } + + override fun onCameraConfigurationChanged(cameraID: Int, displayOrientation: Int) { + Timber.tag(TAG) + .i("initRgbCamera onCameraConfigurationChanged: threadName = ${Thread.currentThread().name}") + if (rgbFaceRectTransformer != null) { + rgbFaceRectTransformer!!.cameraDisplayOrientation = displayOrientation + } + Timber.tag(TAG) + .i("initRgbCamera onCameraConfigurationChanged: $cameraID $displayOrientation") + } + } + val measuredWidth = binding.dualCameraTexturePreviewRgb.measuredWidth + val measuredHeight = binding.dualCameraTexturePreviewRgb.measuredHeight + Timber.tag(TAG) + .i("initRgbCamera measuredWidth=$measuredWidth,measuredHeight=$measuredHeight") + + val previewConfig: PreviewConfig = recognizeViewModel.previewConfig + rgbCameraHelper = DualCameraHelper.Builder() + .previewViewSize(Point(measuredWidth, measuredHeight)) + .rotation(activity.windowManager.defaultDisplay.rotation) + .additionalRotation(previewConfig.rgbAdditionalDisplayOrientation) // 角度 + .previewSize(recognizeViewModel.loadPreviewSize()) + .specificCameraId(previewConfig.rgbCameraId) + .isMirror(true) + .previewOn(binding.dualCameraTexturePreviewRgb) + .cameraListener(cameraListener) + .build() + rgbCameraHelper!!.setSurfaceFrameCallback { frame -> + activity.facePayFragment?.loadBitmap(frame) + } + rgbCameraHelper!!.init() +// rgbCameraHelper!!.start() + } + + /** + * 初始化红外相机,若活体检测类型是可见光活体检测或不启用活体,则不需要启用 + */ + private fun initIrCamera() { + Timber.tag(TAG).d("initIrCamera: livenessType = $livenessType") + if (livenessType === LivenessType.RGB) { + return + } + val irCameraListener: CameraListener = object : CameraListener { + override fun onCameraOpened( + camera: Camera, + cameraId: Int, + displayOrientation: Int, + isMirror: Boolean + ) { + Timber.tag(TAG) + .d("initIrCamera IR onCameraOpened: cameraId = $cameraId, displayOrientation = $displayOrientation") + val previewSizeIr = camera.getParameters().getPreviewSize() + val layoutParams = adjustPreviewViewSize( + binding.dualCameraTexturePreviewRgb, + binding.dualCameraTexturePreviewIr, binding.dualCameraFaceRectViewIr, + previewSizeIr, displayOrientation, 0.25f + ) + + irFaceRectTransformer = FaceRectTransformer( + previewSizeIr.width, previewSizeIr.height, +// layoutParams.width, layoutParams.height, + layoutParams.width, layoutParams.height, + displayOrientation, cameraId, isMirror, + ConfigUtil.isDrawIrRectHorizontalMirror(context), + ConfigUtil.isDrawIrRectVerticalMirror(context) + ) + + recognizeViewModel.onIrCameraOpened(camera) + recognizeViewModel.setIrFaceRectTransformer(irFaceRectTransformer) + } + + + override fun onPreview(nv21: ByteArray?, camera: Camera?) { + recognizeViewModel.refreshIrPreviewData(nv21) + } + + override fun onCameraClosed() { + Timber.tag(TAG).i("initIrCamera onCameraClosed: ") + } + + override fun onCameraError(e: java.lang.Exception) { + Timber.tag(TAG).i("initIrCamera onCameraError: ${e.message}") + e.printStackTrace() + } + + override fun onCameraConfigurationChanged( + cameraID: Int, + displayOrientation: Int + ) { + if (irFaceRectTransformer != null) { + irFaceRectTransformer!!.cameraDisplayOrientation = displayOrientation + } + Timber.tag(TAG) + .i("initIrCamera onCameraConfigurationChanged: cameraID = $cameraID, displayOrientation = $displayOrientation") + } + } + + val previewConfig = recognizeViewModel.previewConfig + irCameraHelper = DualCameraHelper.Builder() + .previewViewSize( + Point( + binding.dualCameraTexturePreviewIr.measuredWidth, + binding.dualCameraTexturePreviewIr.measuredHeight + ) + ) + .rotation(activity.windowManager.defaultDisplay.rotation) + .specificCameraId(previewConfig.irCameraId) + .previewOn(binding.dualCameraTexturePreviewIr) + .cameraListener(irCameraListener) + .isMirror(true) + .previewSize(recognizeViewModel.loadPreviewSize()) //相机预览大小设置,RGB与IR需使用相同大小 + .additionalRotation(previewConfig.irAdditionalDisplayOrientation) //额外旋转角度 + .build() + irCameraHelper!!.init() + try { + irCameraHelper!!.start() + } catch (e: RuntimeException) { + ToastUtils.showToast(e.message + context.getString(R.string.camera_error_notice)) + } + } + + /** + * 绘制RGB、IR画面的实时人脸信息 + * + * @param facePreviewInfoList RGB画面的实时人脸信息 + */ + private fun drawPreviewInfo(facePreviewInfoList: MutableList) { +// Timber.tag(TAG).d("drawPreviewInfo facePreviewInfoList = ${facePreviewInfoList.size}, rgbFaceRectTransformer = ${rgbFaceRectTransformer != null}") + if (rgbFaceRectTransformer != null) { + val rgbDrawInfoList: MutableList? = recognizeViewModel.getDrawInfo( + facePreviewInfoList, + LivenessType.RGB, + openRectInfoDraw + ) + // 识别成功 + binding.dualCameraFaceRectView.drawRealtimeFaceInfo(rgbDrawInfoList) + } + + if (facePreviewInfoList.isEmpty() || (lastFaceTrackId != facePreviewInfoList[0]!!.trackId)) { + if (lastFaceTrackId != -1) { + // mealPickupMode = SPUtil.getInstance().get(GlobalKey.KEY_PICKUP_MODE, 0) ?: 0 + // Timber.tag(TAG).i("$lastFaceTrackId 用户离开") + // lastFaceTrackId = -1 + // postUserData() + // if (mealPickupMode == 0) { + // step1FoodRecognizing() + // } else { + // step2FaceRecognizing(currentFood!!) + // } + + resumeCamera() + } + } + } + + private var lastFaceTrackId: Int = -1 // 上一次的人脸信息 + + override fun onDisplayRemoved() { + super.onDisplayRemoved() + onDismissListener() + } + + + private fun faceRecSuccess(userId: String) { + activity.runOnUiThread { + activity.showWaitingDialog("加载中,请稍后……") + } + activity.getMemberInfoById(userId) { memberInfo -> + if (memberInfo == null) { + activity.hideWaitingDialog() + //ToastUtils.showToast("查询会员信息失败,请稍后重试") + return@getMemberInfoById + } + activity.bindOrder(memberInfo.faceUserId ?: "") { bindResult -> + if (bindResult.not()) { + activity.hideWaitingDialog() + //ToastUtils.showToast("订单绑定失败") + return@bindOrder + } + binding.root.postDelayed({ + activity.hideWaitingDialog() + // TODO: 测试 memberInfo.member是否返回正常数据--------------- + activity.showPayInfo(type = 1, isVip = memberInfo.member, memberInfo = memberInfo) + activity.hidePayTab() + binding.root.postDelayed({ + dismiss() + }, 500) + }, 1000) + } + } + } + +// private fun bindOrder(userId: String, block: () -> Unit) { +// val pickupMode = SPUtil.getInstance().get(GlobalKey.KEY_PICKUP_MODE, 0) +// val mode = if (pickupMode == 1) 1 else 2 +// userViewModel.bindOrder(userId, activity.foodOrderId, mode = mode) { bindResult -> +// activity.runOnUiThread { +// if (bindResult.not()) { +// activity.hideWaitingDialog() +// //ToastUtils.showToast("订单绑定失败") +// return@runOnUiThread +// } +// block() +// } +// } +// } +// private fun getMemberInfo(userId: String, block:(MemberInfo)-> Unit) { +// userViewModel.getMemberInfoById(memberId = userId) { memberInfo -> +// activity.runOnUiThread { +// if (memberInfo == null) { +// activity.hideWaitingDialog() +// //ToastUtils.showToast("查询会员信息失败,请稍后重试") +// return@runOnUiThread +// } +// block(memberInfo) +// } +// } +// } + + + var payQrCodePic: Any? = null + + //总价格 + var totalPrice = 0.0 + + //余额 + private var balance = 0.0 + + //实际支付金额 + private var realPayPrice = 0.0 + + //扣除余额 + private var expensesBalance = 0.0 + + @SuppressLint("SetTextI18n") + private fun initQrCodeView() { + + when (type) { + 0 -> { + binding.layoutVip.gone() + binding.layoutPaySuccess.gone() + binding.layoutScanQrCode.visible() + + binding.tvPayTip.text = "请扫码支付或出示付款码" + binding.tvFoodName3.text = foodName + binding.tvRealAmount3.text = SpannedUtils.getAmountText( + listOf( + TextBean(text = "¥", textSize = 32), + TextBean(text = totalPrice.format2String(2), textSize = 48), + ) + ) + binding.ivPayQrCode.load(payQrCodePic) + } + + 1 -> { + val memberInfo = activity.memberInfo + binding.layoutVip.run { + if (memberInfo != null) visible() else gone() + } + binding.layoutPaySuccess.gone() + binding.layoutScanQrCode.visible() + + balance = (memberInfo?.topUpBalance ?: 0.0) + (memberInfo?.rewardBalance ?: 0.0) + realPayPrice = if (balance >= totalPrice) 0.0 else totalPrice - balance + expensesBalance = if (balance >= totalPrice) totalPrice else balance + + memberInfo?.let { loadUserInfo(it) } + binding.tvUserBalance.text = SpannedUtils.getAmountText( + listOf( + TextBean(text = "¥", textSize = 20), + TextBean(text = balance.format2String(2), textSize = 32), + ) + ) + + binding.tvFoodName3.text = foodName + binding.tvRealAmount3.text = SpannedUtils.getAmountText( + listOf( + TextBean(text = "¥", textSize = 32), + TextBean(text = totalPrice.format2String(2), textSize = 48), + ) + ) + binding.ivPayQrCode.run { +// load(payQrCodePic) + if (balance >= totalPrice) invisible() else visible() + } + + binding.tvPayTip.text = SpannedUtils.getAmountText(getAmountList()) + } + + 2 -> { + val memberInfo = activity.memberInfo + binding.layoutVip.run { + if (memberInfo != null) visible() else gone() + } + binding.layoutPaySuccess.visible() + binding.layoutScanQrCode.gone() + + balance = if (memberInfo != null) (memberInfo.topUpBalance + ?: 0.0) + (memberInfo.rewardBalance ?: 0.0) else 0.0 + realPayPrice = if (balance >= totalPrice) 0.0 else totalPrice - balance + expensesBalance = if (balance >= totalPrice) totalPrice else balance + + memberInfo?.let { loadUserInfo(it) } + val remainBalance = if (balance >= totalPrice) balance - totalPrice else 0.0 + binding.tvUserBalance.text = SpannedUtils.getAmountText( + listOf( + TextBean(text = "¥", textSize = 24), + TextBean(text = remainBalance.format2String(2), textSize = 36), + ) + ) + + val showBalance = expensesBalance.format2String(2) + val showTotal = totalPrice.format2String(2) + binding.tvPayInfo.text = "余额扣除 $showBalance 元,在线支付 $showTotal 元" + } + } + } + + fun loadQrCodeImage(qrCodeUrl: String?) { + binding.ivPayQrCode.load(qrCodeUrl) + } + + private fun loadUserInfo(item: MemberInfo) { + binding.ivHeadPic.load( + if (item.faceUrl.isNullOrBlank()) R.drawable.ic_avatar_default + else item.faceUrl + ) + binding.tvUserName.text = item.name + + val phone = item.phone ?: "" + binding.tvUserPhone.text = + if (phone.length == 11) phone.replace(phone.substring(3, 7), "****") + else phone + } + + private fun getAmountList(): List { + val list: MutableList = mutableListOf() + + list.add(TextBean(text = "余额扣除 ", textSize = 30, textColor = "#FF5E7585")) + list.add( + TextBean( + text = "-${expensesBalance.format2String(2)}", + textSize = 30, + textColor = "#FF0A1428", + isBold = true + ) + ) + + if (balance >= totalPrice) { + //余额大于等于总价格,使用余额支付 + list.add(TextBean(text = " 元,扣除后可用余额 ", textSize = 30, textColor = "#FF5E7585")) + val remainingBalance = balance - totalPrice + list.add( + TextBean( + text = remainingBalance.format2String(2), + textSize = 30, + textColor = "#FF0A1428", + isBold = true + ) + ) + } else { + //余额小于总价格,使用余额+扫码支付 + //实际支付金额 + list.add(TextBean(text = " 元,还需支付 ", textSize = 30, textColor = "#FF5E7585")) + list.add( + TextBean( + text = realPayPrice.format2String(2), + textSize = 30, + textColor = "#FF0A1428", + isBold = true + ) + ) + } + list.add(TextBean(text = " 元", textSize = 30, textColor = "#FF5E7585")) + + return list + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/sw/dualscreen/presentation/pay/ScanQrCodePayPresentation.kt b/app/src/main/java/com/sw/dualscreen/presentation/pay/ScanQrCodePayPresentation.kt index 165dcce..858d599 100644 --- a/app/src/main/java/com/sw/dualscreen/presentation/pay/ScanQrCodePayPresentation.kt +++ b/app/src/main/java/com/sw/dualscreen/presentation/pay/ScanQrCodePayPresentation.kt @@ -1,202 +1,202 @@ -package com.sw.dualscreen.presentation.pay - -import android.annotation.SuppressLint -import android.app.Presentation -import android.os.Bundle -import android.view.Display -import com.sw.dualscreen.R -import com.sw.dualscreen.activity.PayActivity -import com.sw.dualscreen.databinding.PresentationScanQrcodePayBinding -import com.sw.dualscreen.ext.format2String -import com.sw.dualscreen.ext.gone -import com.sw.dualscreen.ext.invisible -import com.sw.dualscreen.ext.load -import com.sw.dualscreen.ext.visible -import com.sw.dualscreen.model.response.MemberInfo -import com.sw.dualscreen.model.response.TextBean -import com.sw.dualscreen.utils.SpannedUtils - -class ScanQrCodePayPresentation( - val activity: PayActivity, - display: Display, - val type: Int, - private val onDismissListener: () -> Unit = {} -) : Presentation(activity, display) { - - //type = 0,扫码支付默认显示二维码 - //type = 1,会员结算显示二维码,是会员则显示名字、头像、手机号、可用余额 - //type = 2,支付成功,是会员则显示名字、头像、手机号、可用余额 - - private lateinit var binding: PresentationScanQrcodePayBinding - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - binding = PresentationScanQrcodePayBinding.inflate(layoutInflater) - setContentView(binding.root) - window?.setBackgroundDrawableResource(android.R.color.transparent) - initView() - } - - var foodName: String? = null - var payQrCodePic: Any? = null - - //总价格 - var totalPrice = 0.0 - - //余额 - private var balance = 0.0 - - //实际支付金额 - private var realPayPrice = 0.0 - - //扣除余额 - private var expensesBalance = 0.0 - - @SuppressLint("SetTextI18n") - private fun initView() { - when (type) { - 0 -> { - binding.layoutVip.gone() - binding.layoutPaySuccess.gone() - binding.layoutScanQrCode.visible() - - binding.tvPayTip.text = "请扫码支付或出示付款码" - binding.tvFoodName.text = foodName - binding.tvRealAmount.text = SpannedUtils.getAmountText( - listOf( - TextBean(text = "¥", textSize = 32), - TextBean(text = totalPrice.format2String(2), textSize = 48), - ) - ) - binding.ivPayQrCode.load(payQrCodePic) - } - - 1 -> { - val memberInfo = activity.memberInfo - binding.layoutVip.run { - if (memberInfo != null) visible() else gone() - } - binding.layoutPaySuccess.gone() - binding.layoutScanQrCode.visible() - - balance = (memberInfo?.topUpBalance ?: 0.0) + (memberInfo?.rewardBalance ?: 0.0) - realPayPrice = if (balance >= totalPrice) 0.0 else totalPrice - balance - expensesBalance = if (balance >= totalPrice) totalPrice else balance - - memberInfo?.let { loadUserInfo(it) } - binding.tvUserBalance.text = SpannedUtils.getAmountText( - listOf( - TextBean(text = "¥", textSize = 20), - TextBean(text = balance.format2String(2), textSize = 32), - ) - ) - - binding.tvFoodName.text = foodName - binding.tvRealAmount.text = SpannedUtils.getAmountText( - listOf( - TextBean(text = "¥", textSize = 32), - TextBean(text = totalPrice.format2String(2), textSize = 48), - ) - ) - binding.ivPayQrCode.run { -// load(payQrCodePic) - if (balance >= totalPrice) invisible() else visible() - } - - binding.tvPayTip.text = SpannedUtils.getAmountText(getAmountList()) - } - - 2 -> { - val memberInfo = activity.memberInfo - binding.layoutVip.run { - if (memberInfo != null) visible() else gone() - } - binding.layoutPaySuccess.visible() - binding.layoutScanQrCode.gone() - - balance = if (memberInfo != null) (memberInfo.topUpBalance - ?: 0.0) + (memberInfo.rewardBalance ?: 0.0) else 0.0 - realPayPrice = if (balance >= totalPrice) 0.0 else totalPrice - balance - expensesBalance = if (balance >= totalPrice) totalPrice else balance - - memberInfo?.let { loadUserInfo(it) } - val remainBalance = if (balance >= totalPrice) balance - totalPrice else 0.0 - binding.tvUserBalance.text = SpannedUtils.getAmountText( - listOf( - TextBean(text = "¥", textSize = 24), - TextBean(text = remainBalance.format2String(2), textSize = 36), - ) - ) - - val showBalance = expensesBalance.format2String(2) - val showTotal = totalPrice.format2String(2) - binding.tvPayInfo.text = "余额扣除 $showBalance 元,在线支付 $showTotal 元" - } - } - } - - fun loadQrCodeImage(qrCodeUrl: String?) { - binding.ivPayQrCode.load(qrCodeUrl) - } - - private fun loadUserInfo(item: MemberInfo) { - binding.ivHeadPic.load( - if(item.faceUrl.isNullOrBlank()) R.drawable.ic_avatar_default - else item.faceUrl - ) - binding.tvUserName.text = item.name - - val phone = item.phone ?: "" - binding.tvUserPhone.text = - if (phone.length == 11) phone.replace(phone.substring(3, 7), "****") - else phone - } - - private fun getAmountList(): List { - val list: MutableList = mutableListOf() - - list.add(TextBean(text = "余额扣除 ", textSize = 30, textColor = "#FF5E7585")) - list.add( - TextBean( - text = "-${expensesBalance.format2String(2)}", - textSize = 30, - textColor = "#FF0A1428", - isBold = true - ) - ) - - if (balance >= totalPrice) { - //余额大于等于总价格,使用余额支付 - list.add(TextBean(text = " 元,扣除后可用余额 ", textSize = 30, textColor = "#FF5E7585")) - val remainingBalance = balance - totalPrice - list.add( - TextBean( - text = remainingBalance.format2String(2), - textSize = 30, - textColor = "#FF0A1428", - isBold = true - ) - ) - } else { - //余额小于总价格,使用余额+扫码支付 - //实际支付金额 - list.add(TextBean(text = " 元,还需支付 ", textSize = 30, textColor = "#FF5E7585")) - list.add( - TextBean( - text = realPayPrice.format2String(2), - textSize = 30, - textColor = "#FF0A1428", - isBold = true - ) - ) - } - list.add(TextBean(text = " 元", textSize = 30, textColor = "#FF5E7585")) - - return list - } - - override fun onDisplayRemoved() { - super.onDisplayRemoved() - onDismissListener() - } -} \ No newline at end of file +//package com.sw.dualscreen.presentation.pay +// +//import android.annotation.SuppressLint +//import android.app.Presentation +//import android.os.Bundle +//import android.view.Display +//import com.sw.dualscreen.R +//import com.sw.dualscreen.activity.PayActivity +//import com.sw.dualscreen.databinding.PresentationScanQrcodePayBinding +//import com.sw.dualscreen.ext.format2String +//import com.sw.dualscreen.ext.gone +//import com.sw.dualscreen.ext.invisible +//import com.sw.dualscreen.ext.load +//import com.sw.dualscreen.ext.visible +//import com.sw.dualscreen.model.response.MemberInfo +//import com.sw.dualscreen.model.response.TextBean +//import com.sw.dualscreen.utils.SpannedUtils +// +//class ScanQrCodePayPresentation( +// val activity: PayActivity, +// display: Display, +// val type: Int, +// private val onDismissListener: () -> Unit = {} +//) : Presentation(activity, display) { +// +// //type = 0,扫码支付默认显示二维码 +// //type = 1,会员结算显示二维码,是会员则显示名字、头像、手机号、可用余额 +// //type = 2,支付成功,是会员则显示名字、头像、手机号、可用余额 +// +// private lateinit var binding: PresentationScanQrcodePayBinding +// +// override fun onCreate(savedInstanceState: Bundle?) { +// super.onCreate(savedInstanceState) +// binding = PresentationScanQrcodePayBinding.inflate(layoutInflater) +// setContentView(binding.root) +// window?.setBackgroundDrawableResource(android.R.color.transparent) +// initView() +// } +// +// var foodName: String? = null +// var payQrCodePic: Any? = null +// +// //总价格 +// var totalPrice = 0.0 +// +// //余额 +// private var balance = 0.0 +// +// //实际支付金额 +// private var realPayPrice = 0.0 +// +// //扣除余额 +// private var expensesBalance = 0.0 +// +// @SuppressLint("SetTextI18n") +// private fun initView() { +// when (type) { +// 0 -> { +// binding.layoutVip.gone() +// binding.layoutPaySuccess.gone() +// binding.layoutScanQrCode.visible() +// +// binding.tvPayTip.text = "请扫码支付或出示付款码" +// binding.tvFoodName.text = foodName +// binding.tvRealAmount.text = SpannedUtils.getAmountText( +// listOf( +// TextBean(text = "¥", textSize = 32), +// TextBean(text = totalPrice.format2String(2), textSize = 48), +// ) +// ) +// binding.ivPayQrCode.load(payQrCodePic) +// } +// +// 1 -> { +// val memberInfo = activity.memberInfo +// binding.layoutVip.run { +// if (memberInfo != null) visible() else gone() +// } +// binding.layoutPaySuccess.gone() +// binding.layoutScanQrCode.visible() +// +// balance = (memberInfo?.topUpBalance ?: 0.0) + (memberInfo?.rewardBalance ?: 0.0) +// realPayPrice = if (balance >= totalPrice) 0.0 else totalPrice - balance +// expensesBalance = if (balance >= totalPrice) totalPrice else balance +// +// memberInfo?.let { loadUserInfo(it) } +// binding.tvUserBalance.text = SpannedUtils.getAmountText( +// listOf( +// TextBean(text = "¥", textSize = 20), +// TextBean(text = balance.format2String(2), textSize = 32), +// ) +// ) +// +// binding.tvFoodName.text = foodName +// binding.tvRealAmount.text = SpannedUtils.getAmountText( +// listOf( +// TextBean(text = "¥", textSize = 32), +// TextBean(text = totalPrice.format2String(2), textSize = 48), +// ) +// ) +// binding.ivPayQrCode.run { +//// load(payQrCodePic) +// if (balance >= totalPrice) invisible() else visible() +// } +// +// binding.tvPayTip.text = SpannedUtils.getAmountText(getAmountList()) +// } +// +// 2 -> { +// val memberInfo = activity.memberInfo +// binding.layoutVip.run { +// if (memberInfo != null) visible() else gone() +// } +// binding.layoutPaySuccess.visible() +// binding.layoutScanQrCode.gone() +// +// balance = if (memberInfo != null) (memberInfo.topUpBalance +// ?: 0.0) + (memberInfo.rewardBalance ?: 0.0) else 0.0 +// realPayPrice = if (balance >= totalPrice) 0.0 else totalPrice - balance +// expensesBalance = if (balance >= totalPrice) totalPrice else balance +// +// memberInfo?.let { loadUserInfo(it) } +// val remainBalance = if (balance >= totalPrice) balance - totalPrice else 0.0 +// binding.tvUserBalance.text = SpannedUtils.getAmountText( +// listOf( +// TextBean(text = "¥", textSize = 24), +// TextBean(text = remainBalance.format2String(2), textSize = 36), +// ) +// ) +// +// val showBalance = expensesBalance.format2String(2) +// val showTotal = totalPrice.format2String(2) +// binding.tvPayInfo.text = "余额扣除 $showBalance 元,在线支付 $showTotal 元" +// } +// } +// } +// +// fun loadQrCodeImage(qrCodeUrl: String?) { +// binding.ivPayQrCode.load(qrCodeUrl) +// } +// +// private fun loadUserInfo(item: MemberInfo) { +// binding.ivHeadPic.load( +// if(item.faceUrl.isNullOrBlank()) R.drawable.ic_avatar_default +// else item.faceUrl +// ) +// binding.tvUserName.text = item.name +// +// val phone = item.phone ?: "" +// binding.tvUserPhone.text = +// if (phone.length == 11) phone.replace(phone.substring(3, 7), "****") +// else phone +// } +// +// private fun getAmountList(): List { +// val list: MutableList = mutableListOf() +// +// list.add(TextBean(text = "余额扣除 ", textSize = 30, textColor = "#FF5E7585")) +// list.add( +// TextBean( +// text = "-${expensesBalance.format2String(2)}", +// textSize = 30, +// textColor = "#FF0A1428", +// isBold = true +// ) +// ) +// +// if (balance >= totalPrice) { +// //余额大于等于总价格,使用余额支付 +// list.add(TextBean(text = " 元,扣除后可用余额 ", textSize = 30, textColor = "#FF5E7585")) +// val remainingBalance = balance - totalPrice +// list.add( +// TextBean( +// text = remainingBalance.format2String(2), +// textSize = 30, +// textColor = "#FF0A1428", +// isBold = true +// ) +// ) +// } else { +// //余额小于总价格,使用余额+扫码支付 +// //实际支付金额 +// list.add(TextBean(text = " 元,还需支付 ", textSize = 30, textColor = "#FF5E7585")) +// list.add( +// TextBean( +// text = realPayPrice.format2String(2), +// textSize = 30, +// textColor = "#FF0A1428", +// isBold = true +// ) +// ) +// } +// list.add(TextBean(text = " 元", textSize = 30, textColor = "#FF5E7585")) +// +// return list +// } +// +// override fun onDisplayRemoved() { +// super.onDisplayRemoved() +// onDismissListener() +// } +//} \ No newline at end of file diff --git a/app/src/main/res/layout/presentation_pay.xml b/app/src/main/res/layout/presentation_pay.xml new file mode 100644 index 0000000..01a8e49 --- /dev/null +++ b/app/src/main/res/layout/presentation_pay.xml @@ -0,0 +1,418 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file