实现了热量值计算
This commit is contained in:
@@ -54,6 +54,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
private var checkedItem: FoodInfo? = null
|
private var checkedItem: FoodInfo? = null
|
||||||
private var imageAnalysis: ImageAnalysis? = null
|
private var imageAnalysis: ImageAnalysis? = null
|
||||||
private var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>? = null
|
private var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>? = null
|
||||||
|
private var canIdentify: Boolean = true
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@@ -156,14 +157,15 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
viewModel.getIdentifiedFoodList()
|
viewModel.getIdentifiedFoodList()
|
||||||
// SensorScaleUtils.startScale { weight ->
|
SensorScaleUtils.startScale { weight ->
|
||||||
// Timber.d("weight = $weight")
|
// Timber.d("weight = $weight")
|
||||||
// if (weight > 0.0) {
|
if (weight > 0.0) {
|
||||||
// if (canIndentify) {
|
if (canIdentify) {
|
||||||
// viewModel.getIdentifiedFoodList()
|
canIdentify = false
|
||||||
// }
|
viewModel.getIdentifiedFoodList()
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createAdapter(): GenericItemAdapter<FoodInfo, ItemFoodInfoBinding> {
|
private fun createAdapter(): GenericItemAdapter<FoodInfo, ItemFoodInfoBinding> {
|
||||||
|
|||||||
@@ -55,6 +55,8 @@ val Float.sp: Float
|
|||||||
Resources.getSystem().displayMetrics
|
Resources.getSystem().displayMetrics
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun Double.format2String(): String = "%.1f".format(this)
|
||||||
|
|
||||||
// 添加扩展函数
|
// 添加扩展函数
|
||||||
fun ImageProxy.toSafeBitmap(): Bitmap {
|
fun ImageProxy.toSafeBitmap(): Bitmap {
|
||||||
val yBuffer = planes[0].buffer // Y
|
val yBuffer = planes[0].buffer // Y
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package com.sw.dualscreen.model.response
|
||||||
|
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
data class DinnerTypeInfo(
|
||||||
|
@SerializedName("dinnerType")
|
||||||
|
val dinnerType: DinnerType? = DinnerType()
|
||||||
|
) : Parcelable {
|
||||||
|
@Parcelize
|
||||||
|
data class DinnerType(
|
||||||
|
@SerializedName("createBy")
|
||||||
|
val createBy: String? = "",
|
||||||
|
@SerializedName("createTime")
|
||||||
|
val createTime: String? = "",
|
||||||
|
@SerializedName("delFlag")
|
||||||
|
val delFlag: Int? = 0,
|
||||||
|
@SerializedName("dinnerType")
|
||||||
|
val dinnerType: String? = "",
|
||||||
|
@SerializedName("endTime")
|
||||||
|
val endTime: String? = "",
|
||||||
|
@SerializedName("id")
|
||||||
|
val id: Int? = 0,
|
||||||
|
@SerializedName("isSync")
|
||||||
|
val isSync: Int? = 0,
|
||||||
|
@SerializedName("isSyncCopy")
|
||||||
|
val isSyncCopy: Int? = 0,
|
||||||
|
@SerializedName("restId")
|
||||||
|
val restId: String? = "",
|
||||||
|
@SerializedName("startTime")
|
||||||
|
val startTime: String? = "",
|
||||||
|
@SerializedName("sysOrgCode")
|
||||||
|
val sysOrgCode: String? = "",
|
||||||
|
@SerializedName("updateBy")
|
||||||
|
val updateBy: String? = "",
|
||||||
|
@SerializedName("updateTime")
|
||||||
|
val updateTime: String? = ""
|
||||||
|
) : Parcelable
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package com.sw.dualscreen.model.response
|
|||||||
|
|
||||||
|
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
import android.text.TextUtils
|
||||||
import com.google.gson.annotations.SerializedName
|
import com.google.gson.annotations.SerializedName
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
@@ -206,7 +207,28 @@ data class FoodInfo(
|
|||||||
val vegetable: String? = "",
|
val vegetable: String? = "",
|
||||||
@SerializedName("vegetableRecommend")
|
@SerializedName("vegetableRecommend")
|
||||||
val vegetableRecommend: String? = ""
|
val vegetableRecommend: String? = ""
|
||||||
) : Parcelable
|
) : Parcelable {
|
||||||
|
|
||||||
|
fun fruitsValue(): Double =
|
||||||
|
if (TextUtils.isEmpty(fruits))
|
||||||
|
0.0
|
||||||
|
else fruits!!.toDouble()
|
||||||
|
|
||||||
|
fun grainValue(): Double =
|
||||||
|
if (TextUtils.isEmpty(grain))
|
||||||
|
0.0
|
||||||
|
else grain!!.toDouble()
|
||||||
|
|
||||||
|
fun vegetableValue(): Double =
|
||||||
|
if (TextUtils.isEmpty(vegetable))
|
||||||
|
0.0
|
||||||
|
else vegetable!!.toDouble()
|
||||||
|
|
||||||
|
fun meatValue(): Double =
|
||||||
|
if (TextUtils.isEmpty(meat))
|
||||||
|
0.0
|
||||||
|
else meat!!.toDouble()
|
||||||
|
}
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class StFoodInfoSetting(
|
data class StFoodInfoSetting(
|
||||||
|
|||||||
+106
-2
@@ -2,6 +2,7 @@ package com.sw.dualscreen.model.response
|
|||||||
|
|
||||||
|
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
import android.text.TextUtils
|
||||||
import com.google.gson.annotations.SerializedName
|
import com.google.gson.annotations.SerializedName
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
@@ -9,69 +10,172 @@ import kotlinx.parcelize.Parcelize
|
|||||||
* 就餐数据
|
* 就餐数据
|
||||||
*/
|
*/
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class NutritionData(
|
data class UserNutritionData(
|
||||||
|
/**
|
||||||
|
* 总胆固醇
|
||||||
|
*/
|
||||||
@SerializedName("cho")
|
@SerializedName("cho")
|
||||||
val cho: String? = "",
|
val cho: String? = "",
|
||||||
|
/**
|
||||||
|
* 饮食纤维
|
||||||
|
*/
|
||||||
@SerializedName("dietFiber")
|
@SerializedName("dietFiber")
|
||||||
val dietFiber: String? = "",
|
val dietFiber: String? = "",
|
||||||
|
/**
|
||||||
|
* 能量
|
||||||
|
*/
|
||||||
@SerializedName("energy")
|
@SerializedName("energy")
|
||||||
val energy: String? = "",
|
val energy: String? = "",
|
||||||
|
/**
|
||||||
|
* 脂肪
|
||||||
|
*/
|
||||||
@SerializedName("fat")
|
@SerializedName("fat")
|
||||||
val fat: String? = "",
|
val fat: String? = "",
|
||||||
|
/**
|
||||||
|
* 食物类型和实际摄入量清单
|
||||||
|
*/
|
||||||
@SerializedName("foodTypeAndRealIntakeVoList")
|
@SerializedName("foodTypeAndRealIntakeVoList")
|
||||||
val foodTypeAndRealIntakeVoList: List<String?>? = listOf(),
|
val foodTypeAndRealIntakeVoList: List<String?>? = listOf(),
|
||||||
@SerializedName("foodWeight")
|
@SerializedName("foodWeight")
|
||||||
val foodWeight: String? = "",
|
val foodWeight: String? = "",
|
||||||
@SerializedName("message")
|
@SerializedName("message")
|
||||||
val message: String? = "",
|
val message: String? = "",
|
||||||
|
/**
|
||||||
|
* 钠
|
||||||
|
*/
|
||||||
@SerializedName("na")
|
@SerializedName("na")
|
||||||
val na: String? = "",
|
val na: String? = "",
|
||||||
|
/**
|
||||||
|
* 蛋白质
|
||||||
|
*/
|
||||||
@SerializedName("protein")
|
@SerializedName("protein")
|
||||||
val protein: String? = "",
|
val protein: String? = "",
|
||||||
|
/**
|
||||||
|
* 最大推荐热量
|
||||||
|
*/
|
||||||
@SerializedName("recommendMax")
|
@SerializedName("recommendMax")
|
||||||
val recommendMax: String? = "",
|
val recommendMax: String? = "",
|
||||||
|
/**
|
||||||
|
* 最小推荐热量
|
||||||
|
*/
|
||||||
@SerializedName("recommendMin")
|
@SerializedName("recommendMin")
|
||||||
val recommendMin: String? = "",
|
val recommendMin: String? = "",
|
||||||
|
/**
|
||||||
|
* 热量详情
|
||||||
|
*/
|
||||||
@SerializedName("stFoodInfoPagoda")
|
@SerializedName("stFoodInfoPagoda")
|
||||||
val stFoodInfoPagoda: StFoodInfoPagoda? = StFoodInfoPagoda(),
|
val stFoodInfoPagoda: StFoodInfoPagoda? = StFoodInfoPagoda(),
|
||||||
@SerializedName("stUserFoodInfoList")
|
@SerializedName("stUserFoodInfoList")
|
||||||
val stUserFoodInfoList: List<String?>? = listOf(),
|
val stUserFoodInfoList: List<String?>? = listOf(),
|
||||||
|
/**
|
||||||
|
* 每日总热量
|
||||||
|
*/
|
||||||
@SerializedName("totalEnergyCalculateScore")
|
@SerializedName("totalEnergyCalculateScore")
|
||||||
val totalEnergyCalculateScore: String? = "",
|
val totalEnergyCalculateScore: String? = "",
|
||||||
|
/**
|
||||||
|
* 用户所在部门
|
||||||
|
*/
|
||||||
@SerializedName("userDept")
|
@SerializedName("userDept")
|
||||||
val userDept: String? = "",
|
val userDept: String? = "",
|
||||||
|
/**
|
||||||
|
* 用户id
|
||||||
|
*/
|
||||||
@SerializedName("userId")
|
@SerializedName("userId")
|
||||||
val userId: String? = "",
|
val userId: String? = "",
|
||||||
|
/**
|
||||||
|
* 姓名
|
||||||
|
*/
|
||||||
@SerializedName("userName")
|
@SerializedName("userName")
|
||||||
val userName: String? = ""
|
val userName: String? = ""
|
||||||
) : Parcelable {
|
) : Parcelable {
|
||||||
|
fun recommendMaxValue(): Double =
|
||||||
|
if (TextUtils.isEmpty(recommendMax)) 0.0
|
||||||
|
else recommendMax!!.toDouble()
|
||||||
|
|
||||||
|
fun recommendMinValue(): Double =
|
||||||
|
if (TextUtils.isEmpty(recommendMin)) 0.0
|
||||||
|
else recommendMin!!.toDouble()
|
||||||
|
|
||||||
|
fun energyValue(): Double =
|
||||||
|
if (TextUtils.isEmpty(energy)) 0.0
|
||||||
|
else energy!!.toDouble()
|
||||||
|
|
||||||
|
fun totalEnergyCalculateScoreValue(): Double =
|
||||||
|
if (TextUtils.isEmpty(totalEnergyCalculateScore)) 0.0
|
||||||
|
else totalEnergyCalculateScore!!.toDouble()
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class StFoodInfoPagoda(
|
data class StFoodInfoPagoda(
|
||||||
|
/**
|
||||||
|
* 水果
|
||||||
|
*/
|
||||||
@SerializedName("fruits")
|
@SerializedName("fruits")
|
||||||
val fruits: String? = "",
|
val fruits: String? = "",
|
||||||
@SerializedName("fruitsRecommend")
|
@SerializedName("fruitsRecommend")
|
||||||
val fruitsRecommend: String? = "",
|
val fruitsRecommend: String? = "",
|
||||||
|
/**
|
||||||
|
* 粮食
|
||||||
|
*/
|
||||||
@SerializedName("grain")
|
@SerializedName("grain")
|
||||||
val grain: String? = "",
|
val grain: String? = "",
|
||||||
@SerializedName("grainRecommend")
|
@SerializedName("grainRecommend")
|
||||||
val grainRecommend: String? = "",
|
val grainRecommend: String? = "",
|
||||||
|
/**
|
||||||
|
* 肉
|
||||||
|
*/
|
||||||
@SerializedName("meat")
|
@SerializedName("meat")
|
||||||
val meat: String? = "",
|
val meat: String? = "",
|
||||||
@SerializedName("meatRecommend")
|
@SerializedName("meatRecommend")
|
||||||
val meatRecommend: String? = "",
|
val meatRecommend: String? = "",
|
||||||
|
/**
|
||||||
|
* 油
|
||||||
|
*/
|
||||||
@SerializedName("oil")
|
@SerializedName("oil")
|
||||||
val oil: String? = "",
|
val oil: String? = "",
|
||||||
|
/**
|
||||||
|
* 盐
|
||||||
|
*/
|
||||||
@SerializedName("salt")
|
@SerializedName("salt")
|
||||||
val salt: String? = "",
|
val salt: String? = "",
|
||||||
|
/**
|
||||||
|
* 大豆
|
||||||
|
*/
|
||||||
@SerializedName("soya")
|
@SerializedName("soya")
|
||||||
val soya: String? = "",
|
val soya: String? = "",
|
||||||
@SerializedName("soyaRecommend")
|
@SerializedName("soyaRecommend")
|
||||||
val soyaRecommend: String? = "",
|
val soyaRecommend: String? = "",
|
||||||
|
/**
|
||||||
|
* 糖
|
||||||
|
*/
|
||||||
@SerializedName("sugar")
|
@SerializedName("sugar")
|
||||||
val sugar: String? = "",
|
val sugar: String? = "",
|
||||||
|
/**
|
||||||
|
* 蔬菜
|
||||||
|
*/
|
||||||
@SerializedName("vegetable")
|
@SerializedName("vegetable")
|
||||||
val vegetable: String? = "",
|
val vegetable: String? = "",
|
||||||
@SerializedName("vegetableRecommend")
|
@SerializedName("vegetableRecommend")
|
||||||
val vegetableRecommend: String? = ""
|
val vegetableRecommend: String? = ""
|
||||||
) : Parcelable
|
) : Parcelable {
|
||||||
|
fun fruitsValue(): Double =
|
||||||
|
if (TextUtils.isEmpty(fruits))
|
||||||
|
0.0
|
||||||
|
else fruits!!.toDouble()
|
||||||
|
|
||||||
|
fun grainValue(): Double =
|
||||||
|
if (TextUtils.isEmpty(grain))
|
||||||
|
0.0
|
||||||
|
else grain!!.toDouble()
|
||||||
|
|
||||||
|
fun vegetableValue(): Double =
|
||||||
|
if (TextUtils.isEmpty(vegetable))
|
||||||
|
0.0
|
||||||
|
else vegetable!!.toDouble()
|
||||||
|
|
||||||
|
fun meatValue(): Double =
|
||||||
|
if (TextUtils.isEmpty(meat))
|
||||||
|
0.0
|
||||||
|
else meat!!.toDouble()
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -3,10 +3,11 @@ package com.sw.dualscreen.network.api
|
|||||||
import com.sw.dualscreen.GlobalData
|
import com.sw.dualscreen.GlobalData
|
||||||
import com.sw.dualscreen.model.request.UserNutritionParam
|
import com.sw.dualscreen.model.request.UserNutritionParam
|
||||||
import com.sw.dualscreen.model.response.ApiResponse
|
import com.sw.dualscreen.model.response.ApiResponse
|
||||||
|
import com.sw.dualscreen.model.response.DinnerTypeInfo
|
||||||
import com.sw.dualscreen.model.response.EquipmentInfo
|
import com.sw.dualscreen.model.response.EquipmentInfo
|
||||||
import com.sw.dualscreen.model.response.FoodInfo
|
import com.sw.dualscreen.model.response.FoodInfo
|
||||||
import com.sw.dualscreen.model.response.NutritionData
|
|
||||||
import com.sw.dualscreen.model.response.UserFaceInfo
|
import com.sw.dualscreen.model.response.UserFaceInfo
|
||||||
|
import com.sw.dualscreen.model.response.UserNutritionData
|
||||||
import retrofit2.http.Body
|
import retrofit2.http.Body
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
import retrofit2.http.Header
|
import retrofit2.http.Header
|
||||||
@@ -78,7 +79,17 @@ interface ApiService {
|
|||||||
@Query("restId") restId: String,
|
@Query("restId") restId: String,
|
||||||
@Query("userId") userId: String,
|
@Query("userId") userId: String,
|
||||||
@Query("foodId") foodId: String,
|
@Query("foodId") foodId: String,
|
||||||
): ApiResponse<NutritionData>
|
): ApiResponse<UserNutritionData>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前餐点类型
|
||||||
|
*/
|
||||||
|
@GET
|
||||||
|
suspend fun getDinnerType(
|
||||||
|
@Url url: String = "${GlobalData.appBaseUrl}/zhstapi/zhst/getCanteenDinnerType",
|
||||||
|
@Query("appVersion") appVersion: String = GlobalData.appVersion,
|
||||||
|
@Query("canteenId") restId: String,
|
||||||
|
): ApiResponse<DinnerTypeInfo>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 提交就餐数据
|
* 提交就餐数据
|
||||||
|
|||||||
@@ -30,8 +30,13 @@ import com.sw.dualscreen.activity.MainActivity
|
|||||||
import com.sw.dualscreen.databinding.ItemUserNutritionBinding
|
import com.sw.dualscreen.databinding.ItemUserNutritionBinding
|
||||||
import com.sw.dualscreen.databinding.PresentationSecondaryScreenBinding
|
import com.sw.dualscreen.databinding.PresentationSecondaryScreenBinding
|
||||||
import com.sw.dualscreen.ext.dp
|
import com.sw.dualscreen.ext.dp
|
||||||
|
import com.sw.dualscreen.ext.format2String
|
||||||
import com.sw.dualscreen.ext.maskName
|
import com.sw.dualscreen.ext.maskName
|
||||||
|
import com.sw.dualscreen.model.response.DinnerTypeInfo
|
||||||
import com.sw.dualscreen.model.response.FoodInfo
|
import com.sw.dualscreen.model.response.FoodInfo
|
||||||
|
import com.sw.dualscreen.model.response.UserNutritionData
|
||||||
|
import com.sw.dualscreen.sdk.SensorScaleUtils
|
||||||
|
import com.sw.dualscreen.utils.Debouncer
|
||||||
import com.sw.dualscreen.utils.GlideUtils
|
import com.sw.dualscreen.utils.GlideUtils
|
||||||
import com.sw.dualscreen.viewmodel.UserViewModel
|
import com.sw.dualscreen.viewmodel.UserViewModel
|
||||||
import com.sw.plate.utils.ToastUtils
|
import com.sw.plate.utils.ToastUtils
|
||||||
@@ -70,6 +75,8 @@ class SecondaryScreenPresentation(
|
|||||||
|
|
||||||
// 当前食物信息
|
// 当前食物信息
|
||||||
private var currentFood: FoodInfo? = null
|
private var currentFood: FoodInfo? = null
|
||||||
|
private var userNutritionData: UserNutritionData? = null
|
||||||
|
private var dinnerType: DinnerTypeInfo? = null
|
||||||
private lateinit var itemUserNutritionBinding: ItemUserNutritionBinding
|
private lateinit var itemUserNutritionBinding: ItemUserNutritionBinding
|
||||||
private lateinit var stepChangeCallback: (Int) -> Unit
|
private lateinit var stepChangeCallback: (Int) -> Unit
|
||||||
|
|
||||||
@@ -92,14 +99,16 @@ class SecondaryScreenPresentation(
|
|||||||
viewModel.nutritionData.collect {
|
viewModel.nutritionData.collect {
|
||||||
Timber.d("registerDataChange nutritionData = $it")
|
Timber.d("registerDataChange nutritionData = $it")
|
||||||
if (it == null) return@collect
|
if (it == null) return@collect
|
||||||
|
userNutritionData = it
|
||||||
|
step3()
|
||||||
itemUserNutritionBinding.tvUserName.text = it.userName.maskName()
|
itemUserNutritionBinding.tvUserName.text = it.userName.maskName()
|
||||||
itemUserNutritionBinding.tvRecommendHeat.text =
|
itemUserNutritionBinding.tvRecommendHeat.text =
|
||||||
"推荐热量:${it.recommendMin}-${it.recommendMax}"
|
"推荐热量:${it.recommendMin}-${it.recommendMax}"
|
||||||
|
}
|
||||||
itemUserNutritionBinding.customKcalColumn.setCustomHeight(280, true)
|
}
|
||||||
itemUserNutritionBinding.customFoodColumn.setCustomHeightPercent(1f, true)
|
activity.lifecycleScope.launch {
|
||||||
itemUserNutritionBinding.customVegetableColumn.setCustomHeightPercent(0.5f, true)
|
viewModel.dinnerTypeInfo.collect {
|
||||||
itemUserNutritionBinding.customMeatColumn.setCustomHeightPercent(0f, true)
|
dinnerType = it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -163,6 +172,8 @@ class SecondaryScreenPresentation(
|
|||||||
|
|
||||||
binding.tvBottomTip.visibility = View.VISIBLE
|
binding.tvBottomTip.visibility = View.VISIBLE
|
||||||
itemUserNutritionBinding.clNutritionData.visibility = View.GONE
|
itemUserNutritionBinding.clNutritionData.visibility = View.GONE
|
||||||
|
stopSensorScale()
|
||||||
|
viewModel.getDinnerType()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -211,6 +222,7 @@ class SecondaryScreenPresentation(
|
|||||||
}
|
}
|
||||||
binding.tvFoodInfo.text = currentFood!!.foodName
|
binding.tvFoodInfo.text = currentFood!!.foodName
|
||||||
|
|
||||||
|
startSensorScale()
|
||||||
|
|
||||||
GlideUtils.loadRoundCornerImage(
|
GlideUtils.loadRoundCornerImage(
|
||||||
context,
|
context,
|
||||||
@@ -229,11 +241,82 @@ class SecondaryScreenPresentation(
|
|||||||
itemUserNutritionBinding.clNutritionData.visibility = View.VISIBLE
|
itemUserNutritionBinding.clNutritionData.visibility = View.VISIBLE
|
||||||
|
|
||||||
viewModel.getUserNutritionData(
|
viewModel.getUserNutritionData(
|
||||||
userId = "187c96f7bf294c08bc1d1e57b90a7210",
|
userId = userNutritionData!!.userId!!,
|
||||||
foodId = currentFood!!.id!!
|
foodId = currentFood!!.id!!
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun startSensorScale() {
|
||||||
|
var lastWeight = 0.0
|
||||||
|
val debouncer = Debouncer(1000)
|
||||||
|
SensorScaleUtils.startScale { weight ->
|
||||||
|
if (weight == lastWeight) return@startScale
|
||||||
|
Timber.d("registerDataChange weight = $weight")
|
||||||
|
lastWeight = weight
|
||||||
|
if (currentFood == null) return@startScale
|
||||||
|
if (userNutritionData == null) return@startScale
|
||||||
|
if (dinnerType == null) return@startScale
|
||||||
|
debouncer.debounce {
|
||||||
|
val calcResultInfo = UserNutritionUtils.calculateNutrition(
|
||||||
|
currentFood!!,
|
||||||
|
userNutritionData!!,
|
||||||
|
weight,
|
||||||
|
dinnerType = dinnerType!!.dinnerType!!.dinnerType!!
|
||||||
|
)
|
||||||
|
Timber.d("calcResultInfo = $calcResultInfo")
|
||||||
|
activity.runOnUiThread {
|
||||||
|
val totalKcal = calcResultInfo.totalKcal
|
||||||
|
val grain = calcResultInfo.grain
|
||||||
|
val fruits = calcResultInfo.fruits
|
||||||
|
val meat = calcResultInfo.meat
|
||||||
|
itemUserNutritionBinding.customKcalColumn.setImageDrawable(
|
||||||
|
true,
|
||||||
|
totalKcal.first < totalKcal.second
|
||||||
|
)
|
||||||
|
itemUserNutritionBinding.totalKcalTv.text = totalKcal.second.format2String()
|
||||||
|
itemUserNutritionBinding.customKcalColumn.setCustomHeightPercent(
|
||||||
|
(totalKcal.second / 100).toFloat(),
|
||||||
|
true
|
||||||
|
)
|
||||||
|
|
||||||
|
itemUserNutritionBinding.customFoodColumn.setImageDrawable(
|
||||||
|
false,
|
||||||
|
grain.first < grain.second
|
||||||
|
)
|
||||||
|
itemUserNutritionBinding.totalFoodTv.text = grain.second.format2String()
|
||||||
|
itemUserNutritionBinding.customFoodColumn.setCustomHeightPercent(
|
||||||
|
(grain.second / 100).toFloat(),
|
||||||
|
true
|
||||||
|
)
|
||||||
|
|
||||||
|
itemUserNutritionBinding.customVegetableColumn.setImageDrawable(
|
||||||
|
false,
|
||||||
|
fruits.first < fruits.second
|
||||||
|
)
|
||||||
|
itemUserNutritionBinding.totalVegetableTv.text = fruits.second.format2String()
|
||||||
|
itemUserNutritionBinding.customVegetableColumn.setCustomHeightPercent(
|
||||||
|
(fruits.second / 100).toFloat(),
|
||||||
|
true
|
||||||
|
)
|
||||||
|
|
||||||
|
itemUserNutritionBinding.customMeatColumn.setImageDrawable(
|
||||||
|
false,
|
||||||
|
meat.first < meat.second
|
||||||
|
)
|
||||||
|
itemUserNutritionBinding.totalMeatTv.text = meat.second.format2String()
|
||||||
|
itemUserNutritionBinding.customMeatColumn.setCustomHeightPercent(
|
||||||
|
(meat.second / 100).toFloat(),
|
||||||
|
true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun stopSensorScale() {
|
||||||
|
SensorScaleUtils.closeScale()
|
||||||
|
}
|
||||||
|
|
||||||
private fun openCamera(cameraId: String) {
|
private fun openCamera(cameraId: String) {
|
||||||
if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) !=
|
if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) !=
|
||||||
PackageManager.PERMISSION_GRANTED
|
PackageManager.PERMISSION_GRANTED
|
||||||
@@ -328,7 +411,8 @@ class SecondaryScreenPresentation(
|
|||||||
|
|
||||||
recognizeViewModel.recognizeUserId.observe(activity, Observer { userId: String? ->
|
recognizeViewModel.recognizeUserId.observe(activity, Observer { userId: String? ->
|
||||||
Timber.i("recognizeUserId observe userId = $userId")
|
Timber.i("recognizeUserId observe userId = $userId")
|
||||||
// viewModel.getUserInfoById(memberId = userId?.toInt() ?: 0)
|
if (userId == null) return@Observer
|
||||||
|
viewModel.getUserNutritionData(userId = userId, foodId = currentFood!!.id!!)
|
||||||
})
|
})
|
||||||
|
|
||||||
recognizeViewModel.drawRectInfoText.observe(activity, Observer { info ->
|
recognizeViewModel.drawRectInfoText.observe(activity, Observer { info ->
|
||||||
@@ -534,7 +618,7 @@ class SecondaryScreenPresentation(
|
|||||||
rgbCameraHelper!!.release()
|
rgbCameraHelper!!.release()
|
||||||
rgbCameraHelper = null
|
rgbCameraHelper = null
|
||||||
}
|
}
|
||||||
|
SensorScaleUtils.closeScale()
|
||||||
recognizeViewModel.destroy()
|
recognizeViewModel.destroy()
|
||||||
super.onStop()
|
super.onStop()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package com.sw.dualscreen.presentation
|
||||||
|
|
||||||
|
|
||||||
|
import android.text.TextUtils
|
||||||
|
import com.sw.dualscreen.model.response.FoodInfo
|
||||||
|
import com.sw.dualscreen.model.response.UserNutritionData
|
||||||
|
|
||||||
|
object UserNutritionUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算热量信息
|
||||||
|
*/
|
||||||
|
fun calculateNutrition(
|
||||||
|
foodInfo: FoodInfo,
|
||||||
|
userModel: UserNutritionData,
|
||||||
|
weight: Double,
|
||||||
|
dinnerType: String
|
||||||
|
): CalcResultInfo {
|
||||||
|
// 1. 初始化变量
|
||||||
|
var foodKcal = 0.0
|
||||||
|
var totalKcal = 0.0
|
||||||
|
var (vegetable, meat, fruits, grain) = List(4) { 0.0 }
|
||||||
|
|
||||||
|
// 2. 处理食物信息
|
||||||
|
foodKcal = calculateValue(foodInfo.stFoodInfoMaterial?.energyKcal, 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)
|
||||||
|
|
||||||
|
// 3. 合并用户数据
|
||||||
|
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()
|
||||||
|
val fruitsAndVeg = fruits + vegetable
|
||||||
|
|
||||||
|
// 4. 判断当餐最大热量
|
||||||
|
val maxKcal =
|
||||||
|
userModel.totalEnergyCalculateScoreValue() * calculateDinnerTypeRatio(dinnerType) / 10
|
||||||
|
|
||||||
|
val pagoda = userModel.stFoodInfoPagoda
|
||||||
|
val calcResult = CalcResultInfo(
|
||||||
|
totalKcal = maxKcal to totalKcal,
|
||||||
|
grain = parseMax(pagoda?.grainRecommend) to grain,
|
||||||
|
fruits = parseMax(pagoda?.fruitsRecommend) + parseMax(pagoda?.vegetableRecommend) to fruitsAndVeg,
|
||||||
|
meat = parseMax(pagoda?.meatRecommend) to meat
|
||||||
|
)
|
||||||
|
return calcResult
|
||||||
|
}
|
||||||
|
|
||||||
|
fun parseMax(recommend: String?): Double {
|
||||||
|
if (TextUtils.isEmpty(recommend) || !recommend!!.contains("-")) return 0.0
|
||||||
|
val (min, max) = recommend.split("-")
|
||||||
|
return max.toDouble()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun calculateDinnerTypeRatio(dinnerType: String): Int {
|
||||||
|
return when (dinnerType) {
|
||||||
|
"早餐", "晚餐" -> 3
|
||||||
|
"午餐" -> 4
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun calculateValue(nutrient: Double?, weight: Double): Double {
|
||||||
|
return weight * (nutrient ?: 1.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
data class CalcResultInfo(
|
||||||
|
var totalKcal: Pair<Double, Double>,
|
||||||
|
var grain: Pair<Double, Double>,
|
||||||
|
var fruits: Pair<Double, Double>,
|
||||||
|
var meat: Pair<Double, Double>,
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -3,10 +3,11 @@ package com.sw.dualscreen.repository
|
|||||||
import com.sw.dualscreen.GlobalData
|
import com.sw.dualscreen.GlobalData
|
||||||
import com.sw.dualscreen.model.request.UserNutritionParam
|
import com.sw.dualscreen.model.request.UserNutritionParam
|
||||||
import com.sw.dualscreen.model.response.ApiResponse
|
import com.sw.dualscreen.model.response.ApiResponse
|
||||||
|
import com.sw.dualscreen.model.response.DinnerTypeInfo
|
||||||
import com.sw.dualscreen.model.response.EquipmentInfo
|
import com.sw.dualscreen.model.response.EquipmentInfo
|
||||||
import com.sw.dualscreen.model.response.FoodInfo
|
import com.sw.dualscreen.model.response.FoodInfo
|
||||||
import com.sw.dualscreen.model.response.NutritionData
|
|
||||||
import com.sw.dualscreen.model.response.UserFaceInfo
|
import com.sw.dualscreen.model.response.UserFaceInfo
|
||||||
|
import com.sw.dualscreen.model.response.UserNutritionData
|
||||||
import com.sw.dualscreen.network.api.ApiService
|
import com.sw.dualscreen.network.api.ApiService
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -80,12 +81,20 @@ class RemoteRepository constructor(
|
|||||||
restId: String = GlobalData.restId,
|
restId: String = GlobalData.restId,
|
||||||
userId: String,
|
userId: String,
|
||||||
foodId: String,
|
foodId: String,
|
||||||
): ApiResponse<NutritionData> {
|
): ApiResponse<UserNutritionData> {
|
||||||
return safeApiCall {
|
return safeApiCall {
|
||||||
apiService.getUserNutritionData(restId = restId, userId = userId, foodId = foodId)
|
apiService.getUserNutritionData(restId = restId, userId = userId, foodId = foodId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun getDinnerType(
|
||||||
|
restId: String = GlobalData.restId,
|
||||||
|
): ApiResponse<DinnerTypeInfo> {
|
||||||
|
return safeApiCall {
|
||||||
|
apiService.getDinnerType(restId = restId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 提交就餐数据
|
* 提交就餐数据
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -143,6 +143,7 @@ object SensorScaleUtils {
|
|||||||
* 关闭称重
|
* 关闭称重
|
||||||
*/
|
*/
|
||||||
fun closeScale() {
|
fun closeScale() {
|
||||||
|
Log.d(TAG, "closeScale")
|
||||||
isOpened = false
|
isOpened = false
|
||||||
mSensorScale?.closeScale()
|
mSensorScale?.closeScale()
|
||||||
mSensorScale == null
|
mSensorScale == null
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
package com.sw.dualscreen.view;
|
package com.sw.dualscreen.view;
|
||||||
|
|
||||||
import android.animation.ValueAnimator;
|
import android.animation.ValueAnimator;
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.animation.AlphaAnimation;
|
import android.view.animation.AlphaAnimation;
|
||||||
|
|
||||||
|
import com.sw.dualscreen.R;
|
||||||
import com.sw.plate.utils.AppUtil;
|
import com.sw.plate.utils.AppUtil;
|
||||||
|
|
||||||
public class CustomImageView extends androidx.appcompat.widget.AppCompatImageView {
|
public class CustomImageView extends androidx.appcompat.widget.AppCompatImageView {
|
||||||
@@ -23,29 +26,37 @@ public class CustomImageView extends androidx.appcompat.widget.AppCompatImageVie
|
|||||||
private static final int MAX_HEIGHT = 280;
|
private static final int MAX_HEIGHT = 280;
|
||||||
|
|
||||||
private boolean isDrawText = false;
|
private boolean isDrawText = false;
|
||||||
|
private Drawable bigRedDrawable;
|
||||||
|
private Drawable bigGreenDrawable;
|
||||||
|
private Drawable redDrawable;
|
||||||
|
private Drawable greenDrawable;
|
||||||
|
|
||||||
public CustomImageView(Context context) {
|
public CustomImageView(Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
init();
|
init(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CustomImageView(Context context, AttributeSet attrs) {
|
public CustomImageView(Context context, AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
init();
|
init(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CustomImageView(Context context, AttributeSet attrs, int defStyleAttr) {
|
public CustomImageView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||||
super(context, attrs, defStyleAttr);
|
super(context, attrs, defStyleAttr);
|
||||||
init();
|
init(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void init() {
|
@SuppressLint("UseCompatLoadingForDrawables")
|
||||||
|
private void init(Context context) {
|
||||||
textToDraw = "超标";
|
textToDraw = "超标";
|
||||||
mPaint = new Paint();//Paint.ANTI_ALIAS_FLAG
|
mPaint = new Paint();//Paint.ANTI_ALIAS_FLAG
|
||||||
mPaint.setColor(Color.WHITE); // Set your desired color
|
mPaint.setColor(Color.WHITE); // Set your desired color
|
||||||
mPaint.setTextSize(mTextSize); // Set your desired text size
|
mPaint.setTextSize(mTextSize); // Set your desired text size
|
||||||
mPaint.setAntiAlias(true);
|
mPaint.setAntiAlias(true);
|
||||||
|
bigRedDrawable = context.getDrawable(R.drawable.img_big_red_column);
|
||||||
|
bigGreenDrawable = context.getDrawable(R.drawable.img_big_green_column);
|
||||||
|
redDrawable = context.getDrawable(R.drawable.img_red_column);
|
||||||
|
greenDrawable = context.getDrawable(R.drawable.img_green_column);
|
||||||
// Typeface typeface = getResources().getFont(R.font.dakai);
|
// Typeface typeface = getResources().getFont(R.font.dakai);
|
||||||
// Typeface typeface = Typeface.create(Typeface.createFromAsset(getContext().getAssets(), "fonts/dakai.TTF"),
|
// Typeface typeface = Typeface.create(Typeface.createFromAsset(getContext().getAssets(), "fonts/dakai.TTF"),
|
||||||
// Typeface.BOLD); // 创建Typeface
|
// Typeface.BOLD); // 创建Typeface
|
||||||
@@ -69,6 +80,20 @@ public class CustomImageView extends androidx.appcompat.widget.AppCompatImageVie
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置图片
|
||||||
|
*
|
||||||
|
* @param isBig 大图
|
||||||
|
* @param isMore 是否超过
|
||||||
|
*/
|
||||||
|
public void setImageDrawable(boolean isBig, boolean isMore) {
|
||||||
|
if (isBig) {
|
||||||
|
setImageDrawable(isMore ? bigRedDrawable : bigGreenDrawable);
|
||||||
|
} else {
|
||||||
|
setImageDrawable(isMore ? redDrawable : greenDrawable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void setCustomHeightPercent(float percent, boolean isAnimation) {
|
public void setCustomHeightPercent(float percent, boolean isAnimation) {
|
||||||
setCustomHeight((int) (percent * MAX_HEIGHT), isAnimation);
|
setCustomHeight((int) (percent * MAX_HEIGHT), isAnimation);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,10 @@ import com.arcsoft.face.ErrorInfo
|
|||||||
import com.sw.dualscreen.GlobalData
|
import com.sw.dualscreen.GlobalData
|
||||||
import com.sw.dualscreen.GlobalKey
|
import com.sw.dualscreen.GlobalKey
|
||||||
import com.sw.dualscreen.model.request.UserNutritionParam
|
import com.sw.dualscreen.model.request.UserNutritionParam
|
||||||
|
import com.sw.dualscreen.model.response.DinnerTypeInfo
|
||||||
import com.sw.dualscreen.model.response.FoodInfo
|
import com.sw.dualscreen.model.response.FoodInfo
|
||||||
import com.sw.dualscreen.model.response.NutritionData
|
|
||||||
import com.sw.dualscreen.model.response.UserFaceModel
|
import com.sw.dualscreen.model.response.UserFaceModel
|
||||||
|
import com.sw.dualscreen.model.response.UserNutritionData
|
||||||
import com.sw.inbound.utils.SPUtil
|
import com.sw.inbound.utils.SPUtil
|
||||||
import com.sw.plate.App
|
import com.sw.plate.App
|
||||||
import com.sw.plate.utils.Base64
|
import com.sw.plate.utils.Base64
|
||||||
@@ -35,8 +36,15 @@ class UserViewModel : BaseViewModel() {
|
|||||||
val searchFoodInfoList: StateFlow<List<FoodInfo>> = _searchFoodInfoList
|
val searchFoodInfoList: StateFlow<List<FoodInfo>> = _searchFoodInfoList
|
||||||
|
|
||||||
// 就餐数据
|
// 就餐数据
|
||||||
private val _nutritionData = MutableStateFlow<NutritionData?>(null)
|
private val _nutritionData = MutableStateFlow<UserNutritionData?>(null)
|
||||||
val nutritionData: StateFlow<NutritionData?> = _nutritionData
|
val nutritionData: StateFlow<UserNutritionData?> = _nutritionData
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 饭点类型
|
||||||
|
*/
|
||||||
|
private val _dinnerTypeInfo = MutableStateFlow<DinnerTypeInfo?>(null)
|
||||||
|
val dinnerTypeInfo: StateFlow<DinnerTypeInfo?> = _dinnerTypeInfo
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取token
|
* 获取token
|
||||||
@@ -179,6 +187,16 @@ class UserViewModel : BaseViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getDinnerType() {
|
||||||
|
Timber.d("getDinnerType")
|
||||||
|
launchWithLoading {
|
||||||
|
val response = repository.getDinnerType()
|
||||||
|
if (parseResponse(response)) {
|
||||||
|
_dinnerTypeInfo.value = response.result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 提交就餐数据
|
* 提交就餐数据
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -76,7 +76,7 @@
|
|||||||
<com.sw.dualscreen.view.CustomImageView
|
<com.sw.dualscreen.view.CustomImageView
|
||||||
android:id="@+id/customKcalColumn"
|
android:id="@+id/customKcalColumn"
|
||||||
android:layout_width="@dimen/dp87"
|
android:layout_width="@dimen/dp87"
|
||||||
android:layout_height="10dp"
|
android:layout_height="0dp"
|
||||||
android:layout_marginBottom="6dp"
|
android:layout_marginBottom="6dp"
|
||||||
android:scaleType="fitXY"
|
android:scaleType="fitXY"
|
||||||
android:src="@drawable/img_big_red_column"
|
android:src="@drawable/img_big_red_column"
|
||||||
|
|||||||
@@ -92,7 +92,7 @@
|
|||||||
|
|
||||||
<style name="takeFoodCustomColumn">
|
<style name="takeFoodCustomColumn">
|
||||||
<item name="android:layout_width">@dimen/dp53</item>
|
<item name="android:layout_width">@dimen/dp53</item>
|
||||||
<item name="android:layout_height">10dp</item>
|
<item name="android:layout_height">0dp</item>
|
||||||
<item name="android:layout_centerHorizontal">true</item>
|
<item name="android:layout_centerHorizontal">true</item>
|
||||||
<!-- <item name="android:layout_marginBottom">-36dp</item>-->
|
<!-- <item name="android:layout_marginBottom">-36dp</item>-->
|
||||||
<item name="android:scaleType">fitXY</item>
|
<item name="android:scaleType">fitXY</item>
|
||||||
|
|||||||
Reference in New Issue
Block a user