From 9801534aad75675530045dc9d9ff2aff25b9b3a7 Mon Sep 17 00:00:00 2001 From: lvmeng <848755140@qq.com> Date: Tue, 2 Jun 2026 11:14:48 +0800 Subject: [PATCH] =?UTF-8?q?feat(ui):=20=E6=96=B0=E5=A2=9E=E9=A4=90?= =?UTF-8?q?=E5=93=81=E5=88=97=E8=A1=A8=E5=92=8C=E8=8F=9C=E5=93=81=E5=8C=85?= =?UTF-8?q?=E8=A3=85=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 创建了 MealListActivity 餐品列表页面,用于展示可选的餐品 - 实现了餐品列表的 RecyclerView 展示和点击跳转功能 - 添加了 PackActivity 菜品包装页面,支持食材构成管理 - 集成了相机预览功能用于食材识别 - 实现了重量识别和食材添加功能 - 添加了侧滑删除菜单和食材重量管理 - 创建了 MealListAdapter 适配器用于餐品列表展示 --- .../dish/match/adapter/MealListAdapter.kt | 36 ++ .../shuwei/dish/match/ui/MealListActivity.kt | 98 +++ .../com/shuwei/dish/match/ui/PackActivity.kt | 607 ++++++++++++++++++ .../main/res/layout/activity_meal_list.xml | 41 ++ app/src/main/res/layout/activity_pack.xml | 231 +++++++ 5 files changed, 1013 insertions(+) create mode 100644 app/src/main/java/com/shuwei/dish/match/adapter/MealListAdapter.kt create mode 100644 app/src/main/java/com/shuwei/dish/match/ui/MealListActivity.kt create mode 100644 app/src/main/java/com/shuwei/dish/match/ui/PackActivity.kt create mode 100644 app/src/main/res/layout/activity_meal_list.xml create mode 100644 app/src/main/res/layout/activity_pack.xml diff --git a/app/src/main/java/com/shuwei/dish/match/adapter/MealListAdapter.kt b/app/src/main/java/com/shuwei/dish/match/adapter/MealListAdapter.kt new file mode 100644 index 0000000..4c81a3d --- /dev/null +++ b/app/src/main/java/com/shuwei/dish/match/adapter/MealListAdapter.kt @@ -0,0 +1,36 @@ +package com.shuwei.dish.match.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.shuwei.dish.match.databinding.ListItemFood2Binding +import com.shuwei.dish.match.model.NutFoodOptionVO + +/** + * 餐品列表适配器 + */ +class MealListAdapter(list: MutableList) : + BaseQuickAdapter(list) { + + inner class VH(var binding: ListItemFood2Binding) : QuickViewHolder(binding.root) + + override fun onBindViewHolder( + holder: VH, + position: Int, + item: NutFoodOptionVO? + ) { + holder.binding.tvDishInfo.text = item?.foodName + } + + override fun onCreateViewHolder( + context: Context, + parent: ViewGroup, + viewType: Int + ): VH { + val inflater = LayoutInflater.from(context) + val binding = ListItemFood2Binding.inflate(inflater, parent, false) + return VH(binding) + } +} diff --git a/app/src/main/java/com/shuwei/dish/match/ui/MealListActivity.kt b/app/src/main/java/com/shuwei/dish/match/ui/MealListActivity.kt new file mode 100644 index 0000000..ea0a2ed --- /dev/null +++ b/app/src/main/java/com/shuwei/dish/match/ui/MealListActivity.kt @@ -0,0 +1,98 @@ +package com.shuwei.dish.match.ui + +import android.content.Intent +import android.os.Bundle +import androidx.recyclerview.widget.LinearLayoutManager +import com.shuwei.dish.match.adapter.MealListAdapter +import com.shuwei.dish.match.base.BaseActivity +import com.shuwei.dish.match.databinding.ActivityMealListBinding +import com.shuwei.dish.match.model.NutFoodOptionVO +import com.shuwei.dish.match.net.NetViewModelV2 +import com.shuwei.dish.match.net.UiState +import com.shuwei.dish.match.utils.ext.gone +import com.shuwei.dish.match.utils.ext.toast +import com.shuwei.dish.match.utils.ext.visible + +/** + * 餐品列表页面 + */ +class MealListActivity : BaseActivity() { + + companion object { + const val MEAL_ITEM = "mealItem" + } + + private val binding by lazy { ActivityMealListBinding.inflate(layoutInflater) } + private val viewModelV2 by lazy { NetViewModelV2() } + + private val mealList = mutableListOf() + private val mealAdapter by lazy { MealListAdapter(mealList) } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(binding.root) + setHeaderBackground() + setTitleBar(titleBarAction = { + it.visible() + }, titleAction = { + it.text = "餐品列表" + }, rightIconAction = { + it.gone() + }, backAction = { + it.setOnClickListener { + finish() + } + }) + + initRecyclerView() + loadMealList() + } + + /** + * 初始化 RecyclerView + */ + private fun initRecyclerView() { + binding.rvMealList.layoutManager = LinearLayoutManager(this) + binding.rvMealList.adapter = mealAdapter + mealAdapter.setOnItemClickListener { _, _, position -> + val item = mealList.getOrNull(position) ?: return@setOnItemClickListener + val intent = Intent(this, PackActivity::class.java).apply { + putExtra(PackActivity.MEAL_ITEM, item) + } + startActivity(intent) + } + } + + /** + * 加载餐品列表 + */ + private fun loadMealList() { + viewModelV2.getFoodOptionsWithCallback( + keyword = null, + pageNum = 1, + pageSize = 100, + onLoading = { + showLoading("加载中……") + }, + onResult = { state -> + dismissLoading() + when (state) { + is UiState.Success -> { + val records = state.data?.records + if (records.isNullOrEmpty()) { + toast("暂无数据") + return@getFoodOptionsWithCallback + } + mealList.clear() + mealList.addAll(records) + mealAdapter.notifyDataSetChanged() + } + is UiState.Error -> { + toast(state.msg) + } + else -> {} + } + } + ) + } +} diff --git a/app/src/main/java/com/shuwei/dish/match/ui/PackActivity.kt b/app/src/main/java/com/shuwei/dish/match/ui/PackActivity.kt new file mode 100644 index 0000000..00d6893 --- /dev/null +++ b/app/src/main/java/com/shuwei/dish/match/ui/PackActivity.kt @@ -0,0 +1,607 @@ +package com.shuwei.dish.match.ui + +import android.annotation.SuppressLint +import android.content.Intent +import android.os.Bundle +import android.util.Log +import android.view.GestureDetector +import android.view.MotionEvent +import android.view.ViewGroup +import androidx.activity.addCallback +import androidx.core.content.IntentCompat +import androidx.lifecycle.lifecycleScope +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.shuwei.dish.match.R +import com.shuwei.dish.match.adapter.FoodMaterialAdapter +import com.shuwei.dish.match.base.BaseActivity +import com.shuwei.dish.match.databinding.ActivityPackBinding +import com.shuwei.dish.match.databinding.LayoutCameraPreviewBinding +import com.shuwei.dish.match.dialog.CommonDialog +import com.shuwei.dish.match.model.CookFoodDTO +import com.shuwei.dish.match.db.entity.CookFoodGoodsEntity +import com.shuwei.dish.match.model.FoodRecord +import com.shuwei.dish.match.model.GoodsItem +import com.shuwei.dish.match.model.NutFoodOptionVO +import com.shuwei.dish.match.net.UiState +import com.shuwei.dish.match.objbox.FoodModule +import com.shuwei.dish.match.utils.AddressUtil +import com.shuwei.dish.match.utils.CameraUtils +import com.shuwei.dish.match.utils.ImageUtil +import com.shuwei.dish.match.utils.SpTool +import com.shuwei.dish.match.utils.WeightUtil +import com.shuwei.dish.match.utils.ext.addOnActionSearchListener +import com.shuwei.dish.match.utils.ext.clickWithDebounce +import com.shuwei.dish.match.utils.ext.dp +import com.shuwei.dish.match.utils.ext.gone +import com.shuwei.dish.match.utils.ext.startActivity +import com.shuwei.dish.match.utils.ext.toJsonString +import com.shuwei.dish.match.utils.ext.toast +import com.shuwei.dish.match.utils.ext.visible +import com.yanzhenjie.recyclerview.SwipeMenuItem +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.io.Serializable +import java.util.concurrent.atomic.AtomicBoolean +import kotlin.math.abs +import com.shuwei.dish.match.model.NutFoodComposition +import com.shuwei.dish.match.net.NetViewModelV2 +import com.shuwei.dish.match.utils.ext.roundedOneDecimalPlace + +@SuppressLint("NotifyDataSetChanged") +class PackActivity : BaseActivity() { + + companion object { + const val TAG = "PackActivity" + const val MEAL_ITEM = "mealItem" + const val PAGE_FROM = "pageFrom" + const val HOME = "home" + const val WEIGHT_CHANGE_VALUE = 5 + const val WEIGHT_RECOGNIZE_VALUE = 10 + + /** 主材数量上限 */ + const val MATERIAL_COUNT = 3 + } + + private val binding by lazy { ActivityPackBinding.inflate(layoutInflater) } + + private val cameraUtils: CameraUtils by lazy { CameraUtils(this) } + + private var mealItem: NutFoodOptionVO? = null + + /** 来源页面标识,HOME 时返回跳转 SamplingListActivity */ + private var pageFrom: String? = null + + private var goodsList: MutableList? = null + private val viewModelV2 by lazy { NetViewModelV2() } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(binding.root) + setHeaderBackground() + pageFrom = intent.getStringExtra(PAGE_FROM) + mealItem = IntentCompat.getParcelableExtra(intent, MEAL_ITEM, NutFoodOptionVO::class.java) + + mealItem?.let { + binding.etInputDish.run { + setText(it.foodName) + tag = it.foodName + } + } + + val isSamplingMode = SpTool.cookMode == 1 + val titleText = if (isSamplingMode) "菜品信息采集" else "菜品净菜包装" + setTitleBar(titleBarAction = { + it.visible() + }, titleAction = { + it.text = titleText + }, rightIconAction = { + it.gone() + }, backAction = { + it.setOnClickListener { + onBackPressedDispatcher.onBackPressed() + } + }) + + // 不可编辑,仅展示菜名 + binding.etInputDish.isFocusable = false + binding.etInputDish.isFocusableInTouchMode = false + binding.ivDishSearch.gone() + + addViewClickListener() + addBackKeyListener() + initCamera(binding.flCameraContainer) + initRecyclerView() + initObserver() + + // 根据传入的餐品数据加载食材列表 + mealItem?.let { + val compositions = it.compositions + if (!compositions.isNullOrEmpty()) { + loadDishCompositions(compositions) + } else { + toast("该餐品无食材构成信息") + } + } + } + private var currentWeight = 0.0 + private fun addViewClickListener() { + // ========== 重量识别相关功能已注释 ========== + WeightUtil.addWeightListener( + weightKey = TAG, + getWeight = { address, state, weight -> + if (address == AddressUtil.ONE && state == WeightUtil.STATE_STABLE) { + runOnUiThread { + currentWeight = weight - initialWeight + binding.tvShowWeight.run { + if (tag != currentWeight) { +// text = "称重:${netWeight}g" + val weightText = "${currentWeight.roundedOneDecimalPlace()}g" + text = weightText + tag = currentWeight + } + } + //recognizeFood(netWeight) + } + } + }) + + if (SpTool.cookMode == 1) { + // 采集模式:绑定搜索栏交互 + binding.ivDishSearch.visible() + binding.etInputDish.isFocusable = true + binding.etInputDish.isFocusableInTouchMode = true + binding.ivDishSearch.setOnClickListener { jumpSearch() } + binding.etInputDish.addOnActionSearchListener { jumpSearch() } + } + +// binding.btnCook.clickWithDebounce { +// if (SpTool.cookMode == 1) { +// // 采集模式:从输入框创建 FoodRecord +// val showFoodName = binding.etInputDish.text.toString().trim() +// if (showFoodName.isBlank()) { +// toast("菜品名称为空") +// return@clickWithDebounce +// } +// if (list.isEmpty()) { +// toast("菜品构成信息未设置") +// return@clickWithDebounce +// } +// val foodRecord = FoodRecord().apply { +// foodId = mealItem?.foodId?.toString() +// foodName = showFoodName +// cookMode = 1 +// } +// Log.d(TAG, "goToSubmit: goodsList:${list.toJsonString()}") +// val submitList = list.map { it.toCookFoodGoodsEntity() }.toMutableList() +// startActivity { +// putExtra(SubmitFoodActivity.GOODS_LIST, submitList as Serializable) +// putExtra(SubmitFoodActivity.FOOD_ITEM, foodRecord as Serializable) +// } +// } else { +// // 包装模式:检查食材是否全部设置完成 +// val count = list.count { it.isSetFinished.not() } +// if (count > 0) { +// showRemindDialog() +// return@clickWithDebounce +// } +// openSubmitPage() +// } +// } + + binding.ivClearWeight.clickWithDebounce { + initialWeight = 0.0 + WeightUtil.tareTwo(1) + } + + binding.ivAddWeight.clickWithDebounce { + if(currentWeight <= 0.0) { + toast("当前秤重量无效") + return@clickWithDebounce + } + list.getOrNull(clickIndex)?.let { + it.useWeight = currentWeight + it.isSetFinished = true + materialAdapter.notifyItemChanged(clickIndex) + } + } + binding.btnGetCode.clickWithDebounce { + val item = list.getOrNull(clickIndex)?:return@clickWithDebounce + //viewModelV2.getCode + } + binding.btnSubmit.clickWithDebounce { + + } + } + +// private val isTakingPhoto = AtomicBoolean(false) + + // ========== 重量识别相关变量已注释 ========== +// private var showRecognizePage = false +// private var pageVisible = true +// private var manualCancelFlag = false +// private var lastPhotoUri: Uri? = null +// private var lastWeight = 0.0 +// private var currentWeight = 0.0 + private var initialWeight = SpTool.configWeight.toDouble() + +// private fun recognizeFood(weight: Double) { +// // 重量识别逻辑已注释 +// } + + /** + * 重新计算 list 中非接口数据(isOriginalData=false)的 materialType + * + * 规则: + * - 接口数据主材数量 n = list 中 isOriginalData=true 且 materialType=1 的数量 + * - 有接口数据且 MATERIAL_COUNT - n <= 0:所有非接口数据均为辅材(2) + * - 无接口数据,或 MATERIAL_COUNT - n > 0:m = MATERIAL_COUNT - n, + * 非接口数据按 useWeight 从大到小排序,前 m 个为主材(1),其余为辅材(2) + */ + private fun updateMaterialTypes() { + val hasOriginalData = list.any { it.isOriginalData } + // 接口数据中主材数量 + val n = list.count { it.isOriginalData && it.materialType == 1 } + // 待分配的非接口数据 + val nonOriginalList = list.filter { !it.isOriginalData } + + if (hasOriginalData && MATERIAL_COUNT - n <= 0) { + // 主材已满,所有非接口数据均为辅材 + nonOriginalList.forEach { it.materialType = 2 } + } else { + // 剩余可分配主材名额 + val m = MATERIAL_COUNT - n + // 按 useWeight 从大到小排序 + val sorted = nonOriginalList.sortedByDescending { it.useWeight ?: 0.0 } + sorted.forEachIndexed { index, item -> + item.materialType = if (index < m) 1 else 2 + } + } + materialAdapter.notifyDataSetChanged() + } + + private fun openSubmitPage() { + getGoodsList() + if (goodsList.isNullOrEmpty()) { + toast("无菜品构成信息") + return + } + Log.d(TAG, "goToSubmit: goodsList:${goodsList?.toJsonString()}") + startActivity { + putExtra(SubmitFoodActivity.GOODS_LIST, goodsList as Serializable) + putExtra(SubmitFoodActivity.FOOD_ITEM, FoodRecord().apply { + foodId = mealItem?.foodId?.toString() + foodName = mealItem?.foodName + }) + } + } + + private fun getGoodsList() { + if (goodsList == null) { + goodsList = mutableListOf() + } else { + goodsList!!.clear() + } + // 将 Goods Item 转换为 CookFoodGoodsEntity 并补充菜品相关字段 + list.filter { it.isSetFinished }.forEach { + goodsList?.add(it.toCookFoodGoodsEntity().apply { + foodId = mealItem?.foodId?.toString() + }) + } + } + + private fun showRemindDialog() { + CommonDialog(this) + .setTitle(getString(R.string.food_remind_01)) + .setContent(getString(R.string.food_remind_02)) + .setNegativeButton("返回调整") + .setPositiveButton("确认无误") { openSubmitPage() } + .setOnDismissCallback { hideStatusBar() } + .show() + } + + + private fun initObserver() { + lifecycleScope.launch { + netViewModel.foodDetailState.collect { state -> + when (state) { + is UiState.Success -> { + val detail = state.data + if (detail == null) { + toast("查询菜品信息为空") + return@collect + } + loadDishDetail(detail) + } + is UiState.Error -> toast(state.msg) + else -> {} + } + } + } + } + + // ========== getDishDetail 方法已删除,不再通过接口查询 ========== + + private fun loadDishDetail(detail: CookFoodDTO) { + val voList = detail.foodConstituteList + if (voList.isNullOrEmpty()) { + return + } + // 筛选出主材和辅材,转换为 Goods Item(useWeight 置零) + val tempData = voList.filter { it.materialType == 1 || it.materialType == 2 } + .map { it.toGoodsItem().also { item -> item.useWeight = 0.0 } } + // 直接替换 adapter.items + list.clear() + list.addAll(tempData) + materialAdapter.items = list + materialAdapter.notifyDataSetChanged() + firstReqSize = list.size + } + + /** + * 加载餐品食材构成(从 NutFoodOptionVO.compositions 解析) + */ + private fun loadDishCompositions(compositions: List) { + // 将 NutFoodComposition 转换为 Goods Item + val tempData = compositions.map { comp -> + GoodsItem().apply { + goodsId = comp.materId?.toString() ?: "" + goodsName = comp.ingredientName ?: "" + materialType = if (comp.isMain == 1) 1 else 2 + useWeight = 0.0 + isOriginalData = true + isSetFinished = false + } + }.toMutableList() + + list.clear() + list.addAll(tempData) + materialAdapter.items = list + materialAdapter.notifyDataSetChanged() + firstReqSize = list.size + } + + private var firstReqSize = 0 + private val list = mutableListOf() + private var clickIndex = -1 + private val materialAdapter by lazy { + FoodMaterialAdapter(list).apply { + onItemClick = { positon -> + this@PackActivity.clickIndex = positon + list.forEachIndexed { index, entity -> + entity.isClicked = index == positon + } + notifyDataSetChanged() + } + addOnItemChildClickListener(R.id.ivClearIcon) { _, _, position -> + val item = list.getOrNull(position) ?: return@addOnItemChildClickListener + Log.d(TAG, "onFoodItemClick: ${item.toJsonString()}") + if (item.isOriginalData) { + // 无重量信息时转为 item 整体点击(触发选中效果) + if (item.useWeight == null || item.useWeight == 0.0) { + onItemClick?.invoke(position) + return@addOnItemChildClickListener + } + deleteRemindDialog("清除确认", "确定清除食材「${item.goodsName}」添加的重量吗?") { + item.run { + isNewDishType = false + useWeight = 0.0 + isSetFinished = false + } + notifyItemChanged(position) + } + return@addOnItemChildClickListener + } + + deleteRemindDialog("删除确认", "确定删除食材「${item.goodsName}」吗?") { + removeFood(position) + } + } + } + } + + /** + * RecyclerView初始化 + */ + @SuppressLint("ClickableViewAccessibility") + private fun initRecyclerView() { + binding.rvMaterialList.let { + it.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false) + // 仅 isNewDishType=true 的 item 显示侧滑删除菜单(必须在 setAdapter 之前调用) + it.setSwipeMenuCreator { _, rightMenu, position -> + if (list.getOrNull(position)?.isNewDishType == true) { + rightMenu.addMenuItem(buildDeleteMenuItem()) + } + } + // 点击侧滑菜单项:先关闭菜单,再弹窗确认删除 + it.setOnItemMenuClickListener { menuBridge, position -> + menuBridge.closeMenu() + val item = list.getOrNull(position) ?: return@setOnItemMenuClickListener + deleteRemindDialog("删除确认", "确定删除食材「${item.goodsName}」吗?") { + removeFood(position) + } + } + // item 点击事件 + it.setOnItemClickListener { _, position -> + materialAdapter.onItemClick?.invoke(position) + } + handleRvTouchHideKeyboard() + it.adapter = materialAdapter + } + } + + /** + * 删除提醒 + */ + private fun deleteRemindDialog(title: String, content: String, action: () -> Unit) { + CommonDialog(this@PackActivity) + .setTitle(title) + .setContent(content) + .setNegativeButton("取消") + .setPositiveButton("确认") { + action() + }.show() + } + + /** + * 移除菜品 + */ + private fun removeFood(position: Int) { + materialAdapter.removeAt(position) + toast("已删除") + updateMaterialTypes() + } + + /** + * 构建侧滑删除菜单项 + */ + private fun buildDeleteMenuItem(): SwipeMenuItem { + return SwipeMenuItem(this).apply { + setImage(R.drawable.ic_trash_white) + setBackground(R.drawable.bg_swipe_delete) + width = 160.dp + height = ViewGroup.LayoutParams.MATCH_PARENT + } + } + + override fun onResume() { + super.onResume() +// pageVisible = true +// showRecognizePage = false + cameraUtils.bind() + } + + override fun onPause() { + super.onPause() +// pageVisible = false + cameraUtils.unbind() + } + + /** + * 初始化相机并绑定预览容器 + * @param container 相机预览容器 + */ + fun initCamera(container: ViewGroup) { + cameraUtils.initCamera() + val previewBinding = LayoutCameraPreviewBinding.inflate(layoutInflater, container) + cameraUtils.setPreviewController(previewBinding.previewView) + } + + /** + * 注册返回键监听,替代已废弃的 onBackPressed() + */ + private fun addBackKeyListener() { + onBackPressedDispatcher.addCallback(this) { + if (SpTool.cookMode == 1) { + // 采集模式:有新增食材时提示保存 + if (list.isEmpty().not()) { + saveDataRemindDialog() + return@addCallback + } + if (pageFrom == HOME) { + startActivity() + } + } else { + // 包装模式:有未保存数据时提示 + val count = list.count { !it.isOriginalData } + if (count > 0) { + saveDataRemindDialog() + return@addCallback + } + } + finish() + } + } + + /** + * 未保存数据提醒 + */ + private fun saveDataRemindDialog() { + CommonDialog(this) + .setTitle("返回提示") + .setContent("您好,当前页面存在未保存的数据,\n确认返回吗?") + .setNegativeButton("取消") + .setPositiveButton("确认") { + if (SpTool.cookMode == 1 && pageFrom == HOME) { + startActivity() + } + finish() + } + .setOnDismissCallback { hideStatusBar() } + .show() + } + + // ========== 拍照回调相关功能已注释 ========== +// private val cameraSuccessCallback: (Uri) -> Unit = { uri -> +// // 拍照成功回调已注释 +// } +// private var notRecognizeDialog: CommonDialog? = null +// private fun showNotRecognizeDialog() { +// // 未识别弹窗已注释 +// } +// private val cameraFailureCallback: (String) -> Unit = { errMsg -> +// // 拍照失败回调已注释 +// } +// private fun loadRecognizeResultPage(nameScoreList: List) { +// // 识别结果页加载已注释 +// } + + /** + * 跳转食物搜索页(采集模式专用) + */ + private fun jumpSearch() { + val searchContent = binding.etInputDish.text.toString().trim() + if (searchContent.isBlank()) { + toast(binding.etInputDish.hint.toString()) + return + } + val launchIntent = Intent(this, FoodSearchActivity::class.java).apply { + putExtra(FoodSearchActivity.FOOD_NAME, searchContent) + } + startActivity(launchIntent) { resultIntent -> + if (resultIntent == null) return@startActivity + val food = IntentCompat.getSerializableExtra(resultIntent, FoodSearchActivity.FOOD_ITEM, FoodRecord::class.java) + Log.d(TAG, "jumpSearch: record=$food") + if (food == null) return@startActivity + binding.etInputDish.run { + setText(food.foodName) + tag = food.foodName + setSelection(text.length) + } + } + hideKeyboard() + } + + private fun handleRvTouchHideKeyboard() { + val gestureDetector = GestureDetector(this, object : GestureDetector.SimpleOnGestureListener() { + override fun onSingleTapUp(e: MotionEvent): Boolean { + hideKeyboard() + return false + } + }) + binding.rvMaterialList.addOnItemTouchListener(object : RecyclerView.SimpleOnItemTouchListener() { + private var startX = 0f + private var startY = 0f + + override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean { + when (e.action) { + MotionEvent.ACTION_DOWN -> { + startX = e.x + startY = e.y + } + MotionEvent.ACTION_MOVE -> { + val dx = abs(e.x - startX) + val dy = abs(e.y - startY) + if (dx > dy && dx > 10) { + hideKeyboard() + } + } + } + gestureDetector.onTouchEvent(e) + return false + } + }) + } + +} diff --git a/app/src/main/res/layout/activity_meal_list.xml b/app/src/main/res/layout/activity_meal_list.xml new file mode 100644 index 0000000..dcc05e8 --- /dev/null +++ b/app/src/main/res/layout/activity_meal_list.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_pack.xml b/app/src/main/res/layout/activity_pack.xml new file mode 100644 index 0000000..059ebb4 --- /dev/null +++ b/app/src/main/res/layout/activity_pack.xml @@ -0,0 +1,231 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +