增加支付接口相关逻辑

This commit is contained in:
2025-12-05 18:03:31 +08:00
parent 8899cae323
commit 04e318f47b
38 changed files with 830 additions and 316 deletions
@@ -121,6 +121,8 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
private fun initData() {
// viewModel.getEquipmentToken()
viewModel.getUserFaceCache(pageNo = 1)
//viewModel.getUserFaceCache2()
// presentation?.step1()
presentation?.step1FoodRecognizing()
}
@@ -219,7 +221,15 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
ToastUtils.showToast("暂无识别数据,请搜索选择")
return@setOnClickListener
}
createOrder(checkedItem!!)
val realWeight = (lastWeight * 1000).roundToInt()
createOrder(foodInfo = checkedItem!!, foodWeight = realWeight, eatWeight = realWeight) {
presentation?.dismiss()
startActivity(Intent(this, PayActivity::class.java).apply {
putExtra(PayActivity.FOOD_INFO, checkedItem!!)
putExtra(PayActivity.FOOD_ORDER_ID, foodOrderId)
})
}
}
}
}
@@ -656,19 +666,18 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
lastTouchTime = System.currentTimeMillis()
}
private fun createOrder(foodInfo: FoodInfo) {
fun createOrder(foodInfo: FoodInfo, foodWeight: Int, eatWeight: Int, block:()-> Unit) {
val mode = SPUtil.getInstance().get(GlobalKey.KEY_CHARGE_MODE, 0)
val realWeight = (lastWeight * 1000).roundToInt()
val order = FoodOrder(
deviceId = GlobalData.deviceId,
foodId = foodInfo.foodId,
foodName = foodInfo.foodName ?: "",
foodMaterialId = foodInfo.foodMaterialId ?: "",
specId = foodInfo.specId ?: "",
foodWeight = realWeight,
eatWeight = realWeight,
foodWeight = foodWeight,
eatWeight = eatWeight,
//根据specId对应规格重量计算
eatNum = getEatNum(realWeight, foodInfo.specWeight ?: 0.0),
eatNum = getEatNum(foodWeight, foodInfo.specWeight ?: 0.0),
userId = null,
notPay = mode != 0,
)
@@ -679,12 +688,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
return@runOnUiThread
}
foodOrderId = orderId
presentation?.dismiss()
startActivity(Intent(this, PayActivity::class.java).apply {
putExtra(PayActivity.FOOD_INFO, foodInfo)
putExtra(PayActivity.FOOD_ORDER_ID, orderId)
})
// ToastUtils.showToast("订单已生成")
block()
}
}
}
@@ -14,6 +14,7 @@ import com.sw.dualscreen.model.response.MemberInfo
import com.sw.dualscreen.presentation.pay.ScanQrCodePayPresentation
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
class PayActivity : BaseActivity<ActivityPayBinding>() {
@@ -164,40 +165,63 @@ class PayActivity : BaseActivity<ActivityPayBinding>() {
private var scanQrCodePayPresentation: ScanQrCodePayPresentation? = null
var memberInfo: MemberInfo? = null
fun showPayInfo(memberInfo: MemberInfo) {
fun showPayInfo(type: Int = 1, isVip: Boolean = false, memberInfo: MemberInfo? = null) {
this.memberInfo = memberInfo
payResultFragment = PayResultFragment.instance(1, memberInfo)
payResultFragment = PayResultFragment.instance(type, memberInfo)
showFragment(payResultFragment!!, TAG_PAY_RESULT)
if (displays.size > 1) {
scanQrCodePayPresentation = ScanQrCodePayPresentation(
activity = this,
display = displays[1],
type = 1
type = type
) {
scanQrCodePayPresentation?.dismiss()
}.also {
it.foodName = foodInfo?.foodName
it.totalPrice = foodInfo?.vipPrice?:0.0
//确认使用vipPrice 还是 specPrice
val totalPrice = if (isVip) foodInfo?.vipPrice else foodInfo?.specPrice
it.totalPrice = totalPrice ?: 0.0
}
scanQrCodePayPresentation?.show()
}
}
fun showPaySuccess() {
payResultFragment = PayResultFragment.instance(2, memberInfo!!)
showFragment(payResultFragment!!, TAG_PAY_RESULT)
if (displays.size > 1) {
scanQrCodePayPresentation = ScanQrCodePayPresentation(
activity = this,
display = displays[1],
type = 2
) {
scanQrCodePayPresentation?.dismiss()
}.also {
it.foodName = foodInfo?.foodName
it.totalPrice = foodInfo?.vipPrice?:0.0
fun showPaySuccess(isVip: Boolean) {
showPayInfo(type = 2, isVip = isVip, memberInfo = memberInfo)
}
scanQrCodePayPresentation?.show()
fun getQrCodeImg(orderId: String, userId: String? = null, block: (String?) -> Unit) {
userViewModel.getQrCodeImg(orderId = orderId, userId = userId) { qrCodeImg ->
runOnUiThread {
if (qrCodeImg.isNullOrBlank()) {
ToastUtils.showToast("获取二维码失败")
return@runOnUiThread
}
block(qrCodeImg)
}
}
}
fun cashPay(param: HashMap<String, String>, block: (Boolean) -> Unit) {
userViewModel.cashPay(param) {
runOnUiThread {
block(it)
}
}
}
fun memberPay(param: HashMap<String, String>, block: () -> Unit) {
userViewModel.memberPay(param) {
runOnUiThread {
block()
}
}
}
fun paySuccessCallback(isVip: Boolean, block: () -> Unit = {}) {
userViewModel.paySuccessCallback(queryType = 1, orderId = foodOrderId) {
showPaySuccess(isVip)
block()
}
}
@@ -7,11 +7,13 @@ import androidx.core.text.buildSpannedString
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.plate.utils.ToastUtils
class CashPayFragment : BaseFragment<FragmentCashPayBinding>() {
private lateinit var payActivity: PayActivity
private var payActivity: PayActivity? = null
private var foodName: String? = null
private var payAmount: String? = null
@@ -22,12 +24,30 @@ class CashPayFragment : BaseFragment<FragmentCashPayBinding>() {
}
override fun initialize() {
payActivity = requireActivity() as PayActivity
payActivity = requireActivity() as? PayActivity
foodName = payActivity.foodInfo?.foodName
payAmount = "36.80"
foodName = payActivity?.foodInfo?.foodName
payAmount = payActivity?.foodInfo?.specPrice.format2String(2)
binding.tvRealAmount.text = getAmountText(payAmount?:"")
binding.btnConfirmPayFinish.setOnClickListener {
payActivity?.cashPay(hashMapOf(
//标价金额(单位为元)
"totalFee" to (payAmount?:""),
//订单类型(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)
}
}
showSubScreen()
}
override fun onHiddenChanged(hidden: Boolean) {
@@ -36,7 +56,7 @@ class CashPayFragment : BaseFragment<FragmentCashPayBinding>() {
delayDismiss()
return
}
showSubScreen()
//showSubScreen()
}
override fun onDestroy() {
@@ -54,7 +74,7 @@ class CashPayFragment : BaseFragment<FragmentCashPayBinding>() {
private fun showSubScreen() {
// 查找副屏(通常索引为1
if (displays.size > 1) {
presentation = CashPayPresentation(activity = payActivity, display = displays[1]) {
presentation = CashPayPresentation(activity = payActivity!!, display = displays[1]) {
presentation?.dismiss()
}.also {
it.foodName = foodName
@@ -4,6 +4,7 @@ import android.graphics.Bitmap
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
class FacePayFragment : BaseFragment<FragmentFacePayBinding>() {
@@ -22,7 +23,7 @@ class FacePayFragment : BaseFragment<FragmentFacePayBinding>() {
// payActivity?.showPayResult()
// }
foodName = payActivity?.foodInfo?.foodName
payAmount = "36.80"
payAmount = payActivity?.foodInfo?.specPrice.format2String(2)
showSubScreen()
}
@@ -32,7 +33,7 @@ class FacePayFragment : BaseFragment<FragmentFacePayBinding>() {
delayDismiss()
return
}
showSubScreen()
//showSubScreen()
}
override fun onDestroy() {
@@ -32,7 +32,7 @@ class NumberPayFragment: BaseFragment<FragmentNumberPayBinding>() {
delayDismiss()
return
}
showSubScreen()
//showSubScreen()
}
override fun onDestroy() {
@@ -1,12 +1,6 @@
package com.sw.dualscreen.activity.fragment.pay
import android.os.Bundle
import android.text.Spanned
import android.text.SpannedString
import android.text.style.AbsoluteSizeSpan
import android.text.style.ForegroundColorSpan
import androidx.core.graphics.toColorInt
import androidx.core.text.buildSpannedString
import com.sw.dualscreen.R
import com.sw.dualscreen.activity.PayActivity
import com.sw.dualscreen.activity.fragment.BaseFragment
@@ -16,7 +10,6 @@ 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.FoodInfo
import com.sw.dualscreen.model.response.MemberInfo
import com.sw.dualscreen.model.response.TextBean
import com.sw.dualscreen.utils.SpannedUtils
@@ -30,7 +23,7 @@ class PayResultFragment : BaseFragment<FragmentPayResultBinding>() {
companion object {
const val PAGE_TYPE = "pageType"
const val MEMBER_INFO = "memberInfo"
fun instance(pageType: Int, memberInfo: MemberInfo): PayResultFragment {
fun instance(pageType: Int, memberInfo: MemberInfo?): PayResultFragment {
return PayResultFragment().apply {
arguments = Bundle().also {
it.putInt(PAGE_TYPE, pageType)
@@ -53,16 +46,24 @@ class PayResultFragment : BaseFragment<FragmentPayResultBinding>() {
binding.btnBack.setOnClickListener {
//payActivity?.showFacePay()
}
if (memberInfo != null) {
binding.layoutMemberInfo.visible()
} else {
binding.layoutMemberInfo.gone()
}
arguments?.let {
pageType = it.getInt(PAGE_TYPE, 0)
memberInfo = it.getParcelable(MEMBER_INFO)
}
totalPrice = payActivity?.foodInfo?.vipPrice ?: 0.0
memberInfo?.let {
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) }
loadUserInfo(it)
}
when (pageType) {
0 -> {
@@ -95,19 +96,24 @@ class PayResultFragment : BaseFragment<FragmentPayResultBinding>() {
)
if (balance >= totalPrice) {
binding.ivPayQrCode.invisible()
binding.btnConfirmPay.isEnabled = true
binding.btnConfirmPay.run {
isEnabled = true
//点击支付,接口成功打开成功页面
setOnClickListener {
memberPay()
}
}
} else {
binding.ivPayQrCode.visible()
// binding.ivPayQrCode.load(payQrCodePic)
binding.btnConfirmPay.isEnabled = false
payActivity?.getQrCodeImg(
orderId = payActivity!!.foodOrderId,
userId = memberInfo!!.id
) { qrCodeImg ->
binding.ivPayQrCode.load(qrCodeImg)
//扫码成功回调打开成功页面
payActivity?.paySuccessCallback(true)
}
//点击支付接口成功打开成功页面,或者扫码手动成功回调打开成功页面
binding.btnConfirmPay.setOnClickListener {
payActivity?.showWaitingDialog("支付中,请稍后……")
binding.root.postDelayed({
payActivity?.hideWaitingDialog()
payActivity?.showPaySuccess()
},1000)
}
}
@@ -115,9 +121,22 @@ class PayResultFragment : BaseFragment<FragmentPayResultBinding>() {
binding.layoutPayInfo.gone()
binding.layoutPaySuccess.visible()
if (memberInfo != null) {
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),
)
)
binding.tvPayAmount.text = "收款金额 ${realPayPrice.format2String(2)}"
binding.tvPayInfo.text =
"应收 ${totalPrice.format2String(2)} 元,余额扣除 ${expensesBalance.format2String(2)}"
binding.tvPayAmount.text = "收款金额 ${realPayPrice.format2String(2)}"
} else {
binding.tvPayAmount.text = "收款金额 ${totalPrice.format2String(2)}"
binding.tvPayInfo.text =
"应收 ${totalPrice.format2String(2)}"
}
}
else -> {}
@@ -168,6 +187,25 @@ class PayResultFragment : BaseFragment<FragmentPayResultBinding>() {
phone
}
private fun memberPay() {
payActivity?.run {
showWaitingDialog("支付中,请稍后……")
memberPay(
hashMapOf(
//支付金额
"totalFee" to totalPrice.format2String(2),
//订单号
"orderNo" to payActivity!!.foodOrderId,
//用户id
"memberId" to memberInfo!!.id!!
)
) {
binding.root.postDelayed({
hideWaitingDialog()
showPaySuccess(true)
},1000)
}
}
}
}
@@ -24,7 +24,7 @@ class ScanQrCodePayFragment: BaseFragment<FragmentScanQrcodePayBinding>() {
private lateinit var payActivity: PayActivity
private var foodName: String? = null
private var payAmount: String? = null
private var payQrCodePic: Any? = null
private var payQrCodePic: String? = null
var presentation: ScanQrCodePayPresentation?=null
private var countDownJob: Job? = null
@@ -37,14 +37,19 @@ class ScanQrCodePayFragment: BaseFragment<FragmentScanQrcodePayBinding>() {
foodName = payActivity.foodInfo?.foodName
payAmount = payActivity.foodInfo?.specPrice.format2String(2)
payQrCodePic = R.drawable.ic_qrcode
binding.tvRealAmount.text = getAmountText(payAmount?:"")
payActivity.getQrCodeImg(orderId = payActivity.foodOrderId) {
payQrCodePic = it
binding.ivPayQrCode.load(payQrCodePic)
binding.tvPayResult.text = "待支付(60s)..."
startCountDown()
payActivity.paySuccessCallback(false)
showSubScreen()
startCountDown()
}
}
override fun onHiddenChanged(hidden: Boolean) {
@@ -53,7 +58,7 @@ class ScanQrCodePayFragment: BaseFragment<FragmentScanQrcodePayBinding>() {
delayDismiss()
return
}
showSubScreen()
//showSubScreen()
}
override fun onDestroy() {
@@ -104,4 +109,5 @@ class ScanQrCodePayFragment: BaseFragment<FragmentScanQrcodePayBinding>() {
}
)
}
}
@@ -3,14 +3,8 @@ package com.sw.dualscreen.model.response
data class ApiResponse<T>(
val code: String,
val msg: String? = "",
val data: T? = null
) {
fun isSuccess(): Boolean = ("00000" == code)
val result: T?
get() = data
val message: String?
get() = msg
}
val data: T? = null,
val result: T? = null,
)
@@ -50,6 +50,25 @@ data class MemberInfo(
data class TextBean(
var text: String,
var textSize: Int,
var textSize: Int = 0,
var textColor: String? = null
)
data class UserNutrition(
//姓名
val name: String?,
//推荐能量
val recommendEnergy: Double?,
//热量
val calorie: Double?,
//果蔬
val fruitsVegetables: Double?,
//肉蛋
val meatEggs: Double?,
//主食
val stapleFood: Double?,
)
data class PayResult(
val paySuc: String? = null
)
@@ -16,13 +16,13 @@ data class FoodInfo(
//菜品名称
val foodName:String? = null,
//能量
val calorie:String? = null,
val calorie:Double? = null,
//蛋白质
val protein:String? = null,
val protein:Double? = null,
//脂肪
val fat:String? = null,
val fat:Double? = null,
//碳水化合物
val carbohydrate:String? = null,
val carbohydrate:Double? = null,
//规格售卖价格(元)
val specPrice: Double? = null,
//VIP售卖价(元)
@@ -33,6 +33,12 @@ data class FoodInfo(
val specId:String? = null,
//规格重量(g)
val specWeight:Double? = null,
//主食
val stapleFood:Double? = null,
//果蔬
val fruitsVegetables:Double? = null,
//肉蛋
val meatEggs:Double? = null,
//-----------------------------------
var score: Int = 0,
@@ -42,12 +48,12 @@ data class FoodInfo(
// @SerializedName("foodTypeAndRealIntakeVoList")
// val foodTypeAndRealIntakeVoList: List<FoodTypeAndRealIntakeVo>? = listOf(),
@SerializedName("stFoodInfoMaterial")
val stFoodInfoMaterial: StFoodInfoMaterial? = StFoodInfoMaterial(),
// @SerializedName("stFoodInfoMaterial")
// val stFoodInfoMaterial: StFoodInfoMaterial? = StFoodInfoMaterial(),
// @SerializedName("stFoodInfoPagoda")
// val stFoodInfoPagoda: StFoodInfoPagoda? = StFoodInfoPagoda(),
@SerializedName("stFoodInfoPagodaAPPVO")
val stFoodInfoPagodaAPPVO: StFoodInfoPagodaAPPVO? = StFoodInfoPagodaAPPVO(),
// @SerializedName("stFoodInfoPagodaAPPVO")
// val stFoodInfoPagodaAPPVO: StFoodInfoPagodaAPPVO? = StFoodInfoPagodaAPPVO(),
// @SerializedName("stFoodInfoSetting")
// val stFoodInfoSetting: StFoodInfoSetting? = StFoodInfoSetting(),
// @SerializedName("stFoodInfoSpecificationList")
@@ -22,3 +22,19 @@ data class UserFaceModel(
val userId: String? = "",
val faceFeatureStr: String? = ""
) : Parcelable
@Parcelize
data class UserFaceModel2(
val userId: String? = "",
val faceFeatureString: String? = "",
val face: String? = ""
) : Parcelable
data class FaceData(
val nextPageIndex:Int,
val total:Int,
val size:Int,
val current:Int,
val pages:Int,
val records: List<UserFaceModel2>?=null
)
@@ -4,11 +4,14 @@ import com.sw.dualscreen.GlobalData
import com.sw.dualscreen.model.request.UserNutritionParam
import com.sw.dualscreen.model.response.ApiResponse
import com.sw.dualscreen.model.response.DinnerType
import com.sw.dualscreen.model.response.FaceData
import com.sw.dualscreen.model.response.FoodInfo
import com.sw.dualscreen.model.response.FoodSearchReq
import com.sw.dualscreen.model.response.FoodOrder
import com.sw.dualscreen.model.response.MemberInfo
import com.sw.dualscreen.model.response.PayResult
import com.sw.dualscreen.model.response.UserFaceModel
import com.sw.dualscreen.model.response.UserNutrition
import com.sw.dualscreen.model.response.UserNutritionData
import com.sw.dualscreen.objbox.CollectedFoodInfo
import okhttp3.MultipartBody
@@ -67,6 +70,13 @@ interface ApiService {
// @Query("pageSize") pageSize: Int
): ApiResponse<List<UserFaceModel>>
@GET
suspend fun getUserFaceCache2(
@Url url: String = "http://192.168.1.230:2223/userface/swUserFaceimgSub/list",
@Query("pageNum") pageNum: Int,
@Query("pageSize") pageSize: Int
): ApiResponse<FaceData>
/**
* 获取已采集数据列表
*/
@@ -92,17 +102,37 @@ interface ApiService {
// @Query("foodName") foodName: String,
): ApiResponse<List<FoodInfo>>
// /**
// * 通过用户信息获取就餐数据
// */
// @GET
// suspend fun getUserNutritionData(
// @Url url: String = "${GlobalData.appBaseUrl}/zhstapi/zhst/getUserNutritionData/face",
// @Query("appVersion") appVersion: String = GlobalData.appVersion,
// @Query("restId") restId: String,
// @Query("userId") userId: String,
// @Query("foodId") foodId: String,
// ): ApiResponse<UserNutritionData>
/**
* 通过用户信息获取就餐数据
*/
@GET
suspend fun getUserNutritionData(
@Url url: String = "${GlobalData.appBaseUrl}/zhstapi/zhst/getUserNutritionData/face",
@Query("appVersion") appVersion: String = GlobalData.appVersion,
@Query("restId") restId: String,
@Query("userId") userId: String,
@Query("foodId") foodId: String,
): ApiResponse<UserNutritionData>
@Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/boothMachine/app/getUserCurrentFoodDetails",
@Query("id") userId: String
): ApiResponse<UserNutrition>
/**
* 获取支付二维码
*/
@GET
suspend fun getQrCodeImg(
@Url url: String = "${GlobalData.appBaseUrl}/pay/yx-check-out-pay/getQrCodeImg",
@Query("orderNo") orderNo: String,
@Query("memberId") memberId: String?,
@Query("totalFee") totalFee: String?
): ApiResponse<String?>
/**
* 获取当前餐点类型
@@ -136,6 +166,33 @@ interface ApiService {
@Body req: FoodSearchReq
): ApiResponse<List<FoodInfo>>
/**
* 查询支付结果
*/
@POST
suspend fun queryOrderState(
@Url url: String = "${GlobalData.appBaseUrl}/pay/yx-check-out-pay/turnOrderInfo",
@Body param: HashMap<String, String>
): ApiResponse<PayResult?>
/**
* 现金支付
*/
@POST
suspend fun cashPay(
@Url url: String = "${GlobalData.appBaseUrl}/pay/yx-check-out-pay/cashPayment",
@Body param: HashMap<String, String>
): ApiResponse<Boolean?>
/**
* 会员支付
*/
@POST
suspend fun memberPay(
@Url url: String = "${GlobalData.appBaseUrl}/pay/yx-check-out-pay/memberPay",
@Body param: HashMap<String, String>
): ApiResponse<Any?>
/**
* 开餐-生成订单
*/
@@ -20,6 +20,7 @@ class RequestInterceptor : Interceptor {
.header("Accept", "application/json")
// .header("Authorization", "Bearer ${getToken()}")
// .header("X-Access-Token", getToken(originalRequest))
.header("X-Access-Token", "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjYW50ZWVuSWQiOiJiZTE1NDgzMS0zNDY2LTNiYTItYTJlYS01NzY1MmM5MTlmZWQiLCJ0eXBlIjoiNCIsInVzZXJJZCI6IjAwMDAwMDAwMDAwMDAwMDAwMDEifQ.sN40cOC-O5WQFrF4IDUs8fFlkNdUKLbJt_rHyTsgYYM")
// .header("X-DEVICE-CODE", "bcf396ed-78f6-3864-9837-7c37c5b2ec41")
.header("X-DEVICE-CODE", GlobalData.deviceId)
.header("authorization", "57ee87183f2a4fa59683ec9ef41c8f5d")
@@ -21,6 +21,7 @@ import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope
import com.arcsoft.face.ErrorInfo
import com.sw.dualscreen.GlobalKey
import com.sw.dualscreen.MyApp
import com.sw.dualscreen.R
import com.sw.dualscreen.activity.MainActivity
import com.sw.dualscreen.databinding.PresentationMainScreenBinding
@@ -33,6 +34,7 @@ import com.sw.dualscreen.ext.visible
import com.sw.dualscreen.model.request.UserNutritionParam
import com.sw.dualscreen.model.response.DinnerType
import com.sw.dualscreen.model.response.FoodInfo
import com.sw.dualscreen.model.response.UserNutrition
import com.sw.dualscreen.model.response.UserNutritionData
import com.sw.dualscreen.utils.Debouncer
import com.sw.dualscreen.utils.SPUtil
@@ -90,7 +92,9 @@ class MainScreenPresentation(
private var detectWeight = 0.0 //识别菜品时的重量
private var lastWeight = 0.0 // 上一次的计算热量结果
private var userNutritionData: UserNutritionData? = null
// private var userNutritionData: UserNutritionData? = null
private var userNutrition: UserNutrition? = null
private var dinnerTypeInfo: DinnerType? = null
private val debouncer = Debouncer(500)
private var recognitionTime: Long = 0L // 人脸识别时的时间
@@ -140,7 +144,8 @@ class MainScreenPresentation(
return
}
if (userNutritionData == null) {
//if (userNutritionData == null) {
if (userNutrition == null) {
Timber.tag(TAG).e("updateWeight userNutritionData is null")
return
}
@@ -206,17 +211,17 @@ class MainScreenPresentation(
}
}
}
activity.lifecycleScope.launch {
userViewModel.nutritionData.collect {
Timber.tag(TAG).d("registerDataChange nutritionData = $it")
userNutritionData = it
if (it == null) return@collect
// step3ShowRecognizeResult()
// activity.lifecycleScope.launch {
// userViewModel.nutritionData.collect {
// Timber.tag(TAG).d("registerDataChange nutritionData = $it")
// userNutritionData = it
// if (it == null) return@collect
//// step3ShowRecognizeResult()
// //binding.nutritionInclude.tvUserName.text = it.userName.maskName()
// //binding.nutritionInclude.tvRecommendHeat.text = "推荐热量:${it.recommendMin}-${it.recommendMax}"
// //updateWeight(lastWeight / 1000)
}
}
//// //updateWeight(lastWeight / 1000)
// }
// }
activity.lifecycleScope.launch {
userViewModel.dinnerTypeInfo.drop(1).collect {
Timber.tag(TAG).d("registerDataChange dinnerTypeInfo = $it")
@@ -311,9 +316,15 @@ class MainScreenPresentation(
tvProteinRate.text = "$proteinRate%"
tvCarbohydrateRate.text = "$carbohydrateRate%"
viewFatLine.updateLayoutParams { height = (fatRate/100.0*84).roundToInt()*1.dp }
viewProteinLine.updateLayoutParams { height = (proteinRate/100.0*84).roundToInt()*1.dp }
viewCarbohydrateLine.updateLayoutParams { height = (carbohydrateRate/100.0*84).roundToInt()*1.dp }
viewFatLine.updateLayoutParams {
height = (fatRate / 100.0 * 84).roundToInt() * 1.dp
}
viewProteinLine.updateLayoutParams {
height = (proteinRate / 100.0 * 84).roundToInt() * 1.dp
}
viewCarbohydrateLine.updateLayoutParams {
height = (carbohydrateRate / 100.0 * 84).roundToInt() * 1.dp
}
}
}
@@ -324,13 +335,14 @@ class MainScreenPresentation(
return (100.0 * value / total).roundToInt()
}
private fun getIntNutritionValue(text: String?): Int {
return if (text.isNullOrBlank()) 0 else text.toFloat().roundToInt() }
private fun getIntNutritionValue(num: Double?): Int {
return num?.roundToInt() ?: 0
}
/**
* 餐品识别成功,不计费模式
*/
fun loadUnbilledMode() {
fun loadUnbilledMode(nutrition: UserNutrition) {
binding.calorieInclude.root.gone()
binding.nutritionInclude.root.visible()
@@ -342,12 +354,13 @@ class MainScreenPresentation(
//binding.ivRecImage.gone()
//updateFoodInfo(foodInfo)
userNutritionData?.let {
binding.nutritionInclude.tvUserName.text = it.userName.maskName()
binding.nutritionInclude.tvUserName.text = nutrition.name.maskName()
binding.nutritionInclude.tvRecommendHeat.text =
"推荐热量:${it.recommendMin}-${it.recommendMax}kcal"
updateWeight(lastWeight / 1000)
}
"推荐热量:${nutrition.recommendEnergy ?: 0}kcal"
//updateWeight(lastWeight / 1000)
// -------------------------------------------------
// 删除userNutritionData,改为userNutrition
calculateNutrition(recognitionWeight - lastWeight)
}
/**
@@ -370,7 +383,8 @@ class MainScreenPresentation(
dinnerTypeInfo = null
currentFood = null
userNutritionData = null
// userNutritionData = null
userNutrition = null
recognitionWeight = 0.0
stepChangeCallback(currentStep)
@@ -434,7 +448,8 @@ class MainScreenPresentation(
binding.ivPreviewImage.gone()
dinnerTypeInfo = null
userNutritionData = null
// userNutritionData = null
userNutrition = null
recognitionWeight = 0.0
stepChangeCallback(currentStep)
@@ -457,7 +472,8 @@ class MainScreenPresentation(
binding.ivPreviewImage.gone()
binding.ivRecImage.let {
it.visible()
val imageUrl = if (foodInfo.foodImg.isNullOrBlank()) foodInfo.photoUri else foodInfo.foodImg
val imageUrl =
if (foodInfo.foodImg.isNullOrBlank()) foodInfo.photoUri else foodInfo.foodImg
it.load(imageUrl)
}
val mode = SPUtil.getInstance().get(GlobalKey.KEY_CHARGE_MODE, 0)
@@ -506,11 +522,12 @@ class MainScreenPresentation(
Timber.tag(TAG)
.d("calculateNutrition weight = $weight, recognitionWeight = $recognitionWeight")
val dinnerType = dinnerTypeInfo!!.dinnerType!!
Timber.tag(TAG)
.d("calculateNutrition foodName = ${currentFood!!.foodName}, dinnerType = $dinnerType, userId = ${userNutritionData!!.userId}")
val calcResultInfo = UserNutritionUtils.calculateNutrition(
// Timber.tag(TAG)
// .d("calculateNutrition foodName = ${currentFood!!.foodName}, dinnerType = $dinnerType, userId = ${userNutritionData!!.userId}")
val calcResultInfo = UserNutritionUtils.calculateNutrition2(
currentFood!!,
userNutritionData!!,
// userNutritionData!!,
userNutrition!!,
weight,
dinnerType = dinnerType
)
@@ -701,6 +718,7 @@ class MainScreenPresentation(
val faceEntity = compareResult.faceEntity
val userId = faceEntity.userName
if (userId == null) return@Observer
ToastUtils.showToast("人脸识别成功,userId = $userId")
if (currentFood == null) {
currentFood = activity.checkedItem
}
@@ -710,17 +728,19 @@ class MainScreenPresentation(
return@runOnUiThread
}
}
// TODO: ------------------人脸识别成功
//-------------------------------------------------
// TODO: ------------------人脸识别成功
step3ShowRecognizeResult()
//根据接口数据更新热量数据--------------------------
loadUnbilledMode()
// userViewModel.getUserNutritionData(
// userId = userId,
// foodId = currentFood!!.foodId!!
// )
userViewModel.getUserNutritionData(userId = userId) { nutrition ->
activity.runOnUiThread {
if (nutrition == null) {
ToastUtils.showToast("未查询到营养数据")
return@runOnUiThread
}
this@MainScreenPresentation.userNutrition = nutrition
loadUnbilledMode(nutrition)
// -------------------------------
}
}
})
recognizeViewModel.drawRectInfoText.observe(activity, Observer { info ->
@@ -1013,7 +1033,8 @@ class MainScreenPresentation(
}
val listIsEmpty = facePreviewInfoList.isEmpty()
val listFirstTrackId = if (listIsEmpty.not()) facePreviewInfoList[0]!!.trackId else null
Timber.tag(TAG).d("listIsEmpty=$listIsEmpty,lastFaceTrackId=$lastFaceTrackId,listFirstTrackId=$listFirstTrackId")
Timber.tag(TAG)
.d("listIsEmpty=$listIsEmpty,lastFaceTrackId=$lastFaceTrackId,listFirstTrackId=$listFirstTrackId")
if (listIsEmpty || (lastFaceTrackId != listFirstTrackId)) {
if (lastFaceTrackId != -1) {
mealPickupMode = SPUtil.getInstance().get(GlobalKey.KEY_PICKUP_MODE, 0) ?: 0
@@ -1032,9 +1053,9 @@ class MainScreenPresentation(
fun postUserData() {
Timber.tag(TAG).d("postUserData")
if (userNutritionData == null || currentFood == null) {
if (userNutrition == null || currentFood == null) {
Timber.tag(TAG)
.d("postUserData userNutritionData = ${userNutritionData == null}, currentFood = ${currentFood == null}")
.d("postUserData userNutritionData = ${userNutrition == null}, currentFood = ${currentFood == null}")
return
}
var eatWeight = 0.0
@@ -1044,14 +1065,23 @@ class MainScreenPresentation(
} else {
recognitionWeight - lastWeight
}
val userNutritionParam = UserNutritionParam(
userId = userNutritionData?.userId!!,
foodId = currentFood?.foodId!!,
faceTime = recognitionTime,
faceEndTime = System.currentTimeMillis(),
eatWeight = eatWeight,//lastWeight
foodWeight = lastWeight
)
userViewModel.postUserNutritionData(listOf(userNutritionParam))
//val userNutritionParam = UserNutritionParam(
// userId = userNutritionData?.userId!!,
// foodId = currentFood?.foodId!!,
// faceTime = recognitionTime,
// faceEndTime = System.currentTimeMillis(),
// eatWeight = eatWeight,//lastWeight
// foodWeight = lastWeight
//)
//userViewModel.postUserNutritionData(listOf(userNutritionParam))
activity.createOrder(
foodInfo = currentFood!!,
foodWeight = lastWeight.roundToInt(),
eatWeight = eatWeight.roundToInt()
) {
if (MyApp.DEBUG) {
ToastUtils.showToast("订单已生成")
}
}
}
}
@@ -4,6 +4,7 @@ package com.sw.dualscreen.presentation
import android.text.TextUtils
import com.sw.dualscreen.ext.toSafeDouble
import com.sw.dualscreen.model.response.FoodInfo
import com.sw.dualscreen.model.response.UserNutrition
import com.sw.dualscreen.model.response.UserNutritionData
import timber.log.Timber
import kotlin.math.max
@@ -16,62 +17,109 @@ object UserNutritionUtils {
/**
* 计算热量信息
*/
fun calculateNutrition(
fun calculateNutrition2(
foodInfo: FoodInfo,
userModel: UserNutritionData,
nutrition: UserNutrition,
weight: Double,
dinnerType: String
): CalcResultInfo {
// 初始化变量
var foodKcal = 0.0
var totalKcal = 0.0
var (vegetable, meat, fruits, grain) = List(4) { 0.0 }
var (calorie, grain, fruitsVegetables, meatEggs) = List(4) { 0.0 }
// 处理食物信息
foodKcal = calculateValue(foodInfo.stFoodInfoMaterial?.energyKcal, weight)
Timber.d("calculateNutrition foodKcal = ${foodKcal}, energyKcal = ${foodInfo.stFoodInfoMaterial?.energyKcal}, weight = $weight")
grain = calculateValue(foodInfo.stFoodInfoPagodaAPPVO?.grainValue(), weight)
fruits = calculateValue(foodInfo.stFoodInfoPagodaAPPVO?.fruitsValue(), weight)
vegetable = calculateValue(foodInfo.stFoodInfoPagodaAPPVO?.vegetableValue(), weight)
meat = calculateValue(foodInfo.stFoodInfoPagodaAPPVO?.meatValue(), weight)
calorie = calculateValue(foodInfo.calorie, weight)
grain = calculateValue(foodInfo.stapleFood, weight)
fruitsVegetables = calculateValue(foodInfo.fruitsVegetables, weight)
meatEggs = calculateValue(foodInfo.meatEggs, weight)
// 合并用户数据
grain += userModel.stFoodInfoPagoda?.grainValue() ?: 0.0
calorie += nutrition.calorie ?: 0.0
grain += nutrition.stapleFood ?: 0.0
fruitsVegetables += nutrition.fruitsVegetables ?: 0.0
meatEggs += nutrition.meatEggs ?: 0.0
fruits += userModel.stFoodInfoPagoda?.fruitsValue() ?: 0.0
vegetable = vegetable.plus(userModel.stFoodInfoPagoda?.vegetableValue() ?: 0.0)
meat += userModel.stFoodInfoPagoda?.meatValue() ?: 0.0
totalKcal = foodKcal + userModel.energyValue()
Timber.d("calculateNutrition totalKcal = ${totalKcal}, energyValue = ${userModel.energyValue()}")
if (totalKcal < 0){
totalKcal = 0.0
}
totalKcal = max(calorie, 0.0)
// 判断当餐最大热量
val maxKcal =
userModel.totalEnergyCalculateScoreValue() * calculateDinnerTypeRatio(dinnerType) / 10
Timber.d("calculateNutrition maxKcal = ${maxKcal}, CalculateScoreValue = ${userModel.totalEnergyCalculateScoreValue()}")
val pagoda = userModel.stFoodInfoPagoda
val fruitsInfo = parseRecommend(pagoda?.fruitsRecommend, fruits)
val vegetableInfo = parseRecommend(pagoda?.vegetableRecommend, vegetable)
//val maxKcal = userModel.totalEnergyCalculateScoreValue() * calculateDinnerTypeRatio(dinnerType) / 10
//Timber.d("calculateNutrition maxKcal = ${maxKcal}, CalculateScoreValue = ${userModel.totalEnergyCalculateScoreValue()}")
// TODO: 测试数据-------------------------------
val rate = calculateDinnerTypeRatio(dinnerType) / 10.0
val maxKcal = totalKcal/ 0.26 / rate
val grainRecommend = "0-100"
val meatRecommend = "0-100"
val fruitsRecommend = "0-100"
// TODO: 测试数据-------------------------------
val calcResult = CalcResultInfo(
totalKcal = CalcInfo(
max = maxKcal,
min = 0.0,
current = totalKcal
),
grain = parseRecommend(pagoda?.grainRecommend, grain),
fruits = CalcInfo( // 果蔬 = 水果+蔬菜
max = fruitsInfo.max + vegetableInfo.max,
min = fruitsInfo.min + vegetableInfo.min,
current = fruitsInfo.current + vegetableInfo.current
),
meat = parseRecommend(pagoda?.meatRecommend, meat)
grain = parseRecommend(grainRecommend, grain),
fruits = parseRecommend(fruitsRecommend, fruitsVegetables),
meat = parseRecommend(meatRecommend, meatEggs)
)
return calcResult
}
// fun calculateNutrition(
// foodInfo: FoodInfo,
// userModel: UserNutritionData,
//// userModel: UserNutrition,
// weight: Double,
// dinnerType: String
// ): CalcResultInfo {
//
// // 初始化变量
// var foodKcal = 0.0
// var totalKcal = 0.0
// var (vegetable, meat, fruits, grain) = List(4) { 0.0 }
//
// // 处理食物信息
// foodKcal = calculateValue(foodInfo.stFoodInfoMaterial?.energyKcal, weight)
// Timber.d("calculateNutrition foodKcal = ${foodKcal}, energyKcal = ${foodInfo.stFoodInfoMaterial?.energyKcal}, weight = $weight")
// grain = calculateValue(foodInfo.stFoodInfoPagodaAPPVO?.grainValue(), weight)
// fruits = calculateValue(foodInfo.stFoodInfoPagodaAPPVO?.fruitsValue(), weight)
// vegetable = calculateValue(foodInfo.stFoodInfoPagodaAPPVO?.vegetableValue(), weight)
// meat = calculateValue(foodInfo.stFoodInfoPagodaAPPVO?.meatValue(), weight)
//
// // 合并用户数据
// grain += userModel.stFoodInfoPagoda?.grainValue() ?: 0.0
//
// fruits += userModel.stFoodInfoPagoda?.fruitsValue() ?: 0.0
// vegetable = vegetable.plus(userModel.stFoodInfoPagoda?.vegetableValue() ?: 0.0)
// meat += userModel.stFoodInfoPagoda?.meatValue() ?: 0.0
//
// totalKcal = foodKcal + userModel.energyValue()
// Timber.d("calculateNutrition totalKcal = ${totalKcal}, energyValue = ${userModel.energyValue()}")
// if (totalKcal < 0) {
// totalKcal = 0.0
// }
// // 判断当餐最大热量
// val maxKcal =
// userModel.totalEnergyCalculateScoreValue() * calculateDinnerTypeRatio(dinnerType) / 10
// Timber.d("calculateNutrition maxKcal = ${maxKcal}, CalculateScoreValue = ${userModel.totalEnergyCalculateScoreValue()}")
// val pagoda = userModel.stFoodInfoPagoda
// val fruitsInfo = parseRecommend(pagoda?.fruitsRecommend, fruits)
// val vegetableInfo = parseRecommend(pagoda?.vegetableRecommend, vegetable)
// val calcResult = CalcResultInfo(
// totalKcal = CalcInfo(
// max = maxKcal,
// min = 0.0,
// current = totalKcal
// ),
// grain = parseRecommend(pagoda?.grainRecommend, grain),
// fruits = CalcInfo( // 果蔬 = 水果+蔬菜
// max = fruitsInfo.max + vegetableInfo.max,
// min = fruitsInfo.min + vegetableInfo.min,
// current = fruitsInfo.current + vegetableInfo.current
// ),
// meat = parseRecommend(pagoda?.meatRecommend, meat)
// )
// return calcResult
// }
fun parseRecommend(recommend: String?, current: Double): CalcInfo {
var newCurrent = if (current < 0) 0.0 else current
if (TextUtils.isEmpty(recommend) || !recommend!!.contains("-")) {
@@ -29,8 +29,12 @@ import com.arcsoft.face.ErrorInfo
import com.sw.dualscreen.R
import com.sw.dualscreen.activity.PayActivity
import com.sw.dualscreen.databinding.PresentationFacePayBinding
import com.sw.dualscreen.ext.format2String
import com.sw.dualscreen.ext.load
import com.sw.dualscreen.model.response.MemberInfo
import com.sw.dualscreen.model.response.TextBean
import com.sw.dualscreen.utils.GsonUtils
import com.sw.dualscreen.utils.SpannedUtils
import com.sw.dualscreen.view.CustomDialog
import com.sw.dualscreen.viewmodel.UserViewModel
import com.sw.plate.utils.ToastUtils
@@ -99,7 +103,12 @@ class FacePayPresentation(
var payAmount: String? = null
private fun initView() {
binding.tvFoodName.text = foodName
binding.tvRealAmount.text = getAmountText(payAmount ?: "")
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) {
@@ -110,19 +119,13 @@ class FacePayPresentation(
// }
}
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) !=
@@ -168,33 +171,13 @@ class FacePayPresentation(
}
}
}
// activity.lifecycleScope.launch {
// userViewModel.nutritionData.collect {
// Timber.tag(TAG).d("registerDataChange nutritionData = $it")
// userNutritionData = it
// if (it == null) return@collect
// step3ShowRecognizeResult()
// //binding.nutritionInclude.tvUserName.text = it.userName.maskName()
// //binding.nutritionInclude.tvRecommendHeat.text = "推荐热量:${it.recommendMin}-${it.recommendMax}"
// //updateWeight(lastWeight / 1000)
// }
// }
// activity.lifecycleScope.launch {
// userViewModel.dinnerTypeInfo.drop(1).collect {
// Timber.tag(TAG).d("registerDataChange dinnerTypeInfo = $it")
// dinnerTypeInfo = it
// }
// }
}
override fun onStop() {
if (rgbCameraHelper != null) {
rgbCameraHelper!!.release()
rgbCameraHelper?.release()
rgbCameraHelper = null
}
if (irCameraHelper != null) {
irCameraHelper!!.release()
irCameraHelper?.release()
irCameraHelper = null
}
recognizeViewModel.destroy()
super.onStop()
}
@@ -202,8 +185,8 @@ class FacePayPresentation(
fun resumeCamera() {
Timber.tag(TAG).d("resumeCamera isRecognition = $isRecognition")
isRecognition = true
if (rgbCameraHelper != null && rgbCameraHelper!!.isStopped) {
rgbCameraHelper!!.start()
if (rgbCameraHelper?.isStopped == true) {
rgbCameraHelper?.start()
}
}
@@ -249,7 +232,8 @@ class FacePayPresentation(
recognizeViewModel.recognizeConfiguration
.observe(activity, Observer { recognizeConfiguration: RecognizeConfiguration? ->
Timber.tag(TAG).i("recognizeConfiguration: observe = ${recognizeConfiguration.toString()}")
Timber.tag(TAG)
.i("recognizeConfiguration: observe = ${recognizeConfiguration.toString()}")
})
recognizeViewModel.recognizeNotice.observe(activity, Observer { notice: String? ->
Timber.tag(TAG).i("recognizeNotice observe notice = $notice")
@@ -258,45 +242,15 @@ class FacePayPresentation(
recognizeViewModel.recognizeUserId.observe(
activity,
Observer { compareResult: CompareResult ->
Timber.tag(TAG).i("recognizeUserId observe compareResult = ${compareResult.trackId}, userId = ${compareResult.faceEntity.userName}")
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
activity.runOnUiThread {
//ToastUtils.showToast("用户人脸识别成功,挑战支付页面")
showWaitingDialog("刷脸支付中,请稍后……")
userViewModel.getMemberInfo(memberId = userId) { memberInfo ->
activity.runOnUiThread {
if (memberInfo == null) {
ToastUtils.showToast("查询会员信息失败,请稍后重试")
return@runOnUiThread
}
userViewModel.bindOrder(userId, activity.foodOrderId) { bindResult ->
activity.runOnUiThread {
if (bindResult.not()) {
hideWaitingDialog()
ToastUtils.showToast("订单绑定失败")
return@runOnUiThread
}
binding.root.postDelayed({
hideWaitingDialog()
activity.showPayInfo(memberInfo)
binding.root.postDelayed({
dismiss()
},500)
},1500)
}
}
}
}
}
// userViewModel.getUserNutritionData(
// userId = userId,
// foodId = currentFood!!.id!!
// )
faceRecSuccess(userId)
})
recognizeViewModel.drawRectInfoText.observe(activity, Observer { info ->
@@ -388,7 +342,8 @@ class FacePayPresentation(
displayOrientation: Int,
isMirror: Boolean
) {
Timber.tag(TAG).d("initRgbCamera Rgb onCameraOpened: cameraId = $cameraId, displayOrientation = $displayOrientation")
Timber.tag(TAG)
.d("initRgbCamera Rgb onCameraOpened: cameraId = $cameraId, displayOrientation = $displayOrientation")
activity.runOnUiThread({
val previewSizeRgb = camera.getParameters().getPreviewSize()
val layoutParams = adjustPreviewViewSize(
@@ -397,8 +352,10 @@ class FacePayPresentation(
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 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(
@@ -454,16 +411,19 @@ class FacePayPresentation(
}
override fun onCameraConfigurationChanged(cameraID: Int, displayOrientation: Int) {
Timber.tag(TAG).i("initRgbCamera onCameraConfigurationChanged: threadName = ${Thread.currentThread().name}")
Timber.tag(TAG)
.i("initRgbCamera onCameraConfigurationChanged: threadName = ${Thread.currentThread().name}")
if (rgbFaceRectTransformer != null) {
rgbFaceRectTransformer!!.cameraDisplayOrientation = displayOrientation
}
Timber.tag(TAG).i("initRgbCamera onCameraConfigurationChanged: $cameraID $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=$measuredWidthmeasuredHeight=$measuredHeight")
Timber.tag(TAG)
.i("initRgbCamera measuredWidth=$measuredWidthmeasuredHeight=$measuredHeight")
val previewConfig: PreviewConfig = recognizeViewModel.previewConfig
rgbCameraHelper = DualCameraHelper.Builder()
@@ -498,7 +458,8 @@ class FacePayPresentation(
displayOrientation: Int,
isMirror: Boolean
) {
Timber.tag(TAG).d("initIrCamera IR onCameraOpened: cameraId = $cameraId, displayOrientation = $displayOrientation")
Timber.tag(TAG)
.d("initIrCamera IR onCameraOpened: cameraId = $cameraId, displayOrientation = $displayOrientation")
val previewSizeIr = camera.getParameters().getPreviewSize()
val layoutParams = adjustPreviewViewSize(
binding.dualCameraTexturePreviewRgb,
@@ -539,7 +500,8 @@ class FacePayPresentation(
if (irFaceRectTransformer != null) {
irFaceRectTransformer!!.cameraDisplayOrientation = displayOrientation
}
Timber.tag(TAG).i("initIrCamera onCameraConfigurationChanged: cameraID = $cameraID, displayOrientation = $displayOrientation")
Timber.tag(TAG)
.i("initIrCamera onCameraConfigurationChanged: cameraID = $cameraID, displayOrientation = $displayOrientation")
}
}
@@ -600,8 +562,10 @@ class FacePayPresentation(
}
}
}
private var lastFaceTrackId: Int = -1 // 上一次的人脸信息
private var mDialogWaiting: CustomDialog? = null
/**
* 显示等待提示框
*/
@@ -627,4 +591,49 @@ class FacePayPresentation(
super.onDisplayRemoved()
onDismissListener()
}
private fun faceRecSuccess(userId: String) {
activity.runOnUiThread {
showWaitingDialog("加载中,请稍后……")
}
getMemberInfo(userId) { memberInfo ->
bindOrder(userId) {
binding.root.postDelayed({
hideWaitingDialog()
activity.showPayInfo(type = 1, isVip = true, memberInfo = memberInfo)
binding.root.postDelayed({
dismiss()
}, 500)
}, 1500)
}
}
}
private fun bindOrder(userId:String, block:()-> Unit) {
userViewModel.bindOrder(userId, activity.foodOrderId) { bindResult ->
activity.runOnUiThread {
if (bindResult.not()) {
hideWaitingDialog()
ToastUtils.showToast("订单绑定失败")
return@runOnUiThread
}
block()
}
}
}
private fun getMemberInfo(userId: String, block:(MemberInfo)-> Unit) {
userViewModel.getMemberInfo(memberId = userId) { memberInfo ->
activity.runOnUiThread {
if (memberInfo == null) {
hideWaitingDialog()
ToastUtils.showToast("查询会员信息失败,请稍后重试")
return@runOnUiThread
}
block(memberInfo)
}
}
}
}
@@ -4,11 +4,14 @@ import com.sw.dualscreen.GlobalData
import com.sw.dualscreen.model.request.UserNutritionParam
import com.sw.dualscreen.model.response.ApiResponse
import com.sw.dualscreen.model.response.DinnerType
import com.sw.dualscreen.model.response.FaceData
import com.sw.dualscreen.model.response.FoodInfo
import com.sw.dualscreen.model.response.FoodSearchReq
import com.sw.dualscreen.model.response.FoodOrder
import com.sw.dualscreen.model.response.MemberInfo
import com.sw.dualscreen.model.response.PayResult
import com.sw.dualscreen.model.response.UserFaceModel
import com.sw.dualscreen.model.response.UserNutrition
import com.sw.dualscreen.model.response.UserNutritionData
import com.sw.dualscreen.network.api.ApiService
import com.sw.dualscreen.objbox.CollectedFoodInfo
@@ -73,6 +76,18 @@ class RemoteRepository constructor(
}
}
suspend fun getUserFaceCache2(
pageNum: Int,
pageSize: Int = 160,
): ApiResponse<FaceData> {
return safeApiCall {
apiService.getUserFaceCache2(
pageNum = pageNum,
pageSize = pageSize
)
}
}
/**
* 获取人脸数据
*/
@@ -107,16 +122,38 @@ class RemoteRepository constructor(
}
}
// /**
// * 通过用户信息获取就餐数据
// */
// suspend fun getUserNutritionData(
// restId: String = GlobalData.restId,
// userId: String,
// foodId: String,
// ): ApiResponse<UserNutritionData> {
// return safeApiCall {
// apiService.getUserNutritionData(restId = restId, userId = userId, foodId = foodId)
// }
// }
/**
* 通过用户信息获取就餐数据
*/
suspend fun getUserNutritionData(
restId: String = GlobalData.restId,
userId: String,
foodId: String,
): ApiResponse<UserNutritionData> {
suspend fun getUserNutritionData(userId: String): ApiResponse<UserNutrition> {
return safeApiCall {
apiService.getUserNutritionData(restId = restId, userId = userId, foodId = foodId)
apiService.getUserNutritionData(userId = userId)
}
}
/**
* 获取支付二维码
*/
suspend fun getQrCodeImg(
orderNo: String,
memberId: String? = null,
totalFee: String? = null
): ApiResponse<String?> {
return safeApiCall {
apiService.getQrCodeImg(orderNo = orderNo, memberId = memberId, totalFee = totalFee)
}
}
@@ -150,12 +187,42 @@ class RemoteRepository constructor(
}
}
/**
* 创建订单
*/
suspend fun createOrder(order: FoodOrder): ApiResponse<Any?> {
return safeApiCall {
apiService.createOrder(order = order)
}
}
/**
* 现金支付
*/
suspend fun cashPay(param: HashMap<String, String>): ApiResponse<Boolean?> {
return safeApiCall {
apiService.cashPay(param = param)
}
}
/**
* 查询订单状态
*/
suspend fun queryOrderState(param: HashMap<String, String>): ApiResponse<PayResult?> {
return safeApiCall {
apiService.queryOrderState(param = param)
}
}
/**
* 会员支付
*/
suspend fun memberPay(param: HashMap<String, String>): ApiResponse<Any?> {
return safeApiCall {
apiService.memberPay(param = param)
}
}
suspend fun bindOrder(userId: String, orderId: String): ApiResponse<Any?> {
return safeApiCall {
apiService.bindOrder(userId = userId, orderId = orderId)
@@ -10,20 +10,19 @@ import com.sw.dualscreen.model.response.TextBean
object SpannedUtils {
const val SPAN_FLAGS = Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
public fun getAmountText(list: List<TextBean>): SpannedString {
return buildSpannedString {
list.forEach {
append(
it.text,
AbsoluteSizeSpan(it.textSize, true),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
val start = length
append(it.text)
val end = length
if (it.textSize != 0) {
setSpan(AbsoluteSizeSpan(it.textSize, true), start, end, SPAN_FLAGS)
}
if (it.textColor.isNullOrBlank().not()) {
append(
it.text,
ForegroundColorSpan(it.textColor!!.toColorInt()),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
setSpan(ForegroundColorSpan(it.textColor!!.toColorInt()), start, end, SPAN_FLAGS)
}
}
}
@@ -56,7 +56,7 @@ abstract class BaseViewModel() : ViewModel() {
if (code == "00000" || code == "200" || code == "0") {
return true
}
val message = response.message?:response.msg
val message = response.msg
Timber.d("msg = ${message}, code = $code")
ToastUtils.showToast("${message}(${code})")
return false
@@ -10,7 +10,10 @@ import com.sw.dualscreen.model.response.DinnerType
import com.sw.dualscreen.model.response.FoodInfo
import com.sw.dualscreen.model.response.FoodOrder
import com.sw.dualscreen.model.response.MemberInfo
import com.sw.dualscreen.model.response.PayResult
import com.sw.dualscreen.model.response.UserFaceModel
import com.sw.dualscreen.model.response.UserFaceModel2
import com.sw.dualscreen.model.response.UserNutrition
import com.sw.dualscreen.model.response.UserNutritionData
import com.sw.dualscreen.objbox.CollectedFoodInfo
import com.sw.dualscreen.utils.GsonUtils
@@ -94,7 +97,7 @@ class UserViewModel : BaseViewModel() {
// 获取成功一次后缓存状态
SPUtil.getInstance().put(GlobalKey.KEY_FIRST_RUN, true)
withContext(Dispatchers.Default) {
val list: List<UserFaceModel> = response.result ?: emptyList()
val list: List<UserFaceModel> = response.data ?: emptyList()
val item = list.firstOrNull { it.userId == "1951105919342936066" }
Timber.tag(TAG).d("getUserFaceCache userId = ${item?.userId}")
val faceEntity = list.map {
@@ -119,6 +122,31 @@ class UserViewModel : BaseViewModel() {
}
}
fun getUserFaceCache2(index: Int = 0) {
Timber.d("getUserFaceCache index = $index")
launch {
_loadFaceResult.value = false
val response = repository.getUserFaceCache2(index)
if (parseResponse(response)) {
// 获取成功一次后缓存状态
SPUtil.getInstance().put(GlobalKey.KEY_FIRST_RUN, true)
withContext(Dispatchers.Default) {
val list: List<UserFaceModel2> = response.result?.records ?: emptyList()
val faceEntity = list.map {
FaceEntity(it.userId, null, Base64.decode(it.face))
}
faceApi.updateFaceData2(index, faceEntity)
}
val nextPageIndex = response.result?.nextPageIndex ?: -1
if (nextPageIndex > 0) {
getUserFaceCache2(nextPageIndex)
} else {
_loadFaceResult.value = true
}
}
}
}
fun getCollectedFoodList(
pageNo: Int = 1,
pageSize: Int = 100,
@@ -130,7 +158,7 @@ class UserViewModel : BaseViewModel() {
val response = repository.getCollectedFoodList(pageNum = pageNo, pageSize = pageSize, foodName = foodName)
if (parseResponse(response)) {
withContext(Dispatchers.Default) {
val list: List<CollectedFoodInfo> = response.result ?: emptyList()
val list: List<CollectedFoodInfo> = response.data ?: emptyList()
block(list)
}
}
@@ -199,9 +227,9 @@ class UserViewModel : BaseViewModel() {
launchWithLoading {
val response = repository.getRestInfoFoodsByType(foodName = foodName)
if (parseResponse(response)) {
val list = response.result ?: emptyList()
val list = response.data ?: emptyList()
action(list)
_identifiedFoodInfoList.value = response.result ?: emptyList()
_identifiedFoodInfoList.value = response.data ?: emptyList()
}
}
}
@@ -211,16 +239,46 @@ class UserViewModel : BaseViewModel() {
_searchFoodInfoList.value = emptyList<FoodInfo>()
}
// /**
// * 获取用户就餐数据
// */
// fun getUserNutritionData(userId: String, foodId: String) {
// Timber.tag(TAG).d("getUserNutritionData userId = ${userId}, foodId = $foodId")
// _nutritionData.value = null
// launch {
// val response = repository.getUserNutritionData(userId = userId, foodId = foodId)
// if (parseResponse(response)) {
// _nutritionData.value = response.result
// }
// }
// }
/**
* 获取用户就餐数据
*/
fun getUserNutritionData(userId: String, foodId: String) {
Timber.tag(TAG).d("getUserNutritionData userId = ${userId}, foodId = $foodId")
_nutritionData.value = null
fun getUserNutritionData(userId: String, block: (UserNutrition?) -> Unit) {
Timber.tag(TAG).d("getUserNutritionData userId = $userId")
launch {
val response = repository.getUserNutritionData(userId = userId, foodId = foodId)
val response = repository.getUserNutritionData(userId = userId)
if (parseResponse(response)) {
_nutritionData.value = response.result
block(response.data)
} else {
block(null)
}
}
}
/**
* 获取用户就餐数据
*/
fun getQrCodeImg(orderId: String, userId: String?=null, block: (String?) -> Unit) {
Timber.tag(TAG).d("getQrCodeImg orderId = $orderId, userId = $userId")
launch {
val response = repository.getQrCodeImg(orderNo = orderId, memberId = userId)
if (parseResponse(response)) {
block(response.data)
} else {
block(null)
}
}
}
@@ -231,7 +289,7 @@ class UserViewModel : BaseViewModel() {
launch {
val response = repository.getDinnerType()
if (parseResponse(response)) {
_dinnerTypeInfo.value = response.result
_dinnerTypeInfo.value = response.data
}
}
}
@@ -254,7 +312,7 @@ class UserViewModel : BaseViewModel() {
launchWithLoading {
val response = repository.getFoodInfo(foodName = foodName)
if (parseResponse(response)) {
val list = response.result ?: emptyList()
val list = response.data ?: emptyList()
_identifiedFoodInfoList.value = list
action(list)
} else {
@@ -275,6 +333,90 @@ class UserViewModel : BaseViewModel() {
}
}
/**
* 现金支付
*/
fun cashPay(param: HashMap<String, String>, block:(Boolean)-> Unit) {
Timber.tag(TAG).d("cashPay")
launchWithLoading {
val response = repository.cashPay(param)
if (parseResponse(response)) {
block(response.data?:false)
} else {
block(false)
}
}
}
/**
* 查询订单状态
*
* @param queryType 查询类型 1支付2退款
* @param orderId 订单号
*/
fun queryOrderState(queryType:Int, orderId:String, block:(PayResult?)-> Unit) {
Timber.tag(TAG).d("queryOrderState")
val param = hashMapOf(
"queryType" to "$queryType",
"payOrderNo" to orderId
)
launchWithLoading {
val response = repository.queryOrderState(param)
if (parseResponse(response)) {
block(response.data)
} else {
block(null)
}
}
}
/**
* 扫码成功回调
*
* @param queryType 查询类型 1支付2退款
* @param orderId 订单号
*/
fun paySuccessCallback(queryType:Int, orderId:String, block:()-> Unit) {
Timber.tag(TAG).d("paySuccessCallback")
val param = hashMapOf(
"queryType" to "$queryType",
"payOrderNo" to orderId
)
launchWithLoading {
var orderState = false
while (orderState.not()) {
val response = repository.queryOrderState(param)
if (parseResponse(response)) {
orderState = response.data?.paySuc == "1"
if (orderState) {
block()
}
}else {
orderState = false
}
}
}
}
/**
* 会员支付
*/
fun memberPay(param: HashMap<String, String>, block:(Boolean)-> Unit) {
Timber.tag(TAG).d("memberPay")
launchWithLoading {
val response = repository.memberPay(param)
if (parseResponse(response)) {
block(true)
} else {
block(false)
}
}
}
/**
* 绑定订单
*/
fun bindOrder(userId: String, orderId: String, block:(Boolean)-> Unit){
Timber.tag(TAG).d("bindOrder")
launchWithLoading {
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 876 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 914 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 863 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 829 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 925 B

+2 -1
View File
@@ -90,7 +90,8 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="27dp"
android:background="@drawable/preview_border" />
android:background="@drawable/ic_camera_rect" />
<!-- preview_border-->
</FrameLayout>
<androidx.recyclerview.widget.RecyclerView
+2 -2
View File
@@ -17,8 +17,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="30dp"
android:layout_marginBottom="90dp"
android:layout_marginTop="20dp"
android:layout_marginBottom="70dp"
android:textColor="#ff0a1428"
android:textSize="60sp"
android:textStyle="bold"
+2 -1
View File
@@ -4,8 +4,9 @@
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="240dp"
android:layout_width="wrap_content"
android:layout_height="80dp"
android:paddingHorizontal="20dp"
android:background="@drawable/dialog_waiting">
@@ -25,4 +25,21 @@
android:textColor="#ffff3232"
android:textSize="36sp"
android:textStyle="bold" />
<Space
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btnConfirmPayFinish"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginHorizontal="32dp"
android:layout_marginBottom="20dp"
android:background="@drawable/bg_btn_save2"
android:text="已支付确认"
android:enabled="true"
android:textColor="@color/white"
android:textSize="40sp" />
</LinearLayout>
@@ -9,6 +9,7 @@
tools:background="#FFF4FAFF">
<androidx.cardview.widget.CardView
android:id="@+id/layoutMemberInfo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardBackgroundColor="@color/white"
@@ -146,9 +147,9 @@
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btnConfirmPay"
android:layout_width="match_parent"
android:layout_height="120dp"
android:layout_height="100dp"
android:layout_marginHorizontal="32dp"
android:layout_marginBottom="32dp"
android:layout_marginBottom="20dp"
android:background="@drawable/bg_btn_save2"
android:text="确认支付"
android:enabled="true"
@@ -79,6 +79,7 @@
android:id="@+id/ivPreviewImage"
android:layout_width="match_parent"
android:layout_height="456dp"
android:scaleType="centerCrop"
app:shapeAppearance="@style/round10dpCornerStyle"
tools:background="@mipmap/ic_launcher"/>
@@ -86,6 +87,7 @@
android:id="@+id/ivRecImage"
android:layout_width="match_parent"
android:layout_height="456dp"
android:scaleType="centerCrop"
tools:background="@mipmap/ic_launcher_round"
app:shapeAppearance="@style/round10dpCornerStyle"
android:visibility="gone"/>
@@ -231,8 +233,8 @@
<FrameLayout
android:id="@+id/flRecognizeIr"
android:layout_width="1.3333dp"
android:layout_height="1dp"
android:layout_width="133.33dp"
android:layout_height="100dp"
android:layout_gravity="bottom"
android:visibility="gone">
@@ -39,6 +39,16 @@ public class FaceApi {
faceDao.insert(list);
}
public void updateFaceData2(int index, List<FaceEntity> list) {
Log.d(TAG, "updateFaceData: index = " + index + ", listSize = " + list.size());
FaceDao faceDao = FaceDatabase.getInstance(App.getContext()).faceDao();
if (index == 0) {
faceDao.deleteAll();
faceDao.resetId();
}
faceDao.insert(list);
}
/**
* 激活arcsoft 人脸
*
@@ -283,6 +283,7 @@ public class RecognizeViewModel extends ViewModel implements RecognizeCallback {
}
// 填入在设置界面设置好的配置信息
boolean enableLive = !ConfigUtil.getLivenessDetectType(context).equals(context.getString(R.string.value_liveness_type_disable));
// enableLive = false;
boolean enableFaceQualityDetect = ConfigUtil.isEnableImageQualityDetect(context);
boolean enableFaceMoveLimit = ConfigUtil.isEnableFaceMoveLimit(context);
boolean enableFaceSizeLimit = ConfigUtil.isEnableFaceSizeLimit(context);