This commit is contained in:
2025-12-19 17:34:31 +08:00
parent af56fb4aeb
commit 960b429e69
18 changed files with 294 additions and 181 deletions
+13 -9
View File
@@ -40,7 +40,8 @@
</receiver> </receiver>
<activity <activity
android:name=".activity.InitActivity" android:name=".activity.InitActivity"
android:exported="true"> android:exported="true"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
@@ -51,15 +52,18 @@
android:name=".activity.MainActivity" android:name=".activity.MainActivity"
android:exported="true"> android:exported="true">
</activity> </activity>
<activity <!-- <activity-->
android:name=".activity.FoodCollectionActivity" <!-- android:name=".activity.FoodCollectionActivity"-->
android:exported="true"> <!-- android:exported="true">-->
</activity> <!-- </activity>-->
<activity android:name="com.sw.dualscreen.activity.CollectedDataActivity" /> <!-- <activity android:name="com.sw.dualscreen.activity.CollectedDataActivity" />-->
<activity android:name="com.sw.dualscreen.activity.SettingActivity" /> <activity android:name="com.sw.dualscreen.activity.SettingActivity"
<activity android:name="com.sw.dualscreen.activity.CollectedFoodActivity" /> android:theme="@style/Theme.AppCompat.Light.NoActionBar" />
<activity android:name="com.sw.dualscreen.activity.PayActivity" /> <activity android:name="com.sw.dualscreen.activity.CollectedFoodActivity"
android:theme="@style/Theme.AppCompat.Light.NoActionBar" />
<activity android:name="com.sw.dualscreen.activity.PayActivity"
android:theme="@style/Theme.AppCompat.Light.NoActionBar" />
<provider <provider
android:name="androidx.core.content.FileProvider" android:name="androidx.core.content.FileProvider"
@@ -1,11 +1,11 @@
package com.sw.dualscreen.activity package com.sw.dualscreen.activity
import android.app.Dialog
import android.content.Context import android.content.Context
import android.graphics.drawable.ColorDrawable
import android.hardware.display.DisplayManager import android.hardware.display.DisplayManager
import android.os.Bundle import android.os.Bundle
import android.text.TextUtils
import android.view.Display import android.view.Display
import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.WindowManager import android.view.WindowManager
@@ -13,19 +13,17 @@ import android.widget.TextView
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import androidx.viewbinding.ViewBinding import androidx.viewbinding.ViewBinding
import com.sw.dualscreen.R import com.sw.dualscreen.R
import com.sw.dualscreen.databinding.DialogWaitingBinding
import com.sw.dualscreen.model.IActivityResult import com.sw.dualscreen.model.IActivityResult
import com.sw.dualscreen.model.response.PostEvent import com.sw.dualscreen.model.response.PostEvent
import com.sw.dualscreen.view.CustomDialog import com.sw.dualscreen.view.CustomDialog
import com.sw.dualscreen.viewmodel.BaseViewModel import com.sw.dualscreen.viewmodel.BaseViewModel
import kotlinx.coroutines.launch import com.sw.plate.utils.ToastUtils
import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode import org.greenrobot.eventbus.ThreadMode
import timber.log.Timber
abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() { abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
@@ -87,14 +85,11 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
fun showWaitingDialog(tip: String?) { fun showWaitingDialog(tip: String?) {
runOnUiThread { runOnUiThread {
hideWaitingDialog() hideWaitingDialog()
val view = View.inflate(this, R.layout.dialog_waiting, null) //val view = View.inflate(this, R.layout.dialog_waiting, null)
if (!TextUtils.isEmpty(tip)) (view.findViewById<View?>(R.id.tvTip) as TextView).text = val dialogBinding = DialogWaitingBinding.inflate(LayoutInflater.from(this))
tip dialogBinding.tvTip.text = tip
mDialogWaiting = CustomDialog(this, view, R.style.MyDialog).apply { mDialogWaiting = CustomDialog(this, dialogBinding.root)
setCancelable(true) mDialogWaiting?.show()
setCanceledOnTouchOutside(true)
show()
}
} }
} }
@@ -113,8 +108,7 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
hideWaitingDialog() hideWaitingDialog()
val view = View.inflate(this, R.layout.dialog_waiting, null) val view = View.inflate(this, R.layout.dialog_waiting, null)
mDialogWaiting = CustomDialog(this, view, R.style.MyDialog) mDialogWaiting = CustomDialog(this, view, R.style.MyDialog)
mDialogWaiting!!.show() mDialogWaiting?.show()
mDialogWaiting!!.setCancelable(true)
} }
val contentView = mDialogWaiting?.findViewById<ViewGroup>(android.R.id.content) val contentView = mDialogWaiting?.findViewById<ViewGroup>(android.R.id.content)
val tvTip = contentView?.findViewById<TextView>(R.id.tvTip) val tvTip = contentView?.findViewById<TextView>(R.id.tvTip)
@@ -32,6 +32,7 @@ import com.sw.dualscreen.ext.gone
import com.sw.dualscreen.ext.load import com.sw.dualscreen.ext.load
import com.sw.dualscreen.ext.visible import com.sw.dualscreen.ext.visible
import com.sw.dualscreen.model.response.ChargeModeEvent import com.sw.dualscreen.model.response.ChargeModeEvent
import com.sw.dualscreen.model.response.ClickBackEvent
import com.sw.dualscreen.model.response.FoodInfo import com.sw.dualscreen.model.response.FoodInfo
import com.sw.dualscreen.model.response.FoodOrder import com.sw.dualscreen.model.response.FoodOrder
import com.sw.dualscreen.model.response.PaySuccessEvent import com.sw.dualscreen.model.response.PaySuccessEvent
@@ -114,6 +115,8 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
private var isRecognitionFood = true private var isRecognitionFood = true
private var isFirstOpen = true private var isFirstOpen = true
private var isStartRecognize = false
override fun getViewModel(): BaseViewModel { override fun getViewModel(): BaseViewModel {
return viewModel return viewModel
} }
@@ -240,17 +243,23 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
} }
pauseAnalysis() pauseAnalysis()
recognizeWeight = lastWeight recognizeWeight = lastWeight
Timber.tag(TAG)
.d("registerDataChange,副屏updateFood调用前耗时:${System.currentTimeMillis() - startTime}")
startTime = System.currentTimeMillis()
presentation?.updateFood(foodInfo) presentation?.updateFood(foodInfo)
binding.tvFoodName.text = foodInfo.foodName binding.tvFoodName.text = foodInfo.foodName
binding.previewView.gone() binding.previewView.gone()
binding.ivImg.visible() binding.ivImg.visible()
if (foodInfo.foodImg.isNullOrBlank()) { if (foodInfo.foodImg.isNullOrBlank()) {
takePhoto { imgUri -> takePhoto(successCallback = { imgUri ->
binding.ivImg.load(imgUri) binding.ivImg.load(imgUri)
presentation?.updateFood(foodInfo.copy(foodImg = imgUri.toString())) presentation?.updateFood(foodInfo.copy(foodImg = imgUri.toString()))
}, failureCallback = {
})
} else {
binding.ivImg.load(foodInfo.foodImg)
} }
}
binding.ivImg.load(foodInfo.foodImg ?: foodInfo.photoUri)
//pauseAnalysis() //pauseAnalysis()
} }
@@ -283,6 +292,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
SensorScaleUtils.addWeightListener { weight -> SensorScaleUtils.addWeightListener { weight ->
Timber.d("registerDataChange weight = $weight") Timber.d("registerDataChange weight = $weight")
if (isPageVisible.not() || isStartRecognize.not()) return@addWeightListener
val isWeightChange = weight - lastWeight > 0.05 val isWeightChange = weight - lastWeight > 0.05
recognizeByWeight(weight, isWeightChange) recognizeByWeight(weight, isWeightChange)
} }
@@ -308,15 +318,23 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
lastWeight = weight lastWeight = weight
} }
private var startTime = 0L
fun recognizeFood() { fun recognizeFood() {
startTime = System.currentTimeMillis()
LightManager.openRedLight() LightManager.openRedLight()
LightManager.openGreenLight() LightManager.openGreenLight()
takePhoto { photoUri -> showWaitingDialog("识别中,请稍后……")
takePhoto(successCallback = { photoUri ->
lastPhotoUri = photoUri lastPhotoUri = photoUri
Timber.tag(TAG).d("main,takePhoto耗时:${System.currentTimeMillis() - startTime}")
startTime = System.currentTimeMillis()
Timber.d("registerDataChange photoUri = ${photoUri.path}") Timber.d("registerDataChange photoUri = ${photoUri.path}")
// viewModel.getIdentifiedFoodList() // viewModel.getIdentifiedFoodList()
ImageUtil.uriToBitmap(this, photoUri)?.let { bitmap -> ImageUtil.uriToBitmap(this, photoUri)?.let { bitmap ->
Timber.tag(TAG).d("main,uriToBitmap耗时:${System.currentTimeMillis() - startTime}")
startTime = System.currentTimeMillis()
Timber.d("registerDataChange photoUri 拿到bitmap") Timber.d("registerDataChange photoUri 拿到bitmap")
// val bmp = BitmapCropper.cropCenter(bitmap, 1300, 900) // val bmp = BitmapCropper.cropCenter(bitmap, 1300, 900)
Timber.d("registerDataChange photoUri bitmap裁剪完成") Timber.d("registerDataChange photoUri bitmap裁剪完成")
@@ -325,19 +343,21 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
this, this,
"IMG_CROP_${System.currentTimeMillis()}.jpg" "IMG_CROP_${System.currentTimeMillis()}.jpg"
) )
Timber.tag(TAG)
.d("main,saveToAppFilesDir耗时:${System.currentTimeMillis() - startTime}")
startTime = System.currentTimeMillis()
Timber.d("registerDataChange photoUri bitmap保存文件路径:${file?.absolutePath}") Timber.d("registerDataChange photoUri bitmap保存文件路径:${file?.absolutePath}")
//val nameList = FoodModule.queryFood(bitmap) //val nameList = FoodModule.queryFood(bitmap)
val scoreList = FoodModule.getFoodScoreList(bitmap) val scoreList = FoodModule.getFoodScoreList(bitmap)
Timber.d( val recDataJson = GsonUtils.toJson(scoreList)
"registerDataChange photoUri 拿到识别数据:${ Timber.tag(TAG)
GsonUtils.toJson( .d("main,getFoodScoreList耗时:${System.currentTimeMillis() - startTime}")
scoreList startTime = System.currentTimeMillis()
) Timber.d("registerDataChange photoUri 拿到识别数据:$recDataJson")
}"
)
val nameList = scoreList.map { it.name } val nameList = scoreList.map { it.name }
val foodName = nameList.joinToString(separator = ",") val foodName = nameList.joinToString(separator = ",")
hideWaitingDialog()
Timber.d("registerDataChange photoUri 识别数据名称:$foodName") Timber.d("registerDataChange photoUri 识别数据名称:$foodName")
if (TextUtils.isEmpty(foodName)) { if (TextUtils.isEmpty(foodName)) {
LightManager.closeGreenLight() LightManager.closeGreenLight()
@@ -350,15 +370,28 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
} }
} else { } else {
//binding.layoutRescan.visibility = View.GONE //binding.layoutRescan.visibility = View.GONE
showWaitingDialog("正在查询菜品信息,请稍后……")
viewModel.getFoodInfo(foodName) { list -> viewModel.getFoodInfo(foodName) { list ->
runOnUiThread { runOnUiThread {
hideWaitingDialog()
Timber.tag(TAG)
.d("main,getFoodInfo耗时:${System.currentTimeMillis() - startTime}")
startTime = System.currentTimeMillis()
updateFoodInfo(list.toMutableList(), scoreList) updateFoodInfo(list.toMutableList(), scoreList)
} }
} }
} }
} }
}, failureCallback = {
runOnUiThread {
hideWaitingDialog()
ToastUtils.showToast("拍照异常,请手动放置后重新识别")
} }
// binding.root.postDelayed({
// recognizeFood()
// }, 500)
})
} }
@SuppressLint("NotifyDataSetChanged") @SuppressLint("NotifyDataSetChanged")
@@ -447,6 +480,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
if (isAnalyzing) { if (isAnalyzing) {
val bitmap = imageProxy.toBitmap() val bitmap = imageProxy.toBitmap()
presentation?.updateImage(bitmap) // 更新副屏 presentation?.updateImage(bitmap) // 更新副屏
isStartRecognize = true
} }
imageProxy.close() // 必须关闭以释放资源 imageProxy.close() // 必须关闭以释放资源
} }
@@ -518,7 +552,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
} }
// 拍照功能 // 拍照功能
private fun takePhoto(callback: (Uri) -> Unit) { private fun takePhoto(successCallback: (Uri) -> Unit, failureCallback: () -> Unit) {
Timber.d("takePhoto") Timber.d("takePhoto")
// 临时停止分析以避免干扰 // 临时停止分析以避免干扰
isAnalyzing = false isAnalyzing = false
@@ -545,7 +579,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
Timber.d("takePhoto savedUri = $savedUri") Timber.d("takePhoto savedUri = $savedUri")
// ToastUtils.showToast("照片保存成功: $savedUri") // ToastUtils.showToast("照片保存成功: $savedUri")
if (savedUri != null) { if (savedUri != null) {
callback(savedUri) successCallback(savedUri)
} }
} }
// 恢复图像分析 // 恢复图像分析
@@ -554,6 +588,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
override fun onError(exception: ImageCaptureException) { override fun onError(exception: ImageCaptureException) {
Timber.e("拍照失败: ${exception.message}") Timber.e("拍照失败: ${exception.message}")
failureCallback()
//runOnUiThread { //runOnUiThread {
// ToastUtils.showToast("拍照失败: ${exception.message}") // ToastUtils.showToast("拍照失败: ${exception.message}")
//} //}
@@ -631,9 +666,11 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
binding.tvTitleTime.text = dateTime binding.tvTitleTime.text = dateTime
} }
private var isPageVisible = true
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
Timber.tag("onResume").d("=================onResume================") isPageVisible = true
// 启动定时器 // 启动定时器
handler.postDelayed(timeoutRunnable, TIME_OUT) handler.postDelayed(timeoutRunnable, TIME_OUT)
@@ -650,12 +687,15 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
setupSecondaryDisplay() setupSecondaryDisplay()
presentation?.step1FoodRecognizing() presentation?.step1FoodRecognizing()
} else { } else {
if (isRefreshPage) {
//已显示副屏,则进行更新 //已显示副屏,则进行更新
val weight = lastWeight val weight = lastWeight
lastWeight = 0.0 lastWeight = 0.0
presentation?.hideRecImage() presentation?.hideRecImage()
recognizeByWeight(weight, true) recognizeByWeight(weight, true)
} }
isRefreshPage = !isRefreshPage
}
} }
//根据付费模式确认是否显示按钮 //根据付费模式确认是否显示按钮
@@ -674,6 +714,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
override fun onPause() { override fun onPause() {
super.onPause() super.onPause()
isPageVisible = false
// 取消定时器 // 取消定时器
handler.removeCallbacks(timeoutRunnable) handler.removeCallbacks(timeoutRunnable)
} }
@@ -770,6 +811,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
@Subscribe(threadMode = ThreadMode.MAIN) @Subscribe(threadMode = ThreadMode.MAIN)
fun onPaySuccessEvent(event: PaySuccessEvent) { fun onPaySuccessEvent(event: PaySuccessEvent) {
isRefreshPage = true
val chargeMode = SPUtil.getInstance().get(GlobalKey.KEY_CHARGE_MODE, 0) ?: 0 val chargeMode = SPUtil.getInstance().get(GlobalKey.KEY_CHARGE_MODE, 0) ?: 0
presentation?.hideNutritionView(chargeMode) presentation?.hideNutritionView(chargeMode)
presentation?.cancel() presentation?.cancel()
@@ -777,9 +819,16 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
@Subscribe(threadMode = ThreadMode.MAIN) @Subscribe(threadMode = ThreadMode.MAIN)
fun onChargeModeEvent(event: ChargeModeEvent) { fun onChargeModeEvent(event: ChargeModeEvent) {
isRefreshPage = true
isStartRecognize = false
presentation?.hideNutritionView(event.chargeMode) presentation?.hideNutritionView(event.chargeMode)
// presentation?.cancel() // presentation?.cancel()
} }
private var isRefreshPage = false
@Subscribe(threadMode = ThreadMode.MAIN)
fun onClickBackEvent(event: ClickBackEvent) {
isRefreshPage = false
}
private fun clickPayButton() { private fun clickPayButton() {
if (checkedItem == null) { if (checkedItem == null) {
@@ -1,5 +1,6 @@
package com.sw.dualscreen.activity package com.sw.dualscreen.activity
import androidx.activity.OnBackPressedCallback
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.sw.dualscreen.R import com.sw.dualscreen.R
@@ -7,8 +8,10 @@ import com.sw.dualscreen.activity.fragment.BusinessFragment
import com.sw.dualscreen.activity.fragment.CollectFragment import com.sw.dualscreen.activity.fragment.CollectFragment
import com.sw.dualscreen.databinding.ActivitySettingBinding import com.sw.dualscreen.databinding.ActivitySettingBinding
import com.sw.dualscreen.model.response.FoodInfo import com.sw.dualscreen.model.response.FoodInfo
import com.sw.dualscreen.model.response.ClickBackEvent
import com.sw.dualscreen.viewmodel.BaseViewModel import com.sw.dualscreen.viewmodel.BaseViewModel
import com.sw.dualscreen.viewmodel.UserViewModel import com.sw.dualscreen.viewmodel.UserViewModel
import org.greenrobot.eventbus.EventBus
class SettingActivity : BaseActivity<ActivitySettingBinding>() { class SettingActivity : BaseActivity<ActivitySettingBinding>() {
@@ -28,10 +31,12 @@ class SettingActivity : BaseActivity<ActivitySettingBinding>() {
override fun initialize() { override fun initialize() {
super.initialize() super.initialize()
initBackDispatcher()
binding.include.let { binding.include.let {
it.ivPageBack.setOnClickListener { it.ivPageBack.setOnClickListener {
// val intent = Intent(this, MainActivity::class.java) // val intent = Intent(this, MainActivity::class.java)
// startActivity(intent) // startActivity(intent)
EventBus.getDefault().post(ClickBackEvent())
finish() finish()
} }
it.tvPageTitle.text = "设置" it.tvPageTitle.text = "设置"
@@ -65,4 +70,17 @@ class SettingActivity : BaseActivity<ActivitySettingBinding>() {
viewModel.searchByFoodName(foodName, action) viewModel.searchByFoodName(foodName, action)
} }
private lateinit var backPressedCallback: OnBackPressedCallback
private fun initBackDispatcher() {
// 创建回调,true表示初始启用状态
backPressedCallback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
EventBus.getDefault().post(ClickBackEvent())
}
}
// 注册回调,使用lifecycleOwner确保生命周期安全
onBackPressedDispatcher.addCallback(this, backPressedCallback)
}
} }
@@ -45,8 +45,9 @@ class CollectFragment : BaseFragment<FragmentCollectBinding>() {
companion object { companion object {
private const val TAG = "CollectFragment" private const val TAG = "CollectFragment"
const val MAX_COUNT = 102 const val MAX_COUNT = 15
} }
private var selectedFoodId: String? = "" private var selectedFoodId: String? = ""
private var selectedFoodName: String? = "" private var selectedFoodName: String? = ""
@@ -64,11 +65,11 @@ class CollectFragment : BaseFragment<FragmentCollectBinding>() {
SearchFoodAdapter(searchFoodList).apply { SearchFoodAdapter(searchFoodList).apply {
setOnItemClickListener { adapter, view, position -> setOnItemClickListener { adapter, view, position ->
checkedItem = searchFoodList[position] checkedItem = searchFoodList[position]
selectedFoodId = checkedItem!!.foodId
selectedFoodName = checkedItem!!.foodName
val isChecked = checkedItem!!.isChecked val isChecked = checkedItem!!.isChecked
searchFoodList[position].isChecked = isChecked.not() searchFoodList[position].isChecked = isChecked.not()
notifyItemChanged(position) notifyItemChanged(position)
selectedFoodId = checkedItem!!.foodId
selectedFoodName = checkedItem!!.foodName
} }
} }
} }
@@ -85,6 +86,7 @@ class CollectFragment : BaseFragment<FragmentCollectBinding>() {
it.bitmap = null it.bitmap = null
it.imageVector = null it.imageVector = null
it.imageFile = null it.imageFile = null
it.imageUri = null
it.isShowCamera = true it.isShowCamera = true
it.isFinish = false it.isFinish = false
it.uploadSuccess = false it.uploadSuccess = false
@@ -93,6 +95,7 @@ class CollectFragment : BaseFragment<FragmentCollectBinding>() {
} }
} }
} }
override fun inflateViewBinding(): FragmentCollectBinding { override fun inflateViewBinding(): FragmentCollectBinding {
return FragmentCollectBinding.inflate(LayoutInflater.from(context)) return FragmentCollectBinding.inflate(LayoutInflater.from(context))
} }
@@ -106,6 +109,17 @@ class CollectFragment : BaseFragment<FragmentCollectBinding>() {
settingActivity?.hideWaitingDialog() settingActivity?.hideWaitingDialog()
rerurn@ cameraCallback rerurn@ cameraCallback
} }
activity?.runOnUiThread {
foodCollectionList[index].let {
it.imageVector = null
it.bitmap = null
it.isShowCamera = false
it.imageFile = null
it.imageUri = uri
}
collectionAdapter.notifyItemChanged(index)
}
// settingActivity?.hideWaitingDialog()
ImageUtil.uriToBitmap(requireActivity(), uri)?.let { bitmap -> ImageUtil.uriToBitmap(requireActivity(), uri)?.let { bitmap ->
// val cropBitmap = BitmapCropper.cropCenter( // val cropBitmap = BitmapCropper.cropCenter(
// original = bitmap, // original = bitmap,
@@ -154,7 +168,7 @@ class CollectFragment : BaseFragment<FragmentCollectBinding>() {
} }
settingActivity?.showWaitingDialog("拍照中……") settingActivity?.showWaitingDialog("拍照中……")
cameraUtils.takePhoto(cameraCallback) { errMsg -> cameraUtils.takePhoto(cameraCallback) { errMsg ->
ToastUtils.showToast(errMsg) ToastUtils.showToast("拍照异常,请重新操作")
settingActivity?.hideWaitingDialog() settingActivity?.hideWaitingDialog()
} }
} }
@@ -173,7 +187,8 @@ class CollectFragment : BaseFragment<FragmentCollectBinding>() {
cameraUtils.setPreviewController(previewView) cameraUtils.setPreviewController(previewView)
binding.rvFoodList.let { binding.rvFoodList.let {
it.layoutManager = GridLayoutManager(requireActivity(), 3, GridLayoutManager.VERTICAL, false) it.layoutManager =
GridLayoutManager(requireActivity(), 3, GridLayoutManager.VERTICAL, false)
it.adapter = collectionAdapter it.adapter = collectionAdapter
} }
@@ -182,12 +197,12 @@ class CollectFragment : BaseFragment<FragmentCollectBinding>() {
} }
binding.btnSave.setOnClickListener { binding.btnSave.setOnClickListener {
if (selectedFoodName.isNullOrBlank()) { if (checkedItem == null || checkedItem!!.isChecked.not()) {
Toast.makeText(requireActivity(), "请选择菜品名称", Toast.LENGTH_SHORT).show() ToastUtils.showToast("请选择菜品名称")
return@setOnClickListener return@setOnClickListener
} }
if (foodCollectionList.size <= 1) { if (foodCollectionList.size <= 1) {
Toast.makeText(requireActivity(), "请拍摄菜品照片", Toast.LENGTH_SHORT).show() ToastUtils.showToast("请拍摄菜品照片")
return@setOnClickListener return@setOnClickListener
} }
upload() upload()
@@ -237,7 +252,10 @@ class CollectFragment : BaseFragment<FragmentCollectBinding>() {
totalList = foodCollectionList, totalList = foodCollectionList,
uploadImage = { batch -> uploadImage = { batch ->
val files = batch.map { it.imageFile } val files = batch.map { it.imageFile }
(requireActivity() as SettingActivity).viewModel.uploadCollectFoodPics(files,params) (requireActivity() as SettingActivity).viewModel.uploadCollectFoodPics(
files,
params
)
}, },
onProgress = { count, batch -> onProgress = { count, batch ->
activity?.runOnUiThread { activity?.runOnUiThread {
@@ -347,6 +365,7 @@ class CollectFragment : BaseFragment<FragmentCollectBinding>() {
it.bitmap = null it.bitmap = null
it.imageVector = null it.imageVector = null
it.imageFile = null it.imageFile = null
it.imageUri = null
it.isShowCamera = true it.isShowCamera = true
it.isFinish = false it.isFinish = false
it.uploadSuccess = false it.uploadSuccess = false
@@ -39,7 +39,11 @@ class FoodCollectionAdapter (var list: MutableList<FoodCollectionBean>) :
scaleType = ImageView.ScaleType.CENTER_CROP scaleType = ImageView.ScaleType.CENTER_CROP
//setImageURI(it.imageUri) //setImageURI(it.imageUri)
//setImageBitmap(it.bitmap) //setImageBitmap(it.bitmap)
if (it.imageUri!=null) {
setImageURI(it.imageUri)
} else {
load(it.imageFile) load(it.imageFile)
}
// it.bitmap?.let { bitmap -> // it.bitmap?.let { bitmap ->
// GlideUtils.loadRoundCornerWitBitmap( // GlideUtils.loadRoundCornerWitBitmap(
// context, // context,
@@ -127,3 +127,7 @@ data class PaySuccessEvent(
data class ChargeModeEvent( data class ChargeModeEvent(
var chargeMode:Int = 0 var chargeMode:Int = 0
) )
data class ClickBackEvent(
var name: String = ""
)
@@ -19,6 +19,7 @@ data class FoodClassInfo(
data class FoodCollectionBean( data class FoodCollectionBean(
var imageFile: File? = null, var imageFile: File? = null,
var imageUri: Uri? = null,
var bitmap: Bitmap? = null, var bitmap: Bitmap? = null,
var imageVector: FloatArray? = null, var imageVector: FloatArray? = null,
var isShowCamera: Boolean = false, var isShowCamera: Boolean = false,
@@ -92,6 +92,7 @@ object FoodModule {
} }
fun queryFoodNameScore(floatArray: FloatArray, queryCount: Int = 15): List<IdNameScore> { fun queryFoodNameScore(floatArray: FloatArray, queryCount: Int = 15): List<IdNameScore> {
val startTime = System.currentTimeMillis()
val query: Query<Food> = val query: Query<Food> =
box.query(Food_.foodVector.nearestNeighbors(floatArray, queryCount)).build() box.query(Food_.foodVector.nearestNeighbors(floatArray, queryCount)).build()
//查询比较分数 //查询比较分数
@@ -101,11 +102,14 @@ object FoodModule {
idScoreList.forEach { idScoreList.forEach {
nameScoreList.add(IdNameScore(id = it.id, name = box.get(it.id).name?:"", score = it.score)) nameScoreList.add(IdNameScore(id = it.id, name = box.get(it.id).name?:"", score = it.score))
} }
Timber.tag("FoodModule").d("registerDataChange,queryFood数据:${GsonUtils.toJson(nameScoreList)}") val nameScoreData = GsonUtils.toJson(nameScoreList)
Timber.tag("FoodModule").d("registerDataChange,queryFood,耗时:${System.currentTimeMillis()-startTime},数据:$nameScoreData")
return nameScoreList return nameScoreList
} }
fun getFoodScoreList(bitmap: Bitmap, queryCount: Int = 15): List<IdNameScore> { fun getFoodScoreList(bitmap: Bitmap, queryCount: Int = 15): List<IdNameScore> {
val startTime = System.currentTimeMillis()
val floatArray = bitmap2FloatArray(bitmap) val floatArray = bitmap2FloatArray(bitmap)
Timber.tag("FoodModule").d("registerDataChange,bitmap2FloatArray,耗时:${System.currentTimeMillis()-startTime}")
val nameScoreList = queryFoodNameScore(floatArray, queryCount) val nameScoreList = queryFoodNameScore(floatArray, queryCount)
if (nameScoreList.isEmpty()) { if (nameScoreList.isEmpty()) {
return emptyList() return emptyList()
@@ -118,6 +118,7 @@ class MainScreenPresentation(
initView() initView()
setupArcCamera() setupArcCamera()
registerDataChange() registerDataChange()
startTime = System.currentTimeMillis()
} }
private var isFirstGetWeight = true private var isFirstGetWeight = true
@@ -261,19 +262,34 @@ class MainScreenPresentation(
/** /**
* 显示识别出的菜品信息 * 显示识别出的菜品信息
*/ */
fun step3ShowRecognizeResult() { fun step3ShowRecognizeResult(userId: String) {
Timber.tag(TAG).d("step3") Timber.tag(TAG).d("main,step3,耗时:${System.currentTimeMillis() - startTime}")
LightManager.closeRedLight() LightManager.closeRedLight()
LightManager.openGreenLight() LightManager.openGreenLight()
currentStep = 3 currentStep = 3
stepChangeCallback(currentStep) stepChangeCallback(currentStep)
if (currentFood == null) {
ToastUtils.showToast("选中物品为空")
return
}
// updateFoodInfo(currentFood!!)
//foodRecSuccess(currentFood!!) //根据接口数据更新热量数据--------------------------
userViewModel.getUserNutritionData(userId = userId) { nutrition ->
activity.runOnUiThread {
if (nutrition == null) {
activity.hideWaitingDialog()
ToastUtils.showToast("未查询到营养数据")
return@runOnUiThread
}
this@MainScreenPresentation.userNutrition = nutrition
loadUnbilledMode()
val imageUrl =
if (currentFood!!.foodImg.isNullOrBlank()) currentFood!!.photoUri else currentFood!!.foodImg
binding.ivRecImage.let {
it.visible()
it.load(imageUrl)
}
activity.updateImage(imageUrl)
activity.hideWaitingDialog()
}
}
} }
private fun initView() { private fun initView() {
@@ -392,14 +408,19 @@ class MainScreenPresentation(
calculateNutrition(recognitionWeight - lastWeight) calculateNutrition(recognitionWeight - lastWeight)
} }
private var isFirstOpen = true
var startTime = 0L
/** /**
* 餐品识别中 * 餐品识别中
*/ */
fun step1FoodRecognizing() { fun step1FoodRecognizing() {
Timber.tag(TAG).d("main,step1,耗时:${System.currentTimeMillis() - startTime}")
startTime = System.currentTimeMillis()
hideStandbyScreen() hideStandbyScreen()
activity.resetTouchTime() activity.resetTouchTime()
if (isFirstOpen.not()) {
activity.resumeAnalysis() activity.resumeAnalysis()
Timber.tag(TAG).d("step1") }
//if (abs(lastWeight.toInt()) <= 5) { //if (abs(lastWeight.toInt()) <= 5) {
// activity.runOnUiThread { // activity.runOnUiThread {
// ToastUtils.showToast("秤上重量几乎为0,请确认") // ToastUtils.showToast("秤上重量几乎为0,请确认")
@@ -426,11 +447,11 @@ class MainScreenPresentation(
binding.flCameraView.visible() binding.flCameraView.visible()
binding.ivRecImage.gone() binding.ivRecImage.gone()
binding.ivPreviewImage.visible() binding.ivPreviewImage.visible()
binding.ivFrame.visible()
binding.ivFaceRecMask.gone() binding.ivFaceRecMask.gone()
binding.tvFaceTip.gone() binding.tvFaceTip.gone()
binding.llPriceInfo.gone() binding.llPriceInfo.gone()
binding.flFace.gone() binding.flFace.gone()
binding.ivFrame.gone()
binding.flRecognizeIr.gone() binding.flRecognizeIr.gone()
pauseCamera() pauseCamera()
@@ -458,7 +479,8 @@ class MainScreenPresentation(
*/ */
fun step2FaceRecognizing(foodInfo: FoodInfo) { fun step2FaceRecognizing(foodInfo: FoodInfo) {
isGoStep1 = true isGoStep1 = true
Timber.tag(TAG).d("step2") Timber.tag(TAG).d("main,step2,耗时:${System.currentTimeMillis() - startTime}")
startTime = System.currentTimeMillis()
currentStep = 2 currentStep = 2
LightManager.closeRedLight() LightManager.closeRedLight()
@@ -497,7 +519,8 @@ class MainScreenPresentation(
// 当前食物信息 // 当前食物信息
private var currentFood: FoodInfo? = null private var currentFood: FoodInfo? = null
fun updateFood(foodInfo: FoodInfo?) { fun updateFood(foodInfo: FoodInfo?) {
Timber.tag(TAG).d("updateFood") Timber.tag(TAG).d("main,updateFood,耗时:${System.currentTimeMillis() - startTime}")
startTime = System.currentTimeMillis()
currentFood = foodInfo currentFood = foodInfo
if (foodInfo == null) { if (foodInfo == null) {
return return
@@ -513,6 +536,8 @@ class MainScreenPresentation(
if (foodInfo.foodImg.isNullOrBlank()) foodInfo.photoUri else foodInfo.foodImg if (foodInfo.foodImg.isNullOrBlank()) foodInfo.photoUri else foodInfo.foodImg
it.load(imageUrl) it.load(imageUrl)
} }
} else {
binding.ivRecImage.gone()
} }
val mode = SPUtil.getInstance().get(GlobalKey.KEY_CHARGE_MODE, 0) val mode = SPUtil.getInstance().get(GlobalKey.KEY_CHARGE_MODE, 0)
if (mode == 0) { if (mode == 0) {
@@ -793,28 +818,7 @@ class MainScreenPresentation(
return@runOnUiThread return@runOnUiThread
} }
} }
step3ShowRecognizeResult() step3ShowRecognizeResult(userId)
//根据接口数据更新热量数据--------------------------
userViewModel.getUserNutritionData(userId = userId) { nutrition ->
activity.runOnUiThread {
if (nutrition == null) {
activity.hideWaitingDialog()
ToastUtils.showToast("未查询到营养数据")
return@runOnUiThread
}
this@MainScreenPresentation.userNutrition = nutrition
loadUnbilledMode()
val imageUrl =
if (currentFood!!.foodImg.isNullOrBlank()) currentFood!!.photoUri else currentFood!!.foodImg
binding.ivRecImage.let {
it.visible()
it.load(imageUrl)
}
activity.updateImage(imageUrl)
activity.hideWaitingDialog()
}
}
}) })
recognizeViewModel.drawRectInfoText.observe(activity, Observer { info -> recognizeViewModel.drawRectInfoText.observe(activity, Observer { info ->
@@ -1140,10 +1144,9 @@ class MainScreenPresentation(
} }
fun postUserData() { fun postUserData() {
Timber.tag(TAG).d("postUserData")
if (userNutrition == null || currentFood == null) {
Timber.tag(TAG) Timber.tag(TAG)
.d("postUserData userNutritionData = ${userNutrition == null}, currentFood = ${currentFood == null}") .d("postUserData userNutritionData是否null ${userNutrition == null}, currentFood是否null: ${currentFood == null}currentUserId是否null${currentUserId == null}", )
if (userNutrition == null || currentFood == null || currentUserId == null) {
return return
} }
createOrder() createOrder()
@@ -3,14 +3,14 @@ package com.sw.dualscreen.view;
import android.app.Dialog; import android.app.Dialog;
import android.content.Context; import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Build; import android.os.Build;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.view.Gravity; import android.view.Gravity;
import android.view.View; import android.view.View;
import android.view.Window; import android.view.Window;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.TextView;
import com.sw.dualscreen.R; import com.sw.dualscreen.R;
/** /**
@@ -18,78 +18,86 @@ import com.sw.dualscreen.R;
*/ */
public class CustomDialog extends Dialog { public class CustomDialog extends Dialog {
/** /**
* 宽高由布局文件中指定(但是最底层的宽度无效,可以多嵌套一层解决) * 宽高由布局文件中指定(但是最底层的宽度无效,可以多嵌套一层解决)
*/ */
public CustomDialog(Context context, View layout) {
super(context, R.style.LoadingDialog);
setContentView(layout);
initConfig();
}
public CustomDialog(Context context, View layout, int style) { public CustomDialog(Context context, View layout, int style) {
super(context, style); super(context, style);
setContentView(layout); setContentView(layout);
initConfig();
}
private void initConfig() {
setCancelable(true);
setCanceledOnTouchOutside(true);
Window window = getWindow(); Window window = getWindow();
if (window != null) {
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
WindowManager.LayoutParams params = window.getAttributes(); WindowManager.LayoutParams params = window.getAttributes();
params.gravity = Gravity.CENTER; params.gravity = Gravity.CENTER;
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
window.setAttributes(params); window.setAttributes(params);
}
/**
* 宽高由该方法的参数设置
*/
public CustomDialog(Context context, int width, int height, View layout,
int style) {
super(context, style);
// 设置内容
setContentView(layout);
// 设置窗口属性
Window window = getWindow();
WindowManager.LayoutParams params = window.getAttributes();
// 设置宽度、高度、密度、对齐方式
float density = getDensity(context);
params.width = (int) (width * density);
params.height = (int) (height * density);
params.gravity = Gravity.CENTER;
window.setAttributes(params);
}
/**
* 获取显示密度
*
* @param context
* @return
*/
public float getDensity(Context context) {
Resources res = context.getResources();
DisplayMetrics dm = res.getDisplayMetrics();
return dm.density;
} }
private void fullScreenImmersive(View view) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_FULLSCREEN;
view.setSystemUiVisibility(uiOptions);
}
}
@Override
public void show() {
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
super.show();
// fullScreenImmersive(getWindow().getDecorView());
// this.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
} }
//
// /**
// * 宽高由该方法的参数设置
// */
// public CustomDialog(Context context, int width, int height, View layout,
// int style) {
// super(context, style);
// // 设置内容
// setContentView(layout);
// // 设置窗口属性
// Window window = getWindow();
// WindowManager.LayoutParams params = window.getAttributes();
// // 设置宽度、高度、密度、对齐方式
// float density = getDensity(context);
// params.width = (int) (width * density);
// params.height = (int) (height * density);
// params.gravity = Gravity.CENTER;
// window.setAttributes(params);
//
// }
//
// /**
// * 获取显示密度
// *
// * @param context
// * @return
// */
// public float getDensity(Context context) {
// Resources res = context.getResources();
// DisplayMetrics dm = res.getDisplayMetrics();
// return dm.density;
// }
//
// private void fullScreenImmersive(View view) {
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
// | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
// | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
// | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
// | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
// | View.SYSTEM_UI_FLAG_FULLSCREEN;
// view.setSystemUiVisibility(uiOptions);
// }
//
// }
// @Override
// public void show() {
// this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
// super.show();
//// fullScreenImmersive(getWindow().getDecorView());
//// this.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
// }
} }
+1 -1
View File
@@ -2,5 +2,5 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android" <shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"> android:shape="rectangle">
<solid android:color="#FFFF3232"/> <solid android:color="#FFFF3232"/>
<corners android:radius="6dp"/> <corners android:radius="10dp"/>
</shape> </shape>
+4 -3
View File
@@ -58,7 +58,7 @@
android:id="@+id/tv_food_name" android:id="@+id/tv_food_name"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="60dp" android:layout_marginTop="50dp"
android:textStyle="bold" android:textStyle="bold"
android:textSize="52sp" android:textSize="52sp"
android:textColor="#FF0A1428" android:textColor="#FF0A1428"
@@ -67,9 +67,9 @@
<FrameLayout <FrameLayout
android:id="@+id/foodDisplayLayout" android:id="@+id/foodDisplayLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="500dp" android:layout_height="560dp"
android:layout_marginHorizontal="28dp" android:layout_marginHorizontal="28dp"
android:layout_marginTop="100dp" android:layout_marginTop="80dp"
android:visibility="visible"> android:visibility="visible">
<androidx.camera.view.PreviewView <androidx.camera.view.PreviewView
@@ -100,6 +100,7 @@
android:layout_height="0dp" android:layout_height="0dp"
app:spanCount="2" app:spanCount="2"
tools:itemCount="8" tools:itemCount="8"
android:overScrollMode="never"
tools:listitem="@layout/list_item_search_food" tools:listitem="@layout/list_item_search_food"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager" app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
android:layout_marginHorizontal="14dp" android:layout_marginHorizontal="14dp"
+2 -1
View File
@@ -11,7 +11,8 @@
android:layout_width="39dp" android:layout_width="39dp"
android:layout_height="39dp" android:layout_height="39dp"
android:indeterminateTint="@color/teal_200" android:indeterminateTint="@color/teal_200"
android:indeterminateTintMode="src_atop" /> android:indeterminateTintMode="src_atop"
android:focusable="false"/>
<TextView <TextView
android:id="@+id/tvTip" android:id="@+id/tvTip"
@@ -187,7 +187,7 @@
<androidx.appcompat.widget.AppCompatButton <androidx.appcompat.widget.AppCompatButton
android:id="@+id/btnConfirm" android:id="@+id/btnConfirm"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="100dp" android:layout_height="87dp"
android:layout_marginHorizontal="32dp" android:layout_marginHorizontal="32dp"
android:layout_marginBottom="48dp" android:layout_marginBottom="48dp"
android:text="确定" android:text="确定"
+1 -1
View File
@@ -175,7 +175,7 @@
<androidx.appcompat.widget.AppCompatButton <androidx.appcompat.widget.AppCompatButton
android:id="@+id/btnSave" android:id="@+id/btnSave"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="100dp" android:layout_height="87dp"
android:layout_marginHorizontal="32dp" android:layout_marginHorizontal="32dp"
android:layout_marginBottom="48dp" android:layout_marginBottom="48dp"
android:text="保存" android:text="保存"
+1 -1
View File
@@ -1,6 +1,6 @@
<resources> <resources>
<!-- Base application theme. --> <!-- Base application theme. -->
<style name="Base.Theme.DualScreen" parent="Theme.Material3.DayNight.NoActionBar"> <style name="Theme.DualScreen" parent="Theme.AppCompat.DayNight.NoActionBar">
<!-- Customize your dark theme here. --> <!-- Customize your dark theme here. -->
<!-- <item name="colorPrimary">@color/my_dark_primary</item> --> <!-- <item name="colorPrimary">@color/my_dark_primary</item> -->
</style> </style>
+6 -3
View File
@@ -1,13 +1,11 @@
<resources> <resources>
<!-- Base application theme. --> <!-- Base application theme. -->
<!-- <style name="Base.Theme.DualScreen" parent="Theme.Material3.DayNight.NoActionBar">--> <!-- <style name="Base.Theme.DualScreen" parent="Theme.Material3.DayNight.NoActionBar">-->
<style name="Base.Theme.DualScreen" parent="Theme.AppCompat.Light.NoActionBar"> <style name="Theme.DualScreen" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your light theme here. --> <!-- Customize your light theme here. -->
<!-- <item name="colorPrimary">@color/my_light_primary</item> --> <!-- <item name="colorPrimary">@color/my_light_primary</item> -->
</style> </style>
<style name="Theme.DualScreen" parent="Base.Theme.DualScreen" />
<style name="text_title_blob"> <style name="text_title_blob">
<item name="android:layout_width">match_parent</item> <item name="android:layout_width">match_parent</item>
<item name="android:textColor">@color/beige_ECE7D0</item> <item name="android:textColor">@color/beige_ECE7D0</item>
@@ -177,4 +175,9 @@
<item name="cornerFamily">rounded</item> <item name="cornerFamily">rounded</item>
<item name="cornerSize">10dp</item> <item name="cornerSize">10dp</item>
</style> </style>
<style name="LoadingDialog" parent="Theme.AppCompat.Dialog">
<item name="android:windowIsFloating">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
</style>
</resources> </resources>