结算页面、设置页面

This commit is contained in:
2025-11-19 18:35:53 +08:00
parent 9818dfc438
commit 60b712f216
75 changed files with 2983 additions and 647 deletions
+3
View File
@@ -57,6 +57,9 @@
</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.CollectedFoodActivity" />
<activity android:name="com.sw.dualscreen.activity.PayActivity" />
<provider <provider
android:name="androidx.core.content.FileProvider" android:name="androidx.core.content.FileProvider"
@@ -61,4 +61,5 @@ object GlobalKey {
const val KEY_FIRST_RUN = "firstRun" const val KEY_FIRST_RUN = "firstRun"
const val KEY_USER_INFO = "userInfoKey" const val KEY_USER_INFO = "userInfoKey"
const val KEY_PICKUP_MODE = "pickupMode" const val KEY_PICKUP_MODE = "pickupMode"
const val KEY_CHARGE_MODE = "chargeMode"
} }
@@ -1,6 +1,10 @@
package com.sw.dualscreen package com.sw.dualscreen
import android.app.Activity
import android.os.Bundle
import com.sw.dualscreen.objbox.ObjectBox import com.sw.dualscreen.objbox.ObjectBox
import com.sw.dualscreen.sdk.SensorScaleUtils
import com.sw.dualscreen.utils.ActivityManager
import com.sw.dualscreen.utils.CrashHandler import com.sw.dualscreen.utils.CrashHandler
import com.sw.plate.App import com.sw.plate.App
import com.sw.plate.utils.AppUtil import com.sw.plate.utils.AppUtil
@@ -23,5 +27,44 @@ class MyApp : App() {
ObjectBox.init(this) ObjectBox.init(this)
// 初始化崩溃处理器 // 初始化崩溃处理器
CrashHandler.init(this) CrashHandler.init(this)
SensorScaleUtils.startScale()
//addActivityLifecycleListener()
}
private fun addActivityLifecycleListener() {
registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
override fun onActivityCreated(
activity: Activity,
savedInstanceState: Bundle?
) {
ActivityManager.addActivity(activity)
}
override fun onActivityStarted(activity: Activity) {
}
override fun onActivityResumed(activity: Activity) {
}
override fun onActivityPaused(activity: Activity) {
}
override fun onActivityStopped(activity: Activity) {
}
override fun onActivitySaveInstanceState(
activity: Activity,
outState: Bundle
) {
}
override fun onActivityDestroyed(activity: Activity) {
ActivityManager.removeActivity(activity)
if (ActivityManager.isEmpty()) {
SensorScaleUtils.closeScale()
}
}
})
} }
} }
@@ -1,134 +1,134 @@
package com.sw.dualscreen.activity //package com.sw.dualscreen.activity
//
import android.annotation.SuppressLint //import android.annotation.SuppressLint
import androidx.activity.viewModels //import androidx.activity.viewModels
import androidx.core.widget.addTextChangedListener //import androidx.core.widget.addTextChangedListener
import androidx.recyclerview.widget.LinearLayoutManager //import androidx.recyclerview.widget.LinearLayoutManager
import com.sw.dualscreen.R //import com.sw.dualscreen.R
import com.sw.dualscreen.adapter.CollectedFoodAdapter //import com.sw.dualscreen.adapter.CollectedFoodAdapter
import com.sw.dualscreen.databinding.ActivityCollectedDataBinding //import com.sw.dualscreen.databinding.ActivityCollectedDataBinding
import com.sw.dualscreen.databinding.LayoutEmptySearchBinding //import com.sw.dualscreen.databinding.LayoutEmptySearchBinding
import com.sw.dualscreen.dialog.WarnDialog //import com.sw.dualscreen.dialog.WarnDialog
import com.sw.dualscreen.ext.addOnActionSearchListener //import com.sw.dualscreen.ext.addOnActionSearchListener
import com.sw.dualscreen.ext.hideKeyboard //import com.sw.dualscreen.ext.hideKeyboard
import com.sw.dualscreen.objbox.CollectedFoodBean //import com.sw.dualscreen.objbox.CollectedFoodBean
import com.sw.dualscreen.objbox.Food //import com.sw.dualscreen.objbox.Food
import com.sw.dualscreen.objbox.ObjectBox //import com.sw.dualscreen.objbox.ObjectBox
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 com.sw.plate.utils.ToastUtils //import com.sw.plate.utils.ToastUtils
import io.objectbox.Box //import io.objectbox.Box
import io.objectbox.kotlin.boxFor //import io.objectbox.kotlin.boxFor
import kotlin.getValue //import kotlin.getValue
//
class CollectedDataActivity : BaseActivity<ActivityCollectedDataBinding>() { //class CollectedDataActivity : BaseActivity<ActivityCollectedDataBinding>() {
private val viewModel by viewModels<UserViewModel>() // private val viewModel by viewModels<UserViewModel>()
override fun getViewModel(): BaseViewModel { // override fun getViewModel(): BaseViewModel {
return viewModel // return viewModel
} // }
//
override fun inflateViewBinding(): ActivityCollectedDataBinding { // override fun inflateViewBinding(): ActivityCollectedDataBinding {
return ActivityCollectedDataBinding.inflate(layoutInflater) // return ActivityCollectedDataBinding.inflate(layoutInflater)
} // }
//
private val list: MutableList<CollectedFoodBean> = mutableListOf() // private val list: MutableList<CollectedFoodBean> = mutableListOf()
private val adapter by lazy { // private val adapter by lazy {
CollectedFoodAdapter(list).apply { // CollectedFoodAdapter(list).apply {
isStateViewEnable = true // isStateViewEnable = true
addOnItemChildClickListener(R.id.ivDeleteFood) { _, _, position -> // addOnItemChildClickListener(R.id.ivDeleteFood) { _, _, position ->
deleteGoods(position) // deleteGoods(position)
} // }
} // }
} // }
//
override fun initialize() { // override fun initialize() {
super.initialize() // super.initialize()
binding.rvFoodList.let { // binding.rvFoodList.let {
it.layoutManager = LinearLayoutManager(this) // it.layoutManager = LinearLayoutManager(this)
it.adapter = adapter // it.adapter = adapter
} // }
binding.ivBack.setOnClickListener { finish() } // binding.ivBack.setOnClickListener { finish() }
binding.ivGoodsSearch.setOnClickListener { // binding.ivGoodsSearch.setOnClickListener {
val searchName = binding.etInputGoods.text.toString().trim() // val searchName = binding.etInputGoods.text.toString().trim()
if (searchName.isBlank()) { // if (searchName.isBlank()) {
ToastUtils.showToast("请输入物品名称") // ToastUtils.showToast("请输入物品名称")
return@setOnClickListener // return@setOnClickListener
} // }
getCollectGoods(searchName) // getCollectGoods(searchName)
} // }
binding.etInputGoods.let { v -> // binding.etInputGoods.let { v ->
v.addOnActionSearchListener { // v.addOnActionSearchListener {
val searchName = binding.etInputGoods.text.toString().trim() // val searchName = binding.etInputGoods.text.toString().trim()
if (searchName.isBlank()) { // if (searchName.isBlank()) {
ToastUtils.showToast("请输入物品名称") // ToastUtils.showToast("请输入物品名称")
return@addOnActionSearchListener // return@addOnActionSearchListener
} // }
getCollectGoods(searchName) // getCollectGoods(searchName)
} // }
v.addTextChangedListener { // v.addTextChangedListener {
if (it.isNullOrBlank()) { // if (it.isNullOrBlank()) {
getCollectGoods() // getCollectGoods()
} // }
} // }
} // }
getCollectGoods() // getCollectGoods()
} // }
//
//
private var box: Box<Food>? = null // private var box: Box<Food>? = null
//
@SuppressLint("NotifyDataSetChanged") // @SuppressLint("NotifyDataSetChanged")
private fun getCollectGoods(searchName:String?=null) { // private fun getCollectGoods(searchName:String?=null) {
if (box == null) { // if (box == null) {
box = ObjectBox.boxStore.boxFor(Food::class) // box = ObjectBox.boxStore.boxFor(Food::class)
} // }
list.clear() // list.clear()
var queryList = box?.all?.distinctBy { it.name } // var queryList = box?.all?.distinctBy { it.name }
if (searchName.isNullOrBlank().not()) { // if (searchName.isNullOrBlank().not()) {
queryList = queryList?.filter { it.name?.contains(searchName) == true } // queryList = queryList?.filter { it.name?.contains(searchName) == true }
} // }
queryList?.forEach { // queryList?.forEach {
list.add(CollectedFoodBean(foodName = it.name)) // list.add(CollectedFoodBean(foodName = it.name))
} // }
adapter.notifyDataSetChanged() // adapter.notifyDataSetChanged()
if (list.isEmpty()) { // if (list.isEmpty()) {
loadEmptyView() // loadEmptyView()
} // }
binding.root.hideKeyboard() // binding.root.hideKeyboard()
} // }
//
private var emptyBinding: LayoutEmptySearchBinding? = null // private var emptyBinding: LayoutEmptySearchBinding? = null
private fun loadEmptyView() { // private fun loadEmptyView() {
if (emptyBinding == null) { // if (emptyBinding == null) {
emptyBinding = LayoutEmptySearchBinding.inflate(layoutInflater, binding.rvFoodList, false) // emptyBinding = LayoutEmptySearchBinding.inflate(layoutInflater, binding.rvFoodList, false)
} // }
emptyBinding?.root?.let { layout -> // emptyBinding?.root?.let { layout ->
layout.setOnClickListener { layout.hideKeyboard() } // layout.setOnClickListener { layout.hideKeyboard() }
adapter.stateView = layout // adapter.stateView = layout
} // }
} // }
//
private fun deleteGoods(position: Int) { // private fun deleteGoods(position: Int) {
WarnDialog( // WarnDialog(
context = context, // context = context,
content = "请确认是否删除菜品:${list[position].foodName}", // content = "请确认是否删除菜品:${list[position].foodName}",
confirmBlock = { // confirmBlock = {
Thread { // Thread {
runOnUiThread { // runOnUiThread {
showWaitingDialog("加载中……") // showWaitingDialog("加载中……")
} // }
val name = list[position].foodName // val name = list[position].foodName
val filterIdList = box?.all?.filter { it.name == name }?.map { it.id } // val filterIdList = box?.all?.filter { it.name == name }?.map { it.id }
box?.removeByIds(filterIdList) // box?.removeByIds(filterIdList)
runOnUiThread { // runOnUiThread {
hideWaitingDialog() // hideWaitingDialog()
adapter.removeAt(position) // adapter.removeAt(position)
ToastUtils.showToast("删除成功") // ToastUtils.showToast("删除成功")
if (list.isEmpty()) { // if (list.isEmpty()) {
loadEmptyView() // loadEmptyView()
} // }
} // }
}.start() // }.start()
}).show() // }).show()
} // }
} //}
@@ -0,0 +1,137 @@
package com.sw.dualscreen.activity
import android.annotation.SuppressLint
import androidx.activity.viewModels
import androidx.core.widget.addTextChangedListener
import androidx.recyclerview.widget.LinearLayoutManager
import com.sw.dualscreen.R
import com.sw.dualscreen.adapter.CollectedFoodNewAdapter
import com.sw.dualscreen.databinding.ActivityCollectedFoodBinding
import com.sw.dualscreen.databinding.LayoutEmptySearchBinding
import com.sw.dualscreen.dialog.WarnDialog
import com.sw.dualscreen.ext.addOnActionSearchListener
import com.sw.dualscreen.ext.hideKeyboard
import com.sw.dualscreen.objbox.CollectedFoodBean
import com.sw.dualscreen.objbox.Food
import com.sw.dualscreen.objbox.ObjectBox
import com.sw.dualscreen.viewmodel.BaseViewModel
import com.sw.dualscreen.viewmodel.UserViewModel
import com.sw.plate.utils.ToastUtils
import io.objectbox.Box
import io.objectbox.kotlin.boxFor
class CollectedFoodActivity : BaseActivity<ActivityCollectedFoodBinding>() {
private val viewModel by viewModels<UserViewModel>()
override fun getViewModel(): BaseViewModel {
return viewModel
}
override fun inflateViewBinding(): ActivityCollectedFoodBinding {
return ActivityCollectedFoodBinding.inflate(layoutInflater)
}
private val list: MutableList<CollectedFoodBean> = mutableListOf()
private val adapter by lazy {
CollectedFoodNewAdapter(list).apply {
isStateViewEnable = true
addOnItemChildClickListener(R.id.ivDeleteFood) { _, _, position ->
deleteGoods(position)
}
}
}
override fun initialize() {
super.initialize()
binding.rvFoodList.let {
it.layoutManager = LinearLayoutManager(this)
it.adapter = adapter
}
binding.include.let {
it.tvPageTitle.text = "已采集餐品"
it.ivPageBack.setOnClickListener { finish() }
}
binding.ivFoodSearch.setOnClickListener {
val searchName = binding.etInputFood.text.toString().trim()
if (searchName.isBlank()) {
ToastUtils.showToast("请输入物品名称")
return@setOnClickListener
}
getCollectGoods(searchName)
}
binding.etInputFood.let { v ->
v.addOnActionSearchListener {
val searchName = binding.etInputFood.text.toString().trim()
if (searchName.isBlank()) {
ToastUtils.showToast("请输入物品名称")
return@addOnActionSearchListener
}
getCollectGoods(searchName)
}
v.addTextChangedListener {
if (it.isNullOrBlank()) {
getCollectGoods()
}
}
}
getCollectGoods()
}
private var box: Box<Food>? = null
@SuppressLint("NotifyDataSetChanged")
private fun getCollectGoods(searchName: String? = null) {
if (box == null) {
box = ObjectBox.boxStore.boxFor(Food::class)
}
list.clear()
var queryList = box?.all?.distinctBy { it.name }
if (searchName.isNullOrBlank().not()) {
queryList = queryList?.filter { it.name?.contains(searchName) == true }
}
queryList?.forEach {
list.add(CollectedFoodBean(foodName = it.name))
}
adapter.notifyDataSetChanged()
if (list.isEmpty()) {
loadEmptyView()
}
binding.root.hideKeyboard()
}
private var emptyBinding: LayoutEmptySearchBinding? = null
private fun loadEmptyView() {
if (emptyBinding == null) {
emptyBinding =
LayoutEmptySearchBinding.inflate(layoutInflater, binding.rvFoodList, false)
}
emptyBinding?.root?.let { layout ->
layout.setOnClickListener { layout.hideKeyboard() }
adapter.stateView = layout
}
}
private fun deleteGoods(position: Int) {
WarnDialog(
context = context,
content = "请确认是否删除菜品:${list[position].foodName}",
confirmBlock = {
Thread {
runOnUiThread {
showWaitingDialog("加载中……")
}
val name = list[position].foodName
val filterIdList = box?.all?.filter { it.name == name }?.map { it.id }
box?.removeByIds(filterIdList)
runOnUiThread {
hideWaitingDialog()
adapter.removeAt(position)
ToastUtils.showToast("删除成功")
if (list.isEmpty()) {
loadEmptyView()
}
}
}.start()
}).show()
}
}
@@ -1,370 +1,370 @@
package com.sw.dualscreen.activity //package com.sw.dualscreen.activity
//
import android.annotation.SuppressLint //import android.annotation.SuppressLint
import android.content.Context //import android.content.Context
import android.content.Intent //import android.content.Intent
import android.graphics.Bitmap //import android.graphics.Bitmap
import android.graphics.Typeface //import android.graphics.Typeface
import android.net.Uri //import android.net.Uri
import android.view.View //import android.view.View
import android.view.inputmethod.EditorInfo //import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager //import android.view.inputmethod.InputMethodManager
import android.widget.Toast //import android.widget.Toast
import androidx.activity.viewModels //import androidx.activity.viewModels
import androidx.camera.view.PreviewView //import androidx.camera.view.PreviewView
import androidx.core.net.toUri //import androidx.core.net.toUri
import androidx.core.view.updateLayoutParams //import androidx.core.view.updateLayoutParams
import androidx.lifecycle.lifecycleScope //import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.GridLayoutManager //import androidx.recyclerview.widget.GridLayoutManager
import com.example.utils.FloatBase64Utils //import com.example.utils.FloatBase64Utils
import com.sw.dualscreen.R //import com.sw.dualscreen.R
import com.sw.dualscreen.adapter.FoodCollectionAdapter //import com.sw.dualscreen.adapter.FoodCollectionAdapter
import com.sw.dualscreen.adapter.GenericItemAdapter //import com.sw.dualscreen.adapter.GenericItemAdapter
import com.sw.dualscreen.adapter.GridSpacingItemDecoration //import com.sw.dualscreen.adapter.GridSpacingItemDecoration
import com.sw.dualscreen.adapter.dpToPx //import com.sw.dualscreen.adapter.dpToPx
import com.sw.dualscreen.databinding.ActivityFoodCollectionBinding //import com.sw.dualscreen.databinding.ActivityFoodCollectionBinding
import com.sw.dualscreen.databinding.ItemSearchFoodInfoBinding //import com.sw.dualscreen.databinding.ItemSearchFoodInfoBinding
import com.sw.dualscreen.databinding.LayoutCameraPreviewBinding //import com.sw.dualscreen.databinding.LayoutCameraPreviewBinding
import com.sw.dualscreen.ext.clickWithDebounce //import com.sw.dualscreen.ext.clickWithDebounce
import com.sw.dualscreen.ext.dp //import com.sw.dualscreen.ext.dp
import com.sw.dualscreen.model.response.FoodInfo //import com.sw.dualscreen.model.response.FoodInfo
import com.sw.dualscreen.objbox.Food //import com.sw.dualscreen.objbox.Food
import com.sw.dualscreen.objbox.FoodCollectionBean //import com.sw.dualscreen.objbox.FoodCollectionBean
import com.sw.dualscreen.objbox.FoodModule //import com.sw.dualscreen.objbox.FoodModule
import com.sw.dualscreen.objbox.ObjectBox //import com.sw.dualscreen.objbox.ObjectBox
import com.sw.dualscreen.utils.BitmapCropper //import com.sw.dualscreen.utils.BitmapCropper
import com.sw.dualscreen.utils.BitmapSaver //import com.sw.dualscreen.utils.BitmapSaver
import com.sw.dualscreen.utils.CameraHelper //import com.sw.dualscreen.utils.CameraHelper
import com.sw.dualscreen.utils.CameraUtils //import com.sw.dualscreen.utils.CameraUtils
import com.sw.dualscreen.utils.Debouncer //import com.sw.dualscreen.utils.Debouncer
import com.sw.dualscreen.utils.ImageUtil //import com.sw.dualscreen.utils.ImageUtil
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 com.sw.plate.utils.ToastUtils //import com.sw.plate.utils.ToastUtils
import io.objectbox.Box //import io.objectbox.Box
import io.objectbox.kotlin.boxFor //import io.objectbox.kotlin.boxFor
import kotlinx.coroutines.launch //import kotlinx.coroutines.launch
import org.pytorch.IValue //import org.pytorch.IValue
import org.pytorch.Module //import org.pytorch.Module
import org.pytorch.torchvision.TensorImageUtils //import org.pytorch.torchvision.TensorImageUtils
import timber.log.Timber //import timber.log.Timber
import kotlin.math.max //import kotlin.math.max
//
class FoodCollectionActivity : BaseActivity<ActivityFoodCollectionBinding>() { //class FoodCollectionActivity : BaseActivity<ActivityFoodCollectionBinding>() {
companion object { // companion object {
val MAX_COUNT = 100 // val MAX_COUNT = 100
} // }
private val viewModel by viewModels<UserViewModel>() // private val viewModel by viewModels<UserViewModel>()
private var selectedFoodId: String? = "" // private var selectedFoodId: String? = ""
private var selectedFoodName: String? = "" // private var selectedFoodName: String? = ""
//
private var box: Box<Food>? = null // private var box: Box<Food>? = null
private val foodCollectionList: MutableList<FoodCollectionBean> = mutableListOf() // private val foodCollectionList: MutableList<FoodCollectionBean> = mutableListOf()
//
// private lateinit var cameraHelper: CameraHelper //// private lateinit var cameraHelper: CameraHelper
//
private lateinit var foodAdapter: GenericItemAdapter<FoodInfo, ItemSearchFoodInfoBinding> // private lateinit var foodAdapter: GenericItemAdapter<FoodInfo, ItemSearchFoodInfoBinding>
private val foodList = mutableListOf<FoodInfo>() // 适配器内部维护的数据列表 // private val foodList = mutableListOf<FoodInfo>() // 适配器内部维护的数据列表
private val debouncer = Debouncer(2000) // private val debouncer = Debouncer(2000)
private lateinit var previewView: PreviewView // private lateinit var previewView: PreviewView
//
private val cameraUtils: CameraUtils by lazy { // private val cameraUtils: CameraUtils by lazy {
CameraUtils(this) // CameraUtils(this)
} // }
//
private val collectionAdapter: FoodCollectionAdapter by lazy { // private val collectionAdapter: FoodCollectionAdapter by lazy {
FoodCollectionAdapter(foodCollectionList).apply { // FoodCollectionAdapter(foodCollectionList).apply {
// setOnItemClickListener { _, _, position -> //// setOnItemClickListener { _, _, position ->
// if (list[position].isShowCamera) { //// if (list[position].isShowCamera) {
//// takePhoto() ////// takePhoto()
// cameraHelper.openCamera() //// cameraHelper.openCamera()
//// }
//// }
// addOnItemChildClickListener(R.id.ivDelete) { _, _, position ->
//// list.removeAt(position)
//// collectionAdapter.notifyItemRemoved(position)
//// collectionAdapter.notifyItemRangeChanged(position, list.size)
// foodCollectionList[position].let {
// it.bitmap = null
// it.isShowCamera = true
// it.isFinish = false
// }
// notifyItemChanged(position)
// }
// }
// }
//
// override fun getViewModel(): BaseViewModel {
// return viewModel
// }
//
// override fun inflateViewBinding(): ActivityFoodCollectionBinding {
// return ActivityFoodCollectionBinding.inflate(layoutInflater)
// }
//
// private val cameraCallback: (Uri) -> Unit = { uri ->
// val index = foodCollectionList.indexOfFirst { it.bitmap == null }
// if (index == -1) {
// ToastUtils.showToast("每次只允许保存${MAX_COUNT}条数据")
// rerurn@ cameraCallback
// }
// ImageUtil.uriToBitmap(this, uri)?.let { bitmap ->
//// val cropBitmap = BitmapCropper.cropCenter(
//// original = bitmap,
//// targetWidth = 1300, targetHeight = 900,
//// //offsetX = 30, offsetY = 100
//// )
// val file = BitmapSaver.saveToAppFilesDir(
// bitmap, this, "IMG_CROP_${System.currentTimeMillis()}.jpg"
// )
// Timber.d("${this.javaClass.simpleName}-cameraCallback-裁剪bitmap保存文件路径:${file?.absolutePath}")
//
// foodCollectionList[index].let {
// it.bitmap = bitmap
// it.isShowCamera = false
// it.imageUri = file?.toUri()
// }
// collectionAdapter.notifyItemChanged(index)
// }
// }
//
// @SuppressLint("NotifyDataSetChanged")
// private fun takePhoto() {
// val count = foodCollectionList.count { it.bitmap != null }
// if (count >= MAX_COUNT) {
// ToastUtils.showToast("每次只允许保存${MAX_COUNT}条数据")
// return
// }
// cameraUtils.takePhoto(cameraCallback)
// }
//
// override fun initialize() {
// cameraUtils.initCamera()
// val previewBinding =
// LayoutCameraPreviewBinding.inflate(layoutInflater, binding.flCameraPreview)
// previewView = previewBinding.previewView.also {
// it.updateLayoutParams {
// width = 180.dp
// height = 180.dp
// }
// }
// cameraUtils.setPreviewController(previewView)
// // 初始化 CameraHelper
//// cameraHelper = CameraHelper(
//// context = this,
//// caller = this,
//// authority = "${packageName}.fileprovider"
//// ) { uri, path ->
//// //if (foodCollectionList.size < 6) {
//// // val insertIndex = if (foodCollectionList.isEmpty()) 0 else foodCollectionList.size - 1
//// // foodCollectionList.add(insertIndex, FoodCollectionBean(imageUri = uri))
//// //} else {
//// // foodCollectionList[foodCollectionList.size - 1] = FoodCollectionBean(imageUri = uri)
//// //}
//// //collectionAdapter.notifyDataSetChanged()
//// cameraCallback(uri)
//// }
//
// binding.ivBack.setOnClickListener {
// val intent = Intent(this, MainActivity::class.java)
// startActivity(intent)
// finish()
// }
// repeat(MAX_COUNT) {
// foodCollectionList.add(FoodCollectionBean(isShowCamera = true))
// }
// binding.rvFoodCollection.let {
// it.layoutManager = GridLayoutManager(this, 3, GridLayoutManager.VERTICAL, false)
// it.adapter = collectionAdapter
// }
//
// binding.btnFoodSearch.setOnClickListener {
// searchInfo()
// }
//
// binding.btnSave.setOnClickListener {
// if (selectedFoodName.isNullOrBlank()) {
// Toast.makeText(this, "请选择菜品名称", Toast.LENGTH_SHORT).show()
// return@setOnClickListener
// }
// if (foodCollectionList.size <= 1) {
// Toast.makeText(this, "请拍摄菜品照片", Toast.LENGTH_SHORT).show()
// return@setOnClickListener
// }
// vectorThread()
// }
//
// binding.editFoodName.setOnEditorActionListener { v, actionId, event ->
// if (actionId == EditorInfo.IME_ACTION_SEARCH) {
// searchInfo()
// val imm =
// v.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
// imm.hideSoftInputFromWindow(v.windowToken, 0)
// true
// } else {
// false
// }
// }
//
// binding.btnCollectedGoods.setOnClickListener {
// startActivity(Intent(this, CollectedDataActivity::class.java))
// }
// binding.btnTakePhoto.clickWithDebounce {
// binding.btnTakePhoto.text = "拍照"
// val count = foodCollectionList.count { it.bitmap != null }
// if (count >= MAX_COUNT) {
// ToastUtils.showToast("每次只允许保存${MAX_COUNT}条数据")
// return@clickWithDebounce
// }
//// cameraHelper.openCamera()
// takePhoto()
// }
// binding.btnClearData.setOnClickListener { clearData() }
// foodAdapter = createAdapter()
// binding.recyclerview.layoutManager = GridLayoutManager(context, 2)
// // 添加间距装饰(12dp)
// binding.recyclerview.addItemDecoration(
// GridSpacingItemDecoration(
// spanCount = 2,
// spacing = dpToPx(30),
// includeEdge = false // 包含边缘间距
// )
// )
// binding.recyclerview.adapter = foodAdapter
// }
//
// private fun vectorThread() {
// //Loading.show(this)
// showWaitingDialog("加载中……")
// Thread {
// foodCollectionList
// .filter { it.bitmap != null }
// .forEachIndexed { index, it ->
// image2VectorTask(it, index)
// }
// runOnUiThread {
// window.decorView.postDelayed({
// //Loading.dismiss()
// hideWaitingDialog()
// }, 1000)
// }
// }.start()
// }
//
// private fun initBox() {
// if (box == null) {
// box = ObjectBox.boxStore.boxFor(Food::class)
// }
// }
//
// private fun image2VectorTask(item: FoodCollectionBean, position: Int) {
// initBox()
// val imageVector = FoodModule.bitmap2FloatArray(item.bitmap!!)
//
// val base64Str = FloatBase64Utils.floatArrayToBase64(imageVector)
// Timber.tag("mzf1").e(base64Str)
//// viewModel.postImageData(
//// context,
//// foodId = selectedFoodId.toString(),
//// foodName = selectedFoodName.toString(),
//// foodVector = base64Str,
//// uri = item.imageUri!!
//// )
// box?.put(Food(name = checkedItem!!.foodName, foodIdx = 0, foodVector = imageVector))
// foodCollectionList[position].let {
// it.imageVector = imageVector
// it.isFinish = true
// }
//
// runOnUiThread {
// collectionAdapter.notifyItemChanged(position)
// }
// }
//
//
// private fun searchInfo() {
// debouncer.debounce {
// viewModel.searchByFoodName(binding.editFoodName.text.toString())
// }
// }
//
// override fun registerDataChange() {
// super.registerDataChange()
// lifecycleScope.launch {
// viewModel.searchFoodInfoList.collect {
//// foodList.clear()
//// foodList.addAll(it)
// foodAdapter.updateData(it)
// }
// }
// }
//
//
// private var checkedItem: FoodInfo? = null
// private fun createAdapter(): GenericItemAdapter<FoodInfo, ItemSearchFoodInfoBinding> {
// return GenericItemAdapter(
// items = emptyList(),
// bindingInflater = ItemSearchFoodInfoBinding::inflate,
// bindCallback = { item, position ->
// this.tvName.text = item.foodName
// if (item.id != checkedItem?.id) {
// this.tvName.typeface = Typeface.defaultFromStyle(Typeface.NORMAL)
// this.tvName.setTextColor(resources.getColor(R.color.search_normal))
// this.llRoot.setBackgroundResource(R.drawable.grid_search_item_normal)
// } else {
// this.tvName.typeface = Typeface.defaultFromStyle(Typeface.BOLD)
// this.tvName.setTextColor(resources.getColor(R.color.search_checked))
// this.llRoot.setBackgroundResource(R.drawable.grid_search_item_checked)
// }
//
// this.llRoot.setOnClickListener {
// Timber.d("itemClick ${item.foodName}, position = $position")
// checkedItem = item
//// viewModel.updateCurrentItem(item)
//// itemClickCallback(item)
// selectedFoodName = item.foodName
// selectedFoodId = item.id
//
// foodAdapter.notifyDataSetChanged()
// } // }
// } // }
addOnItemChildClickListener(R.id.ivDelete) { _, _, position ->
// list.removeAt(position)
// collectionAdapter.notifyItemRemoved(position)
// collectionAdapter.notifyItemRangeChanged(position, list.size)
foodCollectionList[position].let {
it.bitmap = null
it.isShowCamera = true
it.isFinish = false
}
notifyItemChanged(position)
}
}
}
override fun getViewModel(): BaseViewModel {
return viewModel
}
override fun inflateViewBinding(): ActivityFoodCollectionBinding {
return ActivityFoodCollectionBinding.inflate(layoutInflater)
}
private val cameraCallback: (Uri) -> Unit = { uri ->
val index = foodCollectionList.indexOfFirst { it.bitmap == null }
if (index == -1) {
ToastUtils.showToast("每次只允许保存${MAX_COUNT}条数据")
rerurn@ cameraCallback
}
ImageUtil.uriToBitmap(this, uri)?.let { bitmap ->
// val cropBitmap = BitmapCropper.cropCenter(
// original = bitmap,
// targetWidth = 1300, targetHeight = 900,
// //offsetX = 30, offsetY = 100
// )
val file = BitmapSaver.saveToAppFilesDir(
bitmap, this, "IMG_CROP_${System.currentTimeMillis()}.jpg"
)
Timber.d("${this.javaClass.simpleName}-cameraCallback-裁剪bitmap保存文件路径:${file?.absolutePath}")
foodCollectionList[index].let {
it.bitmap = bitmap
it.isShowCamera = false
it.imageUri = file?.toUri()
}
collectionAdapter.notifyItemChanged(index)
}
}
@SuppressLint("NotifyDataSetChanged")
private fun takePhoto() {
val count = foodCollectionList.count { it.bitmap != null }
if (count >= MAX_COUNT) {
ToastUtils.showToast("每次只允许保存${MAX_COUNT}条数据")
return
}
cameraUtils.takePhoto(cameraCallback)
}
override fun initialize() {
cameraUtils.initCamera()
val previewBinding =
LayoutCameraPreviewBinding.inflate(layoutInflater, binding.flCameraPreview)
previewView = previewBinding.previewView.also {
it.updateLayoutParams {
width = 180.dp
height = 180.dp
}
}
cameraUtils.setPreviewController(previewView)
// 初始化 CameraHelper
// cameraHelper = CameraHelper(
// context = this,
// caller = this,
// authority = "${packageName}.fileprovider"
// ) { uri, path ->
// //if (foodCollectionList.size < 6) {
// // val insertIndex = if (foodCollectionList.isEmpty()) 0 else foodCollectionList.size - 1
// // foodCollectionList.add(insertIndex, FoodCollectionBean(imageUri = uri))
// //} else {
// // foodCollectionList[foodCollectionList.size - 1] = FoodCollectionBean(imageUri = uri)
// //}
// //collectionAdapter.notifyDataSetChanged()
// cameraCallback(uri)
// }
binding.ivBack.setOnClickListener {
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
finish()
}
repeat(MAX_COUNT) {
foodCollectionList.add(FoodCollectionBean(isShowCamera = true))
}
binding.rvFoodCollection.let {
it.layoutManager = GridLayoutManager(this, 3, GridLayoutManager.VERTICAL, false)
it.adapter = collectionAdapter
}
binding.btnFoodSearch.setOnClickListener {
searchInfo()
}
binding.btnSave.setOnClickListener {
if (selectedFoodName.isNullOrBlank()) {
Toast.makeText(this, "请选择菜品名称", Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
if (foodCollectionList.size <= 1) {
Toast.makeText(this, "请拍摄菜品照片", Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
vectorThread()
}
binding.editFoodName.setOnEditorActionListener { v, actionId, event ->
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
searchInfo()
val imm =
v.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(v.windowToken, 0)
true
} else {
false
}
}
binding.btnCollectedGoods.setOnClickListener {
startActivity(Intent(this, CollectedDataActivity::class.java))
}
binding.btnTakePhoto.clickWithDebounce {
binding.btnTakePhoto.text = "拍照"
val count = foodCollectionList.count { it.bitmap != null }
if (count >= MAX_COUNT) {
ToastUtils.showToast("每次只允许保存${MAX_COUNT}条数据")
return@clickWithDebounce
}
// cameraHelper.openCamera()
takePhoto()
}
binding.btnClearData.setOnClickListener { clearData() }
foodAdapter = createAdapter()
binding.recyclerview.layoutManager = GridLayoutManager(context, 2)
// 添加间距装饰(12dp)
binding.recyclerview.addItemDecoration(
GridSpacingItemDecoration(
spanCount = 2,
spacing = dpToPx(30),
includeEdge = false // 包含边缘间距
)
)
binding.recyclerview.adapter = foodAdapter
}
private fun vectorThread() {
//Loading.show(this)
showWaitingDialog("加载中……")
Thread {
foodCollectionList
.filter { it.bitmap != null }
.forEachIndexed { index, it ->
image2VectorTask(it, index)
}
runOnUiThread {
window.decorView.postDelayed({
//Loading.dismiss()
hideWaitingDialog()
}, 1000)
}
}.start()
}
private fun initBox() {
if (box == null) {
box = ObjectBox.boxStore.boxFor(Food::class)
}
}
private fun image2VectorTask(item: FoodCollectionBean, position: Int) {
initBox()
val imageVector = FoodModule.bitmap2FloatArray(item.bitmap!!)
val base64Str = FloatBase64Utils.floatArrayToBase64(imageVector)
Timber.tag("mzf1").e(base64Str)
// viewModel.postImageData(
// context,
// foodId = selectedFoodId.toString(),
// foodName = selectedFoodName.toString(),
// foodVector = base64Str,
// uri = item.imageUri!!
// ) // )
box?.put(Food(name = checkedItem!!.foodName, foodIdx = 0, foodVector = imageVector)) // }
foodCollectionList[position].let { //
it.imageVector = imageVector // private var clickIndex = -1
it.isFinish = true //
} // @SuppressLint("NotifyDataSetChanged")
// private fun clearData() {
runOnUiThread { // foodCollectionList.forEach {
collectionAdapter.notifyItemChanged(position) // it.bitmap = null
} // it.isShowCamera = true
} // it.isFinish = false
// }
// collectionAdapter.notifyDataSetChanged()
private fun searchInfo() { //
debouncer.debounce { // clickIndex = -1
viewModel.searchByFoodName(binding.editFoodName.text.toString()) // binding.editFoodName.setText("")
} //// foodList.clear()
} //// foodAdapter.updateData(mutableListOf())
//// foodAdapter.notifyDataSetChanged()
override fun registerDataChange() { // //loadEmptyView()
super.registerDataChange() // }
lifecycleScope.launch { //
viewModel.searchFoodInfoList.collect { // override fun onResume() {
// foodList.clear() // super.onResume()
// foodList.addAll(it) // cameraUtils.bind()
foodAdapter.updateData(it) // binding.llCameraFlag.run {
} // visibility = View.VISIBLE
} // postDelayed({
} // visibility = View.GONE
// }, 3000)
// }
private var checkedItem: FoodInfo? = null // }
private fun createAdapter(): GenericItemAdapter<FoodInfo, ItemSearchFoodInfoBinding> { //
return GenericItemAdapter( // override fun onPause() {
items = emptyList(), // super.onPause()
bindingInflater = ItemSearchFoodInfoBinding::inflate, // cameraUtils.unbind()
bindCallback = { item, position -> // binding.llCameraFlag.visibility = View.VISIBLE
this.tvName.text = item.foodName // }
if (item.id != checkedItem?.id) { //
this.tvName.typeface = Typeface.defaultFromStyle(Typeface.NORMAL) //}
this.tvName.setTextColor(resources.getColor(R.color.search_normal))
this.llRoot.setBackgroundResource(R.drawable.grid_search_item_normal)
} else {
this.tvName.typeface = Typeface.defaultFromStyle(Typeface.BOLD)
this.tvName.setTextColor(resources.getColor(R.color.search_checked))
this.llRoot.setBackgroundResource(R.drawable.grid_search_item_checked)
}
this.llRoot.setOnClickListener {
Timber.d("itemClick ${item.foodName}, position = $position")
checkedItem = item
// viewModel.updateCurrentItem(item)
// itemClickCallback(item)
selectedFoodName = item.foodName
selectedFoodId = item.id
foodAdapter.notifyDataSetChanged()
}
}
)
}
private var clickIndex = -1
@SuppressLint("NotifyDataSetChanged")
private fun clearData() {
foodCollectionList.forEach {
it.bitmap = null
it.isShowCamera = true
it.isFinish = false
}
collectionAdapter.notifyDataSetChanged()
clickIndex = -1
binding.editFoodName.setText("")
// foodList.clear()
// foodAdapter.updateData(mutableListOf())
// foodAdapter.notifyDataSetChanged()
//loadEmptyView()
}
override fun onResume() {
super.onResume()
cameraUtils.bind()
binding.llCameraFlag.run {
visibility = View.VISIBLE
postDelayed({
visibility = View.GONE
}, 3000)
}
}
override fun onPause() {
super.onPause()
cameraUtils.unbind()
binding.llCameraFlag.visibility = View.VISIBLE
}
}
@@ -1,5 +1,6 @@
package com.sw.dualscreen.activity package com.sw.dualscreen.activity
import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.Outline import android.graphics.Outline
@@ -28,11 +29,13 @@ import com.sw.dualscreen.GlobalKey
import com.sw.dualscreen.R import com.sw.dualscreen.R
import com.sw.dualscreen.adapter.GenericItemAdapter import com.sw.dualscreen.adapter.GenericItemAdapter
import com.sw.dualscreen.adapter.GridSpacingItemDecoration import com.sw.dualscreen.adapter.GridSpacingItemDecoration
import com.sw.dualscreen.adapter.SearchFoodAdapter
import com.sw.dualscreen.adapter.dpToPx import com.sw.dualscreen.adapter.dpToPx
import com.sw.dualscreen.databinding.ActivityMainBinding import com.sw.dualscreen.databinding.ActivityMainBinding
import com.sw.dualscreen.databinding.ItemFoodInfoBinding import com.sw.dualscreen.databinding.ItemFoodInfoBinding
import com.sw.dualscreen.ext.dp import com.sw.dualscreen.ext.dp
import com.sw.dualscreen.ext.format2String import com.sw.dualscreen.ext.format2String
import com.sw.dualscreen.ext.visible
import com.sw.dualscreen.model.response.FoodInfo import com.sw.dualscreen.model.response.FoodInfo
import com.sw.dualscreen.objbox.FoodModule import com.sw.dualscreen.objbox.FoodModule
import com.sw.dualscreen.objbox.FoodModule.IdNameScore import com.sw.dualscreen.objbox.FoodModule.IdNameScore
@@ -55,6 +58,10 @@ import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
import java.io.File import java.io.File
import java.time.LocalDateTime
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.util.Locale
import java.util.concurrent.Executors import java.util.concurrent.Executors
import kotlin.math.roundToInt import kotlin.math.roundToInt
@@ -67,7 +74,23 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
private var isAnalyzing = true // 控制是否进行图像分析 private var isAnalyzing = true // 控制是否进行图像分析
private var presentation: SecondaryScreenPresentation? = null private var presentation: SecondaryScreenPresentation? = null
private val executor = Executors.newSingleThreadExecutor() private val executor = Executors.newSingleThreadExecutor()
private lateinit var adapter: GenericItemAdapter<FoodInfo, ItemFoodInfoBinding> private val searchFoodList = mutableListOf<FoodInfo>()
private val adapter by lazy {
SearchFoodAdapter(searchFoodList).apply {
setOnItemClickListener { adapter, view, position ->
searchFoodList.forEachIndexed { index, info ->
searchFoodList[index].isChecked = index == position
}
val item = searchFoodList[position]
Timber.d("itemClick ${item.foodName}, position = $position")
item.photoUri = null
checkedItem = item
notifyDataSetChanged()
// TODO 暂时注释---------------
//updateCurrentFood(item)
}
}
}
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
@@ -102,11 +125,16 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
private fun initView() { private fun initView() {
viewModel.activeEngine() viewModel.activeEngine()
binding.foodDisplayLayout.setOnClickListener { updateDateTime()
val intent = Intent(this, FoodCollectionActivity::class.java) binding.ivSetting.setOnClickListener {
startActivity(intent) startActivity(Intent(this, SettingActivity::class.java))
finish() finish()
} }
//binding.foodDisplayLayout.setOnClickListener {
// val intent = Intent(this, FoodCollectionActivity::class.java)
// startActivity(intent)
// finish()
//}
binding.previewView.outlineProvider = object : ViewOutlineProvider() { binding.previewView.outlineProvider = object : ViewOutlineProvider() {
override fun getOutline(view: View, outline: Outline) { override fun getOutline(view: View, outline: Outline) {
outline.setRoundRect(0, 0, view.width, view.height, 12f.dp) outline.setRoundRect(0, 0, view.width, view.height, 12f.dp)
@@ -121,49 +149,57 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
bottomSheetDialog!!.show(supportFragmentManager, "CustomBottomSheetDialog") bottomSheetDialog!!.show(supportFragmentManager, "CustomBottomSheetDialog")
} }
val spinnerAdapter = ArrayAdapter<String>( //val spinnerAdapter = ArrayAdapter<String>(
this, // this,
R.layout.item_for_custom_spinner, // R.layout.item_for_custom_spinner,
arrayOf("即放即取", "余量取餐") // arrayOf("即放即取", "余量取餐")
) //)
binding.spinner.adapter = spinnerAdapter //binding.spinner.adapter = spinnerAdapter
val mode = SPUtil.getInstance().get(GlobalKey.KEY_PICKUP_MODE, 0) val mode = SPUtil.getInstance().get(GlobalKey.KEY_PICKUP_MODE, 0)
binding.spinner.setSelection(mode ?: 0) //binding.spinner.setSelection(mode ?: 0)
presentation?.updateMealPickupMode(mode ?: 0) presentation?.updateMealPickupMode(mode ?: 0)
binding.spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { //binding.spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected( // override fun onItemSelected(
parent: AdapterView<*>?, // parent: AdapterView<*>?,
view: View?, // view: View?,
position: Int, // position: Int,
id: Long // id: Long
) { // ) {
SPUtil.getInstance().put(GlobalKey.KEY_PICKUP_MODE, position) // SPUtil.getInstance().put(GlobalKey.KEY_PICKUP_MODE, position)
updateCurrentFood(null) // updateCurrentFood(null)
isRecognitionFood = true // isRecognitionFood = true
presentation?.updateMealPickupMode(position) // presentation?.updateMealPickupMode(position)
//
SensorScaleUtils.zero() // SensorScaleUtils.zero()
} // }
//
override fun onNothingSelected(parent: AdapterView<*>?) {} // override fun onNothingSelected(parent: AdapterView<*>?) {}
//}
//adapter = createAdapter()
binding.recyclerview.let {
it.layoutManager = GridLayoutManager(this, 2)
it.adapter = adapter
} }
adapter = createAdapter()
binding.recyclerview.layoutManager = GridLayoutManager(this, 2)
// 添加间距装饰(12dp) // 添加间距装饰(12dp)
binding.recyclerview.addItemDecoration( //binding.recyclerview.addItemDecoration(
GridSpacingItemDecoration( // GridSpacingItemDecoration(
spanCount = 2, // spanCount = 2,
spacing = dpToPx(30), // spacing = dpToPx(30),
includeEdge = false // 包含边缘间距 // includeEdge = false // 包含边缘间距
) // )
) //)
binding.recyclerview.adapter = adapter //binding.recyclerview.adapter = adapter
binding.tvFoodName.setOnClickListener { binding.tvFoodName.setOnClickListener {
SensorScaleUtils.zero() SensorScaleUtils.zero()
} }
binding.tvRescan.setOnClickListener { binding.tvRescan.setOnClickListener {
debouncer.debounce { recognizeFood() } debouncer.debounce { recognizeFood() }
} }
binding.btnPay.setOnClickListener {
startActivity(Intent(this, PayActivity::class.java).apply {
putExtra(PayActivity.FOOD_INFO, checkedItem)
})
}
} }
fun updateCurrentFood(foodInfo: FoodInfo?) { fun updateCurrentFood(foodInfo: FoodInfo?) {
@@ -204,7 +240,23 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
// } // }
lifecycleScope.launch { lifecycleScope.launch {
viewModel.identifiedFoodInfoList.collect { list -> viewModel.identifiedFoodInfoList.collect { list ->
adapter.updateData(list) //adapter.updateData(list)
searchFoodList.clear()
searchFoodList.addAll(list)
adapter.notifyDataSetChanged()
//TODO 暂时写死数据测试---------------------------
binding.flPay.visible()
binding.recyclerview.visible()
searchFoodList.clear()
searchFoodList.add(FoodInfo(foodName = "岐山臊子面"))
searchFoodList.add(FoodInfo(foodName = "肉末干拌面"))
searchFoodList.add(FoodInfo(foodName = "雪菜肉丝面"))
searchFoodList.add(FoodInfo(foodName = "康帅博方便面"))
searchFoodList.add(FoodInfo(foodName = "担担面"))
searchFoodList.add(FoodInfo(foodName = "四合一干拌面"))
adapter.notifyDataSetChanged()
if (list.isNotEmpty()) { if (list.isNotEmpty()) {
checkedItem = list[0] checkedItem = list[0]
checkedItem!!.photoUri = lastPhotoUri checkedItem!!.photoUri = lastPhotoUri
@@ -213,7 +265,8 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
} }
} }
} }
SensorScaleUtils.startScale { weight ->
SensorScaleUtils.addWeightListener { weight ->
Timber.d("registerDataChange weight = $weight") Timber.d("registerDataChange weight = $weight")
presentation?.updateWeight(weight) presentation?.updateWeight(weight)
@@ -281,6 +334,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
} }
} }
@SuppressLint("NotifyDataSetChanged")
private fun updateFoodInfo(list: List<FoodInfo>, scoreList: List<IdNameScore>) { private fun updateFoodInfo(list: List<FoodInfo>, scoreList: List<IdNameScore>) {
Timber.d("registerDataChange识别后查询接口数据:${GsonUtils.toJson(list)}") Timber.d("registerDataChange识别后查询接口数据:${GsonUtils.toJson(list)}")
list.forEach { foodInfo -> list.forEach { foodInfo ->
@@ -288,7 +342,10 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
val score = scoreItem?.score ?: 0.0 val score = scoreItem?.score ?: 0.0
foodInfo.score = ((1 - score) * 10000).roundToInt() foodInfo.score = ((1 - score) * 10000).roundToInt()
} }
adapter.updateData(list) searchFoodList.clear()
searchFoodList.addAll(list)
adapter.notifyDataSetChanged()
//adapter.updateData(list)
if (list.isNotEmpty()) { if (list.isNotEmpty()) {
checkedItem = list[0] checkedItem = list[0]
checkedItem!!.photoUri = lastPhotoUri checkedItem!!.photoUri = lastPhotoUri
@@ -298,33 +355,33 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
} }
} }
private fun createAdapter(): GenericItemAdapter<FoodInfo, ItemFoodInfoBinding> { // private fun createAdapter(): GenericItemAdapter<FoodInfo, ItemFoodInfoBinding> {
return GenericItemAdapter( // return GenericItemAdapter(
items = emptyList(), // items = emptyList(),
bindingInflater = ItemFoodInfoBinding::inflate, // bindingInflater = ItemFoodInfoBinding::inflate,
bindCallback = { item, position -> // bindCallback = { item, position ->
val score = (item.score / 100.0).format2String(2) // val score = (item.score / 100.0).format2String(2)
this.tvName.text = "${item.foodName}\n${score}%" // this.tvName.text = "${item.foodName}\n${score}%"
if (item.id != checkedItem?.id) { // if (item.id != checkedItem?.id) {
this.tvName.typeface = Typeface.defaultFromStyle(Typeface.NORMAL) // this.tvName.typeface = Typeface.defaultFromStyle(Typeface.NORMAL)
this.tvName.setTextColor(resources.getColor(R.color.identify_normal)) // this.tvName.setTextColor(resources.getColor(R.color.identify_normal))
this.llRoot.setBackgroundResource(R.drawable.grid_item_normal) // this.llRoot.setBackgroundResource(R.drawable.grid_item_normal)
} else { // } else {
this.tvName.typeface = Typeface.defaultFromStyle(Typeface.BOLD) // this.tvName.typeface = Typeface.defaultFromStyle(Typeface.BOLD)
this.tvName.setTextColor(resources.getColor(R.color.identify_checked)) // this.tvName.setTextColor(resources.getColor(R.color.identify_checked))
this.llRoot.setBackgroundResource(R.drawable.grid_item_checked) // this.llRoot.setBackgroundResource(R.drawable.grid_item_checked)
} // }
// ////
this.llRoot.setOnClickListener { // this.llRoot.setOnClickListener {
Timber.d("itemClick ${item.foodName}, position = $position") // Timber.d("itemClick ${item.foodName}, position = $position")
item.photoUri = null // item.photoUri = null
checkedItem = item // checkedItem = item
adapter.notifyDataSetChanged() // adapter.notifyDataSetChanged()
updateCurrentFood(item) // updateCurrentFood(item)
} // }
} // }
) // )
} // }
private fun setupCamera() { private fun setupCamera() {
Timber.d("setupCamera") Timber.d("setupCamera")
@@ -496,15 +553,24 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
} }
} }
@SuppressLint("NotifyDataSetChanged")
fun clearFoodList() { fun clearFoodList() {
adapter.updateData(listOf()) //adapter.updateData(listOf())
searchFoodList.clear()
adapter.notifyDataSetChanged() adapter.notifyDataSetChanged()
} }
override fun onDestroy() { override fun onDestroy() {
SensorScaleUtils.closeScale() //SensorScaleUtils.closeScale()
presentation?.dismiss() presentation?.dismiss()
super.onDestroy() super.onDestroy()
shutdownCamera() shutdownCamera()
} }
private fun updateDateTime() {
val formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 EEEE", Locale.CHINA)
val dateTime = formatter.format(LocalDateTime.now(ZoneId.of("Asia/Shanghai")))
binding.tvTitleTime.text = dateTime
}
} }
@@ -0,0 +1,128 @@
package com.sw.dualscreen.activity
import android.view.View
import androidx.activity.viewModels
import androidx.fragment.app.Fragment
import com.sw.dualscreen.R
import com.sw.dualscreen.activity.fragment.CashPayFragment
import com.sw.dualscreen.activity.fragment.FacePayFragment
import com.sw.dualscreen.activity.fragment.NumberPayFragment
import com.sw.dualscreen.activity.fragment.PayResultFragment
import com.sw.dualscreen.activity.fragment.QrCodePayFragment
import com.sw.dualscreen.databinding.ActivityPayBinding
import com.sw.dualscreen.model.response.FoodInfo
import com.sw.dualscreen.viewmodel.BaseViewModel
import com.sw.dualscreen.viewmodel.UserViewModel
class PayActivity : BaseActivity<ActivityPayBinding>() {
companion object {
const val FOOD_INFO = "foodInfo"
const val TAG_PAY_QR_CODE = "tagPayQrCode"
const val TAG_PAY_CASH = "tagPayCash"
const val TAG_PAY_NUMBER = "tagPayNumber"
const val TAG_PAY_FACE = "tagPayFace"
const val TAG_PAY_RESULT = "tagPayResult"
}
private val viewModel by viewModels<UserViewModel>()
override fun getViewModel(): BaseViewModel {
return viewModel
}
override fun inflateViewBinding(): ActivityPayBinding {
return ActivityPayBinding.inflate(layoutInflater)
}
var foodInfo: FoodInfo? = null
private var qrCodePayFragment: QrCodePayFragment? = null
private var cashPayFragment: CashPayFragment? = null
private var numberPayFragment: NumberPayFragment? = null
private var facePayFragment: FacePayFragment? = null
private var payResultFragment: PayResultFragment? = null
@Suppress("DEPRECATION")
override fun initialize() {
super.initialize()
foodInfo = intent.getParcelableExtra(FOOD_INFO)
binding.tvFoodName.text = foodInfo?.foodName
binding.include.ivPageBack.setOnClickListener { finish() }
binding.include.tvPageTitle.text = "下单结算"
val payQrCodeClickListener = View.OnClickListener {
if (qrCodePayFragment == null) {
qrCodePayFragment = QrCodePayFragment()
}
addFragment(qrCodePayFragment!!, TAG_PAY_QR_CODE)
switchButton(true, false, false, false)
}
binding.btnPayQrCode.setOnClickListener(payQrCodeClickListener)
binding.btnPayCash.setOnClickListener {
if (cashPayFragment == null) {
cashPayFragment = CashPayFragment()
}
addFragment(cashPayFragment!!, TAG_PAY_CASH)
switchButton(false, true, false, false)
}
binding.btnPayNumber.setOnClickListener {
if (numberPayFragment == null) {
numberPayFragment = NumberPayFragment()
}
addFragment(numberPayFragment!!, TAG_PAY_NUMBER)
switchButton(false, false, true, false)
}
binding.btnPayFace.setOnClickListener {
showFacePay()
}
payQrCodeClickListener.onClick(binding.btnPayQrCode)
}
private fun switchButton(vararg arr: Boolean) {
binding.btnPayQrCode.isChecked = arr[0]
binding.btnPayCash.isChecked = arr[1]
binding.btnPayNumber.isChecked = arr[2]
binding.btnPayFace.isChecked = arr[3]
}
fun showFacePay() {
if (facePayFragment == null) {
facePayFragment = FacePayFragment()
}
addFragment(facePayFragment!!, TAG_PAY_FACE)
switchButton(false, false, false, true)
}
private fun addFragment(currentFragment: Fragment, tag: String) {
runCatching {
supportFragmentManager.beginTransaction().apply {
val existFragment = supportFragmentManager.findFragmentByTag(tag)
if (existFragment == null) {
add(R.id.fragmentContainerView, currentFragment, tag)
}
val fragments = supportFragmentManager.fragments
fragments.forEach {
it?.let { fragment ->
if (fragment != currentFragment) {
hide(fragment)
}
}
}
show(currentFragment)
commitAllowingStateLoss()
}
}.onFailure {
it.printStackTrace()
}
}
fun showPayResult() {
if (payResultFragment == null) {
payResultFragment = PayResultFragment()
}
addFragment(payResultFragment!!, TAG_PAY_RESULT)
}
}
@@ -0,0 +1,71 @@
package com.sw.dualscreen.activity
import android.content.Intent
import androidx.activity.viewModels
import androidx.fragment.app.Fragment
import com.sw.dualscreen.R
import com.sw.dualscreen.activity.fragment.BusinessFragment
import com.sw.dualscreen.activity.fragment.CollectFragment
import com.sw.dualscreen.databinding.ActivitySettingBinding
import com.sw.dualscreen.model.response.FoodInfo
import com.sw.dualscreen.viewmodel.BaseViewModel
import com.sw.dualscreen.viewmodel.UserViewModel
import kotlin.collections.get
import kotlin.text.replace
class SettingActivity : BaseActivity<ActivitySettingBinding>() {
private val viewModel by viewModels<UserViewModel>()
override fun getViewModel(): BaseViewModel {
return viewModel
}
override fun inflateViewBinding(): ActivitySettingBinding {
return ActivitySettingBinding.inflate(layoutInflater)
}
private val fragmentList = mutableListOf<Fragment>().apply {
add(BusinessFragment())
add(CollectFragment())
}
override fun initialize() {
super.initialize()
binding.include.let {
it.ivPageBack.setOnClickListener {
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
finish()
}
it.tvPageTitle.text = "设置"
}
binding.rgSetting.setOnCheckedChangeListener { group, checkedId ->
if (checkedId == R.id.rbBusiness) {
showFragment(fragmentList[0])
return@setOnCheckedChangeListener
}
if (checkedId == R.id.rbCollect) {
showFragment(fragmentList[1])
return@setOnCheckedChangeListener
}
}
binding.rgSetting.check(R.id.rbBusiness)
}
private fun showFragment(fragment: Fragment) {
runCatching {
supportFragmentManager.beginTransaction().apply {
replace(R.id.fragmentContainerView, fragment)
commit()
}
}.onFailure {
it.printStackTrace()
}
}
fun searchByFoodName(foodName:String, action: (List<FoodInfo>) -> Unit) {
viewModel.searchByFoodName(foodName, action)
}
}
@@ -0,0 +1,32 @@
package com.sw.dualscreen.activity.fragment
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.viewbinding.ViewBinding
abstract class BaseFragment<VB : ViewBinding>: Fragment() {
protected lateinit var binding: VB
protected abstract fun inflateViewBinding(): VB
abstract fun initialize()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = inflateViewBinding()
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initialize()
}
}
@@ -0,0 +1,42 @@
package com.sw.dualscreen.activity.fragment
import android.view.LayoutInflater
import com.sw.dualscreen.GlobalKey
import com.sw.dualscreen.R
import com.sw.dualscreen.databinding.FragmentBusinessBinding
import com.sw.dualscreen.sdk.SensorScaleUtils
import com.sw.dualscreen.utils.SPUtil
import kotlin.math.roundToInt
class BusinessFragment: BaseFragment<FragmentBusinessBinding>() {
override fun inflateViewBinding(): FragmentBusinessBinding {
return FragmentBusinessBinding.inflate(LayoutInflater.from(context))
}
override fun initialize() {
binding.rgCharge.let {
it.setOnCheckedChangeListener { group, checkedId ->
val mode = if (checkedId == R.id.rbChargeYes) 0 else 1
SPUtil.getInstance().put(GlobalKey.KEY_CHARGE_MODE, mode)
}
val mode = SPUtil.getInstance().get(GlobalKey.KEY_CHARGE_MODE, 0)
it.check(if (mode == 0) R.id.rbChargeYes else R.id.rbChargeNot)
}
binding.rgTakeFood.let {
it.setOnCheckedChangeListener { group, checkedId ->
val mode = if (checkedId == R.id.rbPickAndPlace) 0 else 1
SPUtil.getInstance().put(GlobalKey.KEY_PICKUP_MODE, mode)
}
val mode = SPUtil.getInstance().get(GlobalKey.KEY_PICKUP_MODE, 0)
it.check(if (mode == 0) R.id.rbPickAndPlace else R.id.rbSurplusCalculate)
}
binding.btnClearZero.setOnClickListener {
SensorScaleUtils.tare()
}
SensorScaleUtils.addWeightListener { value ->
val realWeight = (value * 1000).roundToInt()
binding.tvFoodWeight.text = "$realWeight"
}
}
}
@@ -0,0 +1,25 @@
package com.sw.dualscreen.activity.fragment
import android.text.Spanned
import android.text.SpannedString
import android.text.style.AbsoluteSizeSpan
import androidx.core.text.buildSpannedString
import com.sw.dualscreen.databinding.FragmentCashPayBinding
class CashPayFragment: BaseFragment<FragmentCashPayBinding>() {
override fun inflateViewBinding(): FragmentCashPayBinding {
return FragmentCashPayBinding.inflate(layoutInflater)
}
override fun initialize() {
binding.tvRealAmount.text = getAmountText("36.8")
}
private fun getAmountText(amount:String): SpannedString {
return buildSpannedString {
append("¥", AbsoluteSizeSpan(36, true), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
append(amount, AbsoluteSizeSpan(60, true), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
}
}
}
@@ -0,0 +1,285 @@
package com.sw.dualscreen.activity.fragment
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.view.LayoutInflater
import android.view.View
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.widget.Toast
import androidx.camera.view.PreviewView
import androidx.core.net.toUri
import androidx.core.view.updateLayoutParams
import androidx.recyclerview.widget.GridLayoutManager
import com.sw.dualscreen.R
import com.sw.dualscreen.activity.CollectedFoodActivity
import com.sw.dualscreen.activity.SettingActivity
import com.sw.dualscreen.adapter.FoodCollectionAdapter
import com.sw.dualscreen.adapter.SearchFoodAdapter
import com.sw.dualscreen.databinding.FragmentCollectBinding
import com.sw.dualscreen.databinding.LayoutCameraPreviewBinding
import com.sw.dualscreen.ext.clickWithDebounce
import com.sw.dualscreen.ext.dp
import com.sw.dualscreen.model.response.FoodInfo
import com.sw.dualscreen.objbox.Food
import com.sw.dualscreen.objbox.FoodCollectionBean
import com.sw.dualscreen.objbox.FoodModule
import com.sw.dualscreen.objbox.ObjectBox
import com.sw.dualscreen.utils.BitmapSaver
import com.sw.dualscreen.utils.CameraUtils
import com.sw.dualscreen.utils.Debouncer
import com.sw.dualscreen.utils.ImageUtil
import com.sw.plate.utils.ToastUtils
import io.objectbox.Box
import io.objectbox.kotlin.boxFor
import timber.log.Timber
import kotlin.getValue
class CollectFragment : BaseFragment<FragmentCollectBinding>() {
companion object {
const val MAX_COUNT = 5
}
private var selectedFoodId: String? = ""
private var selectedFoodName: String? = ""
private var box: Box<Food>? = null
private val foodCollectionList = mutableListOf<FoodCollectionBean>().apply {
repeat(MAX_COUNT) {
add(FoodCollectionBean(isShowCamera = true))
}
}
private val searchFoodList = mutableListOf<FoodInfo>()
private var settingActivity: SettingActivity?=null
private var checkedItem: FoodInfo? = null
private val searchFoodAdapter by lazy {
SearchFoodAdapter(searchFoodList).apply {
setOnItemClickListener { adapter, view, position ->
checkedItem = searchFoodList[position]
selectedFoodId = checkedItem!!.id
val isChecked = checkedItem!!.isChecked
searchFoodList[position].isChecked = isChecked.not()
notifyItemChanged(position)
}
}
}
private val debouncer = Debouncer(2000)
private lateinit var previewView: PreviewView
private val cameraUtils: CameraUtils by lazy {
CameraUtils(requireActivity())
}
private val collectionAdapter: FoodCollectionAdapter by lazy {
FoodCollectionAdapter(foodCollectionList).apply {
addOnItemChildClickListener(R.id.ivDelete) { _, _, position ->
foodCollectionList[position].let {
it.bitmap = null
it.isShowCamera = true
it.isFinish = false
}
notifyItemChanged(position)
}
}
}
override fun inflateViewBinding(): FragmentCollectBinding {
return FragmentCollectBinding.inflate(LayoutInflater.from(context))
}
private val cameraCallback: (Uri) -> Unit = { uri ->
val index = foodCollectionList.indexOfFirst { it.bitmap == null }
if (index == -1) {
ToastUtils.showToast("每次只允许保存${MAX_COUNT}条数据")
rerurn@cameraCallback
}
ImageUtil.uriToBitmap(requireActivity(), uri)?.let { bitmap ->
// val cropBitmap = BitmapCropper.cropCenter(
// original = bitmap,
// targetWidth = 1300, targetHeight = 900,
// //offsetX = 30, offsetY = 100
// )
val file = BitmapSaver.saveToAppFilesDir(
bitmap, requireActivity(), "IMG_CROP_${System.currentTimeMillis()}.jpg"
)
Timber.d("${this.javaClass.simpleName}-cameraCallback-裁剪bitmap保存文件路径:${file?.absolutePath}")
foodCollectionList[index].let {
it.bitmap = bitmap
it.isShowCamera = false
it.imageUri = file?.toUri()
}
collectionAdapter.notifyItemChanged(index)
}
}
@SuppressLint("NotifyDataSetChanged")
private fun takePhoto() {
val count = foodCollectionList.count { it.bitmap != null }
if (count >= MAX_COUNT) {
ToastUtils.showToast("每次只允许保存${MAX_COUNT}条数据")
return
}
cameraUtils.takePhoto(cameraCallback)
}
override fun initialize() {
settingActivity = activity as SettingActivity
cameraUtils.initCamera()
val previewBinding =
LayoutCameraPreviewBinding.inflate(layoutInflater, binding.flCameraPreview)
previewView = previewBinding.previewView.also {
it.updateLayoutParams {
width = 456.dp
height = 342.dp
}
}
cameraUtils.setPreviewController(previewView)
binding.rvFoodList.let {
it.layoutManager = GridLayoutManager(requireActivity(), 3, GridLayoutManager.VERTICAL, false)
it.adapter = collectionAdapter
}
binding.btnFoodSearch.setOnClickListener {
searchInfo()
}
binding.btnSave.setOnClickListener {
if (selectedFoodName.isNullOrBlank()) {
Toast.makeText(requireActivity(), "请选择菜品名称", Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
if (foodCollectionList.size <= 1) {
Toast.makeText(requireActivity(), "请拍摄菜品照片", Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
vectorThread()
}
binding.editFoodName.setOnEditorActionListener { v, actionId, event ->
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
searchInfo()
val imm =
v.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(v.windowToken, 0)
true
} else {
false
}
}
binding.btnCollectedFood.setOnClickListener {
startActivity(Intent(requireActivity(), CollectedFoodActivity::class.java))
}
binding.btnTakePhoto.clickWithDebounce {
val count = foodCollectionList.count { it.bitmap != null }
if (count >= MAX_COUNT) {
ToastUtils.showToast("每次只允许保存${MAX_COUNT}条数据")
return@clickWithDebounce
}
takePhoto()
}
binding.btnClearData.setOnClickListener { clearData() }
binding.rvSearchFood.let {
it.layoutManager = GridLayoutManager(context, 2)
it.adapter = searchFoodAdapter
}
}
private fun vectorThread() {
settingActivity?.showWaitingDialog("加载中……")
Thread {
foodCollectionList
.filter { it.bitmap != null }
.forEachIndexed { index, it ->
image2VectorTask(it, index)
}
activity?.runOnUiThread {
binding.root.postDelayed({
settingActivity?.hideWaitingDialog()
}, 1000)
}
}.start()
}
private fun initBox() {
if (box == null) {
box = ObjectBox.boxStore.boxFor(Food::class)
}
}
private fun image2VectorTask(item: FoodCollectionBean, position: Int) {
initBox()
val imageVector = FoodModule.bitmap2FloatArray(item.bitmap!!)
// val base64Str = FloatBase64Utils.floatArrayToBase64(imageVector)
// Timber.tag("mzf1").e(base64Str)
//// viewModel.postImageData(
//// context,
//// foodId = selectedFoodId.toString(),
//// foodName = selectedFoodName.toString(),
//// foodVector = base64Str,
//// uri = item.imageUri!!
//// )
box?.put(Food(name = checkedItem!!.foodName, foodIdx = 0, foodVector = imageVector))
foodCollectionList[position].let {
it.imageVector = imageVector
it.isFinish = true
}
activity?.runOnUiThread {
collectionAdapter.notifyItemChanged(position)
}
}
@SuppressLint("NotifyDataSetChanged")
private fun searchInfo() {
debouncer.debounce {
settingActivity?.searchByFoodName(binding.editFoodName.text.toString()) {
searchFoodList.clear()
searchFoodList.addAll(it)
searchFoodAdapter.notifyDataSetChanged()
}
}
}
private var clickIndex = -1
@SuppressLint("NotifyDataSetChanged")
private fun clearData() {
foodCollectionList.forEach {
it.bitmap = null
it.isShowCamera = true
it.isFinish = false
}
collectionAdapter.notifyDataSetChanged()
clickIndex = -1
binding.editFoodName.setText("")
// foodList.clear()
// foodAdapter.updateData(mutableListOf())
// foodAdapter.notifyDataSetChanged()
//loadEmptyView()
}
override fun onResume() {
super.onResume()
cameraUtils.bind()
binding.llCameraFlag.run {
visibility = View.VISIBLE
postDelayed({
visibility = View.GONE
}, 3000)
}
}
override fun onPause() {
super.onPause()
cameraUtils.unbind()
binding.llCameraFlag.visibility = View.VISIBLE
}
}
@@ -0,0 +1,19 @@
package com.sw.dualscreen.activity.fragment
import com.sw.dualscreen.activity.PayActivity
import com.sw.dualscreen.databinding.FragmentFacePayBinding
class FacePayFragment : BaseFragment<FragmentFacePayBinding>() {
override fun inflateViewBinding(): FragmentFacePayBinding {
return FragmentFacePayBinding.inflate(layoutInflater)
}
private var payActivity: PayActivity? = null
override fun initialize() {
payActivity = activity as PayActivity
binding.tvFaceState.setOnClickListener {
payActivity?.showPayResult()
}
}
}
@@ -0,0 +1,15 @@
package com.sw.dualscreen.activity.fragment
import com.sw.dualscreen.databinding.FragmentNumberPayBinding
import com.sw.dualscreen.ext.hideKeyboard
class NumberPayFragment: BaseFragment<FragmentNumberPayBinding>() {
override fun inflateViewBinding(): FragmentNumberPayBinding {
return FragmentNumberPayBinding.inflate(layoutInflater)
}
override fun initialize() {
binding.root.hideKeyboard()
}
}
@@ -0,0 +1,28 @@
package com.sw.dualscreen.activity.fragment
import com.sw.dualscreen.activity.PayActivity
import com.sw.dualscreen.databinding.FragmentPayResultBinding
class PayResultFragment: BaseFragment<FragmentPayResultBinding>() {
override fun inflateViewBinding(): FragmentPayResultBinding {
return FragmentPayResultBinding.inflate(layoutInflater)
}
private var payActivity: PayActivity? = null
override fun initialize() {
payActivity = activity as PayActivity
binding.btnBack.setOnClickListener {
payActivity?.showFacePay()
}
}
override fun onHiddenChanged(hidden: Boolean) {
super.onHiddenChanged(hidden)
//显示时重新查询接口
if (hidden.not()) {
}
}
}
@@ -0,0 +1,29 @@
package com.sw.dualscreen.activity.fragment
import android.text.Spanned
import android.text.SpannedString
import android.text.style.AbsoluteSizeSpan
import androidx.core.text.buildSpannedString
import com.sw.dualscreen.R
import com.sw.dualscreen.databinding.FragmentQrcodePayBinding
class QrCodePayFragment: BaseFragment<FragmentQrcodePayBinding>() {
override fun inflateViewBinding(): FragmentQrcodePayBinding {
return FragmentQrcodePayBinding.inflate(layoutInflater)
}
override fun initialize() {
binding.tvRealAmount.text = getAmountText("36.8")
binding.ivPayQrCode.setImageResource(R.drawable.ic_qrcode)
binding.tvPayResult.text = "待支付(60s)..."
}
private fun getAmountText(amount:String): SpannedString {
return buildSpannedString {
append("¥", AbsoluteSizeSpan(36, true), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
append(amount, AbsoluteSizeSpan(60, true), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
}
}
}
@@ -1,34 +1,34 @@
package com.sw.dualscreen.adapter //package com.sw.dualscreen.adapter
//
import android.content.Context //import android.content.Context
import android.view.LayoutInflater //import android.view.LayoutInflater
import android.view.View //import android.view.View
import android.view.ViewGroup //import android.view.ViewGroup
import android.widget.ImageView //import android.widget.ImageView
import com.chad.library.adapter4.BaseQuickAdapter //import com.chad.library.adapter4.BaseQuickAdapter
import com.chad.library.adapter4.viewholder.QuickViewHolder //import com.chad.library.adapter4.viewholder.QuickViewHolder
import com.sw.dualscreen.R //import com.sw.dualscreen.R
import com.sw.dualscreen.databinding.ListItemCollectedDataBinding //import com.sw.dualscreen.databinding.ListItemCollectedDataBinding
import com.sw.dualscreen.databinding.ListItemFoodCollectionBinding //import com.sw.dualscreen.databinding.ListItemFoodCollectionBinding
import com.sw.dualscreen.objbox.CollectedFoodBean //import com.sw.dualscreen.objbox.CollectedFoodBean
import com.sw.dualscreen.objbox.FoodCollectionBean //import com.sw.dualscreen.objbox.FoodCollectionBean
//
class CollectedFoodAdapter (var list: MutableList<CollectedFoodBean>) : //class CollectedFoodAdapter (var list: MutableList<CollectedFoodBean>) :
BaseQuickAdapter<CollectedFoodBean, CollectedFoodAdapter.VH>(list) { // BaseQuickAdapter<CollectedFoodBean, CollectedFoodAdapter.VH>(list) {
//
inner class VH(var binding: ListItemCollectedDataBinding) : QuickViewHolder(binding.root) // inner class VH(var binding: ListItemCollectedDataBinding) : QuickViewHolder(binding.root)
//
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH { // override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
val inflater = LayoutInflater.from(context) // val inflater = LayoutInflater.from(context)
val binding = ListItemCollectedDataBinding.inflate(inflater, parent, false) // val binding = ListItemCollectedDataBinding.inflate(inflater, parent, false)
return VH(binding) // return VH(binding)
} // }
//
override fun onBindViewHolder(holder: VH, position: Int, item: CollectedFoodBean?) { // override fun onBindViewHolder(holder: VH, position: Int, item: CollectedFoodBean?) {
holder.binding.tvFoodName.text = item?.foodName // holder.binding.tvFoodName.text = item?.foodName
holder.binding.divider.run { // holder.binding.divider.run {
visibility = if (position == list.size - 1) View.GONE else View.VISIBLE // visibility = if (position == list.size - 1) View.GONE else View.VISIBLE
} // }
} // }
//
} //}
@@ -0,0 +1,27 @@
package com.sw.dualscreen.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import com.chad.library.adapter4.BaseQuickAdapter
import com.chad.library.adapter4.viewholder.QuickViewHolder
import com.sw.dualscreen.databinding.ListItemCollectedFoodBinding
import com.sw.dualscreen.objbox.CollectedFoodBean
class CollectedFoodNewAdapter(var list: MutableList<CollectedFoodBean>) :
BaseQuickAdapter<CollectedFoodBean, CollectedFoodNewAdapter.VH>(list) {
inner class VH(var binding: ListItemCollectedFoodBinding) : QuickViewHolder(binding.root)
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
val inflater = LayoutInflater.from(context)
val binding = ListItemCollectedFoodBinding.inflate(inflater, parent, false)
return VH(binding)
}
override fun onBindViewHolder(holder: VH, position: Int, item: CollectedFoodBean?) {
holder.binding.tvFoodName.text = item?.foodName
holder.binding.tvCollectedNum.text = "已采集153"
}
}
@@ -9,7 +9,9 @@ import com.chad.library.adapter4.BaseQuickAdapter
import com.chad.library.adapter4.viewholder.QuickViewHolder import com.chad.library.adapter4.viewholder.QuickViewHolder
import com.sw.dualscreen.R import com.sw.dualscreen.R
import com.sw.dualscreen.databinding.ListItemFoodCollectionBinding import com.sw.dualscreen.databinding.ListItemFoodCollectionBinding
import com.sw.dualscreen.ext.dp
import com.sw.dualscreen.objbox.FoodCollectionBean import com.sw.dualscreen.objbox.FoodCollectionBean
import com.sw.dualscreen.utils.GlideUtils
class FoodCollectionAdapter (var list: MutableList<FoodCollectionBean>) : class FoodCollectionAdapter (var list: MutableList<FoodCollectionBean>) :
BaseQuickAdapter<FoodCollectionBean, FoodCollectionAdapter.VH>(list) { BaseQuickAdapter<FoodCollectionBean, FoodCollectionAdapter.VH>(list) {
@@ -30,11 +32,20 @@ class FoodCollectionAdapter (var list: MutableList<FoodCollectionBean>) :
binding.imageView.run { binding.imageView.run {
if (it.isShowCamera) { if (it.isShowCamera) {
scaleType = ImageView.ScaleType.CENTER scaleType = ImageView.ScaleType.CENTER
setImageResource(R.drawable.ic_camera256) setImageResource(R.drawable.ic_camera_default)
} else { } else {
scaleType = ImageView.ScaleType.FIT_CENTER //scaleType = ImageView.ScaleType.FIT_CENTER
scaleType = ImageView.ScaleType.CENTER_CROP
//setImageURI(it.imageUri) //setImageURI(it.imageUri)
setImageBitmap(it.bitmap) //setImageBitmap(it.bitmap)
it.bitmap?.let { bitmap ->
GlideUtils.loadRoundCornerWitBitmap(
context,
url = bitmap,
imageView = this,
radius = 8.dp
)
}
} }
} }
} }
@@ -0,0 +1,35 @@
package com.sw.dualscreen.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import com.chad.library.adapter4.BaseQuickAdapter
import com.chad.library.adapter4.viewholder.QuickViewHolder
import com.sw.dualscreen.databinding.ListItemSearchFoodBinding
import com.sw.dualscreen.ext.format2String
import com.sw.dualscreen.model.response.FoodInfo
class SearchFoodAdapter(var list: MutableList<FoodInfo>) :
BaseQuickAdapter<FoodInfo, SearchFoodAdapter.VH>(list) {
inner class VH(var binding: ListItemSearchFoodBinding) : QuickViewHolder(binding.root)
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
val inflater = LayoutInflater.from(context)
val binding = ListItemSearchFoodBinding.inflate(inflater, parent, false)
return VH(binding)
}
override fun onBindViewHolder(holder: VH, position: Int, item: FoodInfo?) {
holder.binding.tvFoodName.run {
if (item!!.score == 0) {
text = item.foodName
} else {
val score = (item.score / 100.0).format2String(2)
text = "${item.foodName}\n${score}%"
}
isChecked = item.isChecked
}
}
}
@@ -120,3 +120,15 @@ fun View.clickWithDebounce(delay: Long = 500, action: () -> Unit) {
} }
} }
} }
fun View.visible() {
visibility = View.VISIBLE
}
fun View.invisible() {
visibility = View.INVISIBLE
}
fun View.gone() {
visibility = View.GONE
}
@@ -39,7 +39,8 @@ data class FoodInfo(
val stFoodInfoSetting: StFoodInfoSetting? = StFoodInfoSetting(), val stFoodInfoSetting: StFoodInfoSetting? = StFoodInfoSetting(),
@SerializedName("stFoodInfoSpecificationList") @SerializedName("stFoodInfoSpecificationList")
val stFoodInfoSpecificationList: List<StFoodInfoSpecification?>? = listOf(), val stFoodInfoSpecificationList: List<StFoodInfoSpecification?>? = listOf(),
var score: Int = 0 var score: Int = 0,
var isChecked: Boolean = false
) : Parcelable { ) : Parcelable {
@Parcelize @Parcelize
data class FoodTypeAndRealIntakeVo( data class FoodTypeAndRealIntakeVo(
@@ -4,8 +4,10 @@ import com.sw.plate.utils.ToastUtils
import com.wabon.wbintelligenthardwaresdk.api.SensorScale import com.wabon.wbintelligenthardwaresdk.api.SensorScale
import com.wabon.wbintelligenthardwaresdk.api.SensorScale.OnScaleResult import com.wabon.wbintelligenthardwaresdk.api.SensorScale.OnScaleResult
import timber.log.Timber import timber.log.Timber
import kotlin.math.roundToInt
typealias Callback = (Double) -> Unit typealias Callback = (Double) -> Unit
typealias WeightCallback = (Double) -> Unit
private const val TAG = "SensorScaleUtils" private const val TAG = "SensorScaleUtils"
@@ -41,6 +43,10 @@ object SensorScaleUtils {
lastWeight = value lastWeight = value
callback?.invoke(value) callback?.invoke(value)
} }
weightCallbackList.forEach {
it.invoke(value)
}
} }
/** /**
@@ -60,7 +66,7 @@ object SensorScaleUtils {
* 开启称重 * 开启称重
* @param autoScale 是否开启自动读取 * @param autoScale 是否开启自动读取
*/ */
fun startScale(autoScale: Boolean = true, callback: Callback?) { fun startScale(autoScale: Boolean = true, callback: Callback? = null) {
Timber.d("startScale isOpened = $isOpened") Timber.d("startScale isOpened = $isOpened")
if (isOpened) { if (isOpened) {
startContinuousRead(callback = callback) startContinuousRead(callback = callback)
@@ -112,6 +118,13 @@ object SensorScaleUtils {
mSensorScale?.readWeight() mSensorScale?.readWeight()
} }
private var weightCallbackList: MutableList<WeightCallback> = mutableListOf()
fun addWeightListener(weightCallback: WeightCallback) {
if (weightCallbackList.contains(weightCallback).not()) {
weightCallbackList.add(weightCallback)
}
}
/** /**
* 零位标定 * 零位标定
*/ */
@@ -0,0 +1,57 @@
package com.sw.dualscreen.utils
import android.app.Activity
import android.os.Process
import java.util.Stack
object ActivityManager {
private val activityStack = Stack<Activity>()
// 添加Activity到栈
fun addActivity(activity: Activity) {
activityStack.add(activity)
}
// 移除指定Activity
fun removeActivity(activity: Activity) {
activityStack.remove(activity)
}
// 获取当前Activity
fun currentActivity(): Activity? {
return if (activityStack.isEmpty()) null else activityStack.lastElement()
}
// 结束指定Activity
fun finishActivity(activity: Activity) {
if (!activity.isFinishing) {
activity.finish()
}
}
// 结束所有Activity
fun finishAllActivity() {
activityStack.forEach {
if (!it.isFinishing) {
it.finish()
}
}
activityStack.clear()
}
// 退出应用程序
fun exitApp() {
finishAllActivity()
Process.killProcess(Process.myPid())
}
fun getActivityStack(): Stack<Activity>{
return activityStack
}
fun isEmpty() : Boolean {
return activityStack.isEmpty()
}
}
@@ -104,6 +104,21 @@ object GlideUtils {
.into(imageView) .into(imageView)
} }
fun loadRoundCornerWitBitmap(
context: Context,
url: Bitmap,
imageView: ImageView,
radius: Int,
@DrawableRes placeholderResId: Int = 0,
@DrawableRes errorResId: Int = 0
) {
val requestBuilder = Glide.with(context)
.load(url)
.apply(RequestOptions.bitmapTransform(RoundedCorners(radius)))
applyPlaceholder(requestBuilder, placeholderResId, errorResId)
.into(imageView)
}
/** /**
* 加载图片并获取Bitmap * 加载图片并获取Bitmap
* @param context 上下文 * @param context 上下文
@@ -158,12 +158,14 @@ class UserViewModel : BaseViewModel() {
/** /**
* 搜索食物 * 搜索食物
*/ */
fun searchByFoodName(foodName: String) { fun searchByFoodName(foodName: String, action: (List<FoodInfo>) -> Unit = {}) {
Timber.d("searchByFoodName foodName = $foodName") Timber.d("searchByFoodName foodName = $foodName")
launchWithLoading { launchWithLoading {
val response = repository.getRestInfoFoodsByType(foodName = foodName) val response = repository.getRestInfoFoodsByType(foodName = foodName)
if (parseResponse(response)) { if (parseResponse(response)) {
_searchFoodInfoList.value = response.result ?: emptyList() val list = response.result ?: emptyList()
action(list)
_searchFoodInfoList.value = list
} }
} }
} }
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#FF5E7585" android:state_checked="false"/>
<item android:color="#FFFF3232" android:state_checked="true"/>
</selector>
+5
View File
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#FF5E7585" android:state_checked="false"/>
<item android:color="#FFFF3232" android:state_checked="true"/>
</selector>
Binary file not shown.

After

Width:  |  Height:  |  Size: 417 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#ffffff"/>
<stroke android:color="#FFFF3232" android:width="2dp"/>
<corners android:radius="6dp"/>
</shape>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#FF5E7585"/>
<corners android:radius="6dp"/>
</shape>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#FFFF3232"/>
<corners android:radius="50dp"/>
</shape>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#FFFF3232"/>
<corners android:radius="6dp"/>
</shape>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#80FF3232"/>
<corners android:radius="6dp"/>
</shape>
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#FFE7EFF8"/>
<corners android:radius="8dp"/>
</shape>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#FFF4FAFF"/>
<stroke android:color="@color/white" android:width="2dp"/>
</shape>
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="false">
<shape android:shape="rectangle">
<corners android:radius="45dp"/>
<solid android:color="#FFE7EFF8"/>
<stroke android:color="#FFC4CFDA" android:width="2dp"/>
</shape>
</item>
<item android:state_checked="true">
<shape android:shape="rectangle">
<corners android:radius="45dp"/>
<solid android:color="#FFFFF0F0"/>
<stroke android:color="#FFFF3232" android:width="2dp"/>
</shape>
</item>
</selector>
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#FFFF3232"/>
<size android:width="10dp" android:height="40dp"/>
<corners android:radius="5dp"/>
</shape>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#FFF4FAFF"/>
<stroke android:width="2dp" android:color="@color/white"/>
</shape>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/white"/>
<stroke android:width="2dp" android:color="#FFE7EFF8"/>
<corners android:radius="8dp"/>
</shape>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#FFF4FAFF"/>
<stroke android:width="2dp" android:color="#FFE7EFF8"/>
<corners android:radius="8dp"/>
</shape>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/white"/>
<stroke android:width="2dp" android:color="#FFC4CFDA"/>
<corners android:radius="50dp"/>
</shape>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/white"/>
<stroke android:width="2dp" android:color="#FFE7EFF8"/>
<corners android:radius="8dp"/>
</shape>
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="false">
<layer-list>
<item>
<shape android:shape="rectangle">
<solid android:color="@color/white" />
<corners android:radius="8dp" />
</shape>
</item>
</layer-list>
</item>
<item android:state_checked="true">
<layer-list>
<item>
<shape android:shape="rectangle">
<solid android:color="@color/white" />
<corners android:radius="8dp" />
<stroke android:width="2dp" android:color="#FFFF3232" />
</shape>
</item>
<item android:width="48dp" android:height="48dp" android:gravity="end|bottom">
<bitmap android:src="@drawable/ic_setting_checked" />
</item>
</layer-list>
</item>
</selector>
+13
View File
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:width="294dp" android:height="60dp">
<shape android:shape="rectangle">
<stroke android:width="2dp" android:color="#FFFF3232"/>
<!-- <corners android:topRightRadius="6dp" android:bottomRightRadius="6dp"/>-->
<corners android:radius="6dp"/>
</shape>
</item>
<item android:gravity="start">
<bitmap android:src="@drawable/ic_vip_level"/>
</item>
</layer-list>
@@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFE7EFF8">
<include
android:id="@+id/include"
layout="@layout/layout_title_bar"/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginHorizontal="32dp"
android:background="@drawable/setting_border_gray3">
<EditText
android:id="@+id/etInputFood"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent"
android:gravity="center"
android:hint="输入菜品名称"
android:maxLines="1"
android:paddingStart="45dp"
android:paddingEnd="100dp"
android:textColor="@color/black"
android:textColorHint="#FFC4CFDA"
android:textSize="36sp"
android:inputType="text"
android:imeOptions="actionSearch" />
<ImageView
android:id="@+id/ivFoodSearch"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="end|center_vertical"
android:layout_marginEnd="30dp"
android:padding="5dp"
android:src="@drawable/ic_search2" />
</FrameLayout>
<!-- <com.scwang.smart.refresh.layout.SmartRefreshLayout-->
<!-- android:id="@+id/refreshLayout"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="0dp"-->
<!-- android:layout_marginHorizontal="130dp"-->
<!-- android:layout_marginTop="40dp"-->
<!-- android:layout_marginBottom="58dp"-->
<!-- app:layout_constraintBottom_toTopOf="@id/dividerLine"-->
<!-- app:layout_constraintTop_toBottomOf="@id/flSearchBlock">-->
<!-- <com.scwang.smart.refresh.header.ClassicsHeader-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content" />-->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvFoodList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:overScrollMode="never"
android:layout_margin="10dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:itemCount="8"
tools:listitem="@layout/list_item_collected_food" />
<!-- <com.scwang.smart.refresh.footer.ClassicsFooter-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content" />-->
<!-- </com.scwang.smart.refresh.layout.SmartRefreshLayout>-->
</LinearLayout>
+62 -22
View File
@@ -4,7 +4,7 @@
android:id="@+id/main" android:id="@+id/main"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@mipmap/bg" android:background="#FFE7EFF8"
android:gravity="center_horizontal" android:gravity="center_horizontal"
android:orientation="vertical" android:orientation="vertical"
tools:context=".activity.MainActivity"> tools:context=".activity.MainActivity">
@@ -12,25 +12,44 @@
<FrameLayout <FrameLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="150dp">
android:paddingTop="40dp"
android:paddingEnd="40dp">
<LinearLayout <TextView
android:id="@+id/tvTitleTime"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="end" android:layout_gravity="center_vertical"
android:background="@drawable/bg_detection_selector"> android:layout_marginStart="32dp"
android:textColor="#ff0a1428"
android:textSize="30sp"
android:textStyle="bold"
tools:text="2025年11月11日 周二" />
<Spinner <ImageView
android:id="@+id/spinner" android:id="@+id/ivSetting"
style="@style/customSpinnerStyle" android:layout_width="64dp"
android:layout_width="wrap_content" android:layout_height="64dp"
android:layout_height="wrap_content" android:layout_gravity="end|center_vertical"
android:layout_gravity="end" android:layout_marginEnd="22dp"
android:padding="0dp" android:padding="10dp"
android:popupBackground="@drawable/shape_for_custom_spinner" /> android:src="@drawable/ic_setting"
</LinearLayout> tools:ignore="ContentDescription" />
<!-- <LinearLayout-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_gravity="end"-->
<!-- android:background="@drawable/bg_detection_selector">-->
<!-- <Spinner-->
<!-- android:id="@+id/spinner"-->
<!-- style="@style/customSpinnerStyle"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_gravity="end"-->
<!-- android:padding="0dp"-->
<!-- android:popupBackground="@drawable/shape_for_custom_spinner" />-->
<!-- </LinearLayout>-->
</FrameLayout> </FrameLayout>
@@ -91,7 +110,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="未识别出菜品,请重试或手动搜索" android:text="未识别出菜品,请重试或手动搜索"
android:textColor="@color/white" android:textColor="#FFFF3232"
android:textSize="24sp" /> android:textSize="24sp" />
<TextView <TextView
@@ -99,11 +118,11 @@
android:layout_width="180dp" android:layout_width="180dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="20dp" android:layout_marginTop="20dp"
android:background="@drawable/bg_rescan" android:background="@drawable/bg_border_red"
android:gravity="center" android:gravity="center"
android:padding="10dp" android:padding="10dp"
android:text="重试" android:text="重试"
android:textColor="#ffff9900" android:textColor="#FFFF3232"
android:textSize="32sp" /> android:textSize="32sp" />
</LinearLayout> </LinearLayout>
@@ -111,11 +130,32 @@
android:id="@+id/tv_to_search" android:id="@+id/tv_to_search"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="90dp" android:layout_marginTop="40dp"
android:layout_marginBottom="90dp" android:layout_marginBottom="60dp"
android:padding="10dp" android:padding="10dp"
android:text="以上都不是,手动搜索" android:text="以上都不是,手动搜索"
android:textColor="#ffff9900" android:textStyle="bold"
android:textColor="#FFFF3232"
android:textSize="36sp" /> android:textSize="36sp" />
<FrameLayout
android:id="@+id/flPay"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:visibility="gone">
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btnPay"
android:layout_width="match_parent"
android:layout_margin="32dp"
android:layout_height="100dp"
android:textStyle="bold"
android:text="去结算"
android:textSize="40sp"
android:background="@drawable/bg_btn_save"
android:textColor="@color/white"/>
</FrameLayout>
</LinearLayout> </LinearLayout>
+25 -3
View File
@@ -1,21 +1,43 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="#E7EFF8" android:background="#E7EFF8"
android:orientation="vertical"> android:orientation="vertical"
tools:ignore="HardcodedText">
<Space <include
android:id="@+id/include"
layout="@layout/layout_title_bar" />
<TextView
android:id="@+id/tvFoodName"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="30dp"
android:layout_marginBottom="90dp"
android:textColor="#ff0a1428"
android:textSize="60sp"
android:textStyle="bold"
tools:text="岐山臊子面" />
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragmentContainerView"
android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="1" /> android:layout_marginHorizontal="32dp"
android:layout_weight="1"
android:background="@drawable/bg_pay_content" />
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="167dp" android:layout_height="167dp"
android:layout_gravity="bottom" android:layout_gravity="bottom"
android:layout_marginHorizontal="32dp" android:layout_marginHorizontal="32dp"
android:layout_marginTop="48dp"
android:layout_marginBottom="64dp" android:layout_marginBottom="64dp"
android:gravity="center_vertical" android:gravity="center_vertical"
android:orientation="horizontal"> android:orientation="horizontal">
@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFE7EFF8"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical">
<include
android:id="@+id/include"
layout="@layout/layout_title_bar" />
<RadioGroup
android:id="@+id/rgSetting"
android:layout_width="match_parent"
android:layout_height="130dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<RadioButton
android:id="@+id/rbBusiness"
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_marginStart="50dp"
android:layout_marginEnd="25dp"
android:layout_weight="1"
android:button="@null"
tools:checked="true"
android:gravity="center"
android:maxLines="1"
android:text="经营设置"
android:textColor="@color/setting_radio"
android:textSize="30sp"
android:textStyle="bold" />
<RadioButton
android:id="@+id/rbCollect"
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_marginStart="25dp"
android:layout_marginEnd="50dp"
android:layout_weight="1"
android:button="@null"
android:gravity="center"
android:maxLines="1"
android:text="餐品采集"
android:textColor="@color/setting_radio"
android:textSize="30sp"
android:textStyle="bold" />
</RadioGroup>
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragmentContainerView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
@@ -0,0 +1,180 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/setting_border"
android:orientation="vertical"
android:paddingHorizontal="32dp"
android:paddingTop="35dp"
android:paddingBottom="42dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawablePadding="17dp"
android:text="计费设置"
android:textColor="@color/black"
android:textSize="36sp"
android:textStyle="bold"
app:drawableStartCompat="@drawable/line_shape" />
<RadioGroup
android:id="@+id/rgCharge"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="35dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<RadioButton
android:id="@+id/rbChargeNot"
android:layout_width="0dp"
android:layout_height="120dp"
android:layout_weight="1"
android:background="@drawable/setting_check_selector"
android:button="@null"
android:gravity="center"
android:maxLines="1"
android:text="不计费"
android:textColor="@color/setting_radio"
android:textSize="30sp"
android:textStyle="bold"
tools:checked="true" />
<RadioButton
android:id="@+id/rbChargeYes"
android:layout_width="0dp"
android:layout_height="120dp"
android:layout_marginStart="32dp"
android:layout_weight="1"
android:background="@drawable/setting_check_selector"
android:button="@null"
android:gravity="center"
android:maxLines="1"
android:text="计费"
android:textColor="@color/setting_radio"
android:textSize="30sp"
android:textStyle="bold" />
</RadioGroup>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="42dp"
android:background="@drawable/setting_border"
android:orientation="vertical"
android:paddingHorizontal="32dp"
android:paddingTop="35dp"
android:paddingBottom="42dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawablePadding="17dp"
android:text="取餐设置"
android:textColor="@color/black"
android:textSize="36sp"
android:textStyle="bold"
app:drawableStartCompat="@drawable/line_shape" />
<RadioGroup
android:id="@+id/rgTakeFood"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="35dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<RadioButton
android:id="@+id/rbSurplusCalculate"
android:layout_width="0dp"
android:layout_height="120dp"
android:layout_weight="1"
android:background="@drawable/setting_check_selector"
android:button="@null"
android:gravity="center"
android:maxLines="1"
android:text="余量计量"
android:textColor="@color/setting_radio"
android:textSize="30sp"
android:textStyle="bold"
tools:checked="true" />
<RadioButton
android:id="@+id/rbPickAndPlace"
android:layout_width="0dp"
android:layout_height="120dp"
android:layout_marginStart="32dp"
android:layout_weight="1"
android:background="@drawable/setting_check_selector"
android:button="@null"
android:gravity="center"
android:maxLines="1"
android:text="即放即取"
android:textColor="@color/setting_radio"
android:textSize="30sp"
android:textStyle="bold" />
</RadioGroup>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="342dp"
android:layout_marginTop="42dp"
android:background="@drawable/setting_border_gray">
<TextView
android:layout_width="wrap_content"
android:layout_height="120dp"
android:layout_marginStart="42dp"
android:text="餐具重量(克)"
android:layout_gravity="start"
android:gravity="center_vertical"
android:textColor="#ff5e7585"
android:textSize="30sp"
android:textStyle="bold" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btnClearZero"
android:layout_width="120dp"
android:layout_height="60dp"
android:layout_marginEnd="42dp"
android:layout_gravity="end"
android:layout_marginTop="30dp"
android:background="@drawable/bg_btn_clear"
android:gravity="center"
android:text="清零"
android:textColor="@color/white"
android:textSize="30sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tvFoodWeight"
android:layout_width="match_parent"
android:layout_height="180dp"
android:layout_marginStart="42dp"
android:layout_marginTop="120dp"
android:layout_marginEnd="42dp"
android:background="@drawable/setting_border_gray2"
android:layout_gravity="start"
android:gravity="center"
android:maxLines="1"
android:ellipsize="end"
android:textColor="@color/black"
android:textSize="60sp"
android:textStyle="bold"
tools:text="0.0" />
</FrameLayout>
</LinearLayout>
</LinearLayout>
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<TextView
tools:ignore="HardcodedText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="260dp"
android:text="应收金额"
android:textColor="#ff5e7585"
android:textSize="30sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tvRealAmount"
tools:text="¥36.80"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:textColor="#ffff3232"
android:textSize="36sp"
android:textStyle="bold" />
</LinearLayout>
@@ -0,0 +1,184 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="32dp"
android:background="@drawable/setting_border"
android:orientation="vertical"
android:paddingBottom="16dp">
<TextView
android:id="@+id/tvChargeSetting"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
android:layout_marginStart="32dp"
android:layout_marginTop="35dp"
android:drawablePadding="17dp"
android:text="计费设置"
android:textColor="@color/black"
android:textSize="36sp"
android:textStyle="bold"
app:drawableStartCompat="@drawable/line_shape"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/btnCollectedFood"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|center_vertical"
android:layout_marginEnd="32dp"
android:gravity="center_vertical"
android:includeFontPadding="false"
android:text="已采集餐品"
android:textColor="#ff5e7585"
android:textSize="30sp"
android:textStyle="bold"
app:drawableEndCompat="@drawable/ic_arrow_right"
app:layout_constraintBottom_toBottomOf="@id/tvChargeSetting"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/tvChargeSetting" />
<FrameLayout
android:id="@+id/flPreview"
android:layout_width="456dp"
android:layout_height="342dp"
android:layout_marginTop="41dp"
app:layout_constraintStart_toStartOf="@id/tvChargeSetting"
app:layout_constraintTop_toBottomOf="@id/tvChargeSetting">
<androidx.cardview.widget.CardView
android:id="@+id/flCameraPreview"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:cardCornerRadius="8dp"
app:cardElevation="0dp" />
<LinearLayout
android:id="@+id/llCameraFlag"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:gravity="center"
android:background="@color/white"
android:orientation="vertical"
android:visibility="visible">
<ImageView
android:layout_width="88dp"
android:layout_height="88dp"
android:layout_gravity="center"
android:scaleType="fitCenter"
android:src="@drawable/ic_camera256"
tools:ignore="ContentDescription" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="图片采集"
android:textColor="#ffb4b4c8"
android:textSize="26sp" />
</LinearLayout>
</FrameLayout>
<ImageView
android:id="@+id/btnClearData"
android:layout_width="212dp"
android:layout_height="155dp"
android:src="@drawable/ic_retake_photo"
app:layout_constraintEnd_toEndOf="@id/btnCollectedFood"
app:layout_constraintTop_toTopOf="@id/flPreview"
tools:ignore="ContentDescription" />
<ImageView
android:id="@+id/btnTakePhoto"
android:layout_width="212dp"
android:layout_height="155dp"
android:src="@drawable/ic_take_photo"
app:layout_constraintBottom_toBottomOf="@id/flPreview"
app:layout_constraintEnd_toEndOf="@id/btnCollectedFood"
tools:ignore="ContentDescription" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvFoodList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="16dp"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/flPreview"
app:spanCount="3"
tools:itemCount="5"
tools:listitem="@layout/list_item_food_collection" />
</androidx.constraintlayout.widget.ConstraintLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginHorizontal="32dp"
android:layout_marginTop="32dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<EditText
android:id="@+id/editFoodName"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/setting_border_gray3"
android:gravity="center_vertical"
android:hint="输入菜品名称"
android:imeOptions="actionSearch"
android:maxLines="1"
android:paddingStart="47dp"
android:paddingEnd="80dp"
android:textColor="@color/black"
android:textColorHint="#FFC4CFDA"
android:textSize="36sp" />
<ImageView
android:id="@+id/btnFoodSearch"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_gravity="end|center_vertical"
android:layout_marginEnd="15dp"
android:padding="10dp"
android:src="@drawable/ic_search2" />
</FrameLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvSearchFood"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:minHeight="348dp"
android:layout_weight="1"
app:spanCount="2"
tools:itemCount="10"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
tools:listitem="@layout/list_item_search_food"/>
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btnSave"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginHorizontal="32dp"
android:layout_marginBottom="48dp"
android:text="保存"
android:background="@drawable/bg_btn_save"
android:textColor="@color/white"
android:textSize="40sp" />
</LinearLayout>
@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="会员验证"
android:textColor="#ff0a1428"
android:textSize="36sp"
android:textStyle="bold"
tools:ignore="HardcodedText" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="32dp"
android:layout_marginTop="64dp">
<FrameLayout
android:id="@+id/flCameraPreview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="@+id/ivFacePhoto"
android:layout_width="match_parent"
android:layout_height="510dp"
android:src="@mipmap/ic_launcher"
android:scaleType="centerCrop"
tools:ignore="ContentDescription" />
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:src="@drawable/face_mask"
android:layout_gravity="bottom"
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/tvFaceState"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginBottom="32dp"
android:text="识别中..."
android:textColor="#ffffffff"
android:textSize="30sp" />
</FrameLayout>
</LinearLayout>
@@ -0,0 +1,86 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/vip_level"/>
<TextView
android:layout_width="200dp"
android:layout_height="60dp"
android:textColor="#FFFF3232"
android:textSize="30sp"
android:textStyle="bold"
android:gravity="center"
android:includeFontPadding="false"
android:layout_gravity="end|center_vertical"
android:text="6.80 元/份"/>
</FrameLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="会员验证"
android:textColor="#ff0a1428"
android:textSize="36sp"
android:textStyle="bold"
tools:ignore="HardcodedText" />
<EditText
android:id="@+id/etInputPhone"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginHorizontal="64dp"
android:inputType="number"
android:background="@drawable/setting_border_gray3"
android:hint="输入手机号后四位"
android:textColorHint="#ffc4cfda"
android:textColor="#ff0a1428"
android:layout_marginTop="64dp"
android:textSize="36sp"
android:gravity="center"
android:maxLines="1"
android:maxLength="4"
android:paddingHorizontal="50dp"
android:textStyle="bold"
tools:ignore="Autofill,HardcodedText,LabelFor,TextFields" />
<EditText
android:id="@+id/etInputNumber"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginHorizontal="64dp"
android:inputType="text"
android:background="@drawable/setting_border_gray3"
android:hint="输入消费码"
android:textColorHint="#ffc4cfda"
android:textColor="#ff0a1428"
android:layout_marginTop="32dp"
android:textSize="36sp"
android:gravity="center"
android:maxLines="1"
android:paddingHorizontal="50dp"
android:textStyle="bold"
tools:ignore="Autofill,HardcodedText,LabelFor,TextFields" />
<androidx.appcompat.widget.AppCompatButton
android:layout_width="match_parent"
android:layout_marginTop="64dp"
android:layout_marginHorizontal="64dp"
android:text="确定"
android:textColor="@color/white"
android:textStyle="bold"
android:textSize="36sp"
android:background="@drawable/bg_btn_confirm"
android:layout_height="100dp"/>
</LinearLayout>
@@ -0,0 +1,218 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="32dp"
tools:background="#FFF4FAFF">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardBackgroundColor="@color/white"
app:cardCornerRadius="8dp"
app:cardElevation="0dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="32dp"
android:paddingTop="32dp"
android:paddingBottom="47dp">
<ImageView
android:id="@+id/ivHeadPic"
android:layout_width="120dp"
android:layout_height="120dp"
android:src="@mipmap/ic_launcher"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tvUserName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:textColor="#ff0a1428"
android:textSize="32sp"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@+id/tvUserPhone"
app:layout_constraintStart_toEndOf="@id/ivHeadPic"
app:layout_constraintTop_toTopOf="@id/ivHeadPic"
app:layout_constraintVertical_chainStyle="packed"
tools:text="DAMIHU" />
<TextView
android:id="@+id/tvUserPhone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:textColor="#ff889ac2"
android:textSize="26sp"
app:layout_constraintBottom_toBottomOf="@id/ivHeadPic"
app:layout_constraintStart_toStartOf="@id/tvUserName"
app:layout_constraintTop_toBottomOf="@id/tvUserName"
tools:text="138****8000" />
<com.google.android.material.divider.MaterialDivider
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="32dp"
app:dividerColor="#FFDBE5FB"
app:layout_constraintTop_toBottomOf="@id/ivHeadPic" />
<TextView
android:id="@+id/tvBalanceName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="47dp"
android:text="可用余额"
android:textColor="#ff889ac2"
android:textSize="30sp"
app:layout_constraintStart_toStartOf="@id/ivHeadPic"
app:layout_constraintTop_toBottomOf="@id/divider" />
<TextView
android:id="@+id/tvUserBalance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FF0A1428"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="@id/tvBalanceName"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/tvBalanceName"
tools:text="¥16.80" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
<LinearLayout
android:id="@+id/layoutPayInfo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical"
android:visibility="gone">
<Space
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="应收金额"
android:textColor="#ff5e7585"
android:textSize="30sp"
android:textStyle="bold"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/tvRealAmount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:textColor="#ffff3232"
android:textSize="36sp"
android:textStyle="bold"
tools:text="¥36.80" />
<ImageView
android:id="@+id/ivPayQrCode"
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_marginTop="56dp"
android:src="@drawable/ic_qrcode"
android:visibility="visible" />
<Space
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<TextView
android:id="@+id/tvAccountInfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="余额扣除 -16.80 元,还需支付 20.00 元"
android:textColor="#ff889ac2"
android:textSize="30sp" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btnConfirmPay"
android:layout_width="match_parent"
android:layout_height="120dp"
android:layout_marginHorizontal="32dp"
android:layout_marginTop="50dp"
android:layout_marginBottom="32dp"
android:background="@drawable/bg_btn_save2"
android:text="确认支付"
android:textColor="@color/white"
android:textSize="40sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<Space
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<ImageView
android:layout_width="120dp"
android:layout_height="120dp"
android:src="@drawable/ic_pay_success" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="48dp"
android:text="支付成功"
android:textColor="#ff00c864"
android:textSize="60sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tvPayAmount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:textColor="#ff0a1428"
android:textSize="36sp"
tools:text="收款金额 20.00 元" />
<TextView
android:id="@+id/tvPayInfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="48dp"
android:textColor="#ff889ac2"
android:textSize="30sp"
tools:text="应收 38.00 元,余额扣除 16.80 元" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btnBack"
android:layout_width="270dp"
android:layout_height="90dp"
android:layout_marginTop="48dp"
android:background="@drawable/bg_gray"
android:text="返回"
android:textSize="30sp"
android:textStyle="bold" />
<Space
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
</LinearLayout>
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="260dp"
android:text="应收金额"
android:textColor="#ff5e7585"
android:textSize="30sp"
android:textStyle="bold"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/tvRealAmount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:textColor="#ffff3232"
android:textSize="36sp"
android:textStyle="bold"
tools:text="¥36.80" />
<ImageView
android:id="@+id/ivPayQrCode"
android:layout_width="310dp"
android:layout_height="310dp"
android:layout_marginTop="64dp"
tools:src="@drawable/ic_qrcode"
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/tvPayResult"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="64dp"
tools:text="待支付(60s)..."
android:textColor="#ff5e7585"
android:textSize="30sp"
android:textStyle="bold" />
</LinearLayout>
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="150dp">
<ImageView
android:id="@+id/ivPageBack"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_gravity="center_vertical"
android:layout_marginStart="22dp"
android:padding="10dp"
android:src="@drawable/ic_back2"
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/tvPageTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textColor="#ff0a1428"
android:layout_marginHorizontal="70dp"
android:textSize="36sp"
android:maxLines="1"
android:ellipsize="end"
android:textStyle="bold"
tools:text="下单结算" />
</FrameLayout>
@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginVertical="25dp"
android:layout_marginStart="80dp"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/tvFoodName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:gravity="center_vertical"
android:maxLines="1"
android:textColor="@color/black"
android:textSize="36sp"
android:textStyle="bold"
tools:text="高杆白菜" />
<TextView
android:id="@+id/tvCollectedNum"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="23dp"
android:textColor="#ff5e7585"
android:textSize="30sp"
tools:text="已采集153" />
</LinearLayout>
<ImageView
android:id="@+id/ivDeleteFood"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_marginEnd="75dp"
android:paddingHorizontal="10dp"
android:src="@drawable/ic_close2"
tools:ignore="ContentDescription" />
</LinearLayout>
@@ -1,31 +1,30 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="212dp"
android:layout_height="200dp" android:layout_height="159dp"
android:layout_margin="3dp" android:layout_margin="16dp"
android:background="@drawable/bg_gray"> android:background="@drawable/bg_gray2">
<ImageView <ImageView
android:id="@+id/imageView" android:id="@+id/imageView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:scaleType="center" android:scaleType="center"
tools:src="@drawable/ic_camera256" /> tools:src="@drawable/ic_camera_default" />
<ImageView <ImageView
android:id="@+id/ivDelete" android:id="@+id/ivDelete"
android:layout_width="48dp" android:layout_width="52dp"
android:layout_height="48dp" android:layout_height="52dp"
android:layout_gravity="end|top" android:layout_gravity="end|top"
android:paddingTop="10dp" android:padding="6dp"
android:paddingBottom="10dp"
android:src="@drawable/ic_delete_red" /> android:src="@drawable/ic_delete_red" />
<ImageView <ImageView
android:id="@+id/ivFinish" android:id="@+id/ivFinish"
android:layout_width="48dp" android:layout_width="36dp"
android:layout_height="48dp" android:layout_height="36dp"
android:layout_gravity="end|bottom" android:layout_gravity="end|bottom"
android:padding="5dp" android:padding="5dp"
android:src="@drawable/ic_finish" /> android:src="@drawable/ic_finish" />
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/tvFoodName"
android:layout_width="match_parent"
android:layout_height="90dp"
android:background="@drawable/bg_search_food"
android:ellipsize="end"
android:gravity="center"
android:maxLines="1"
android:layout_marginHorizontal="16dp"
android:layout_marginVertical="8dp"
android:paddingHorizontal="15dp"
android:textAlignment="center"
android:textColor="@color/color_search_food"
android:textSize="30sp"
android:textStyle="bold"
tools:text="肉沫干拌面" />