From 1024d82958d8726fd4a223f5cb9bca105107cdeb Mon Sep 17 00:00:00 2001 From: lvmeng <848755140@qq.com> Date: Fri, 15 May 2026 15:18:26 +0800 Subject: [PATCH] =?UTF-8?q?refactor(ui):=20=E5=B0=86=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E7=94=B1=E5=A4=9A=E4=B8=AA=20LinearLayout=20?= =?UTF-8?q?=E9=87=8D=E6=9E=84=E4=B8=BA=20RecyclerView=20=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- .../dish/match/adapter/SettingAdapter.kt | 42 +++ .../shuwei/dish/match/model/SettingItem.kt | 38 ++ .../shuwei/dish/match/ui/SettingActivity.kt | 326 +++++------------ app/src/main/res/layout/activity_setting.xml | 329 +----------------- app/src/main/res/layout/list_item_setting.xml | 46 +++ 5 files changed, 213 insertions(+), 568 deletions(-) create mode 100644 app/src/main/java/com/shuwei/dish/match/adapter/SettingAdapter.kt create mode 100644 app/src/main/java/com/shuwei/dish/match/model/SettingItem.kt create mode 100644 app/src/main/res/layout/list_item_setting.xml diff --git a/app/src/main/java/com/shuwei/dish/match/adapter/SettingAdapter.kt b/app/src/main/java/com/shuwei/dish/match/adapter/SettingAdapter.kt new file mode 100644 index 0000000..15f4212 --- /dev/null +++ b/app/src/main/java/com/shuwei/dish/match/adapter/SettingAdapter.kt @@ -0,0 +1,42 @@ +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.ListItemSettingBinding +import com.shuwei.dish.match.model.SettingItem +import com.shuwei.dish.match.utils.ext.gone +import com.shuwei.dish.match.utils.ext.visible + +/** + * 设置页面列表适配器 + * 点击事件直接调用 item.onClick(),无需在 Adapter 中分发业务逻辑 + */ +class SettingAdapter : BaseQuickAdapter() { + + override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH { + val binding = ListItemSettingBinding.inflate(LayoutInflater.from(context), parent, false) + return VH(binding) + } + + override fun onBindViewHolder(holder: VH, position: Int, item: SettingItem?) { + item ?: return + holder.binding.tvTitle.text = item.title + + // 有副标题则显示,否则隐藏 + val subtitle = item.subtitle + if (subtitle != null) { + holder.binding.tvSubtitle.visible() + holder.binding.tvSubtitle.text = subtitle + } else { + holder.binding.tvSubtitle.gone() + } + + // 点击事件直接委托给实体类中注入的 lambda + holder.binding.root.setOnClickListener { item.onClick() } + } + + inner class VH(val binding: ListItemSettingBinding) : QuickViewHolder(binding.root) +} diff --git a/app/src/main/java/com/shuwei/dish/match/model/SettingItem.kt b/app/src/main/java/com/shuwei/dish/match/model/SettingItem.kt new file mode 100644 index 0000000..669fbc4 --- /dev/null +++ b/app/src/main/java/com/shuwei/dish/match/model/SettingItem.kt @@ -0,0 +1,38 @@ +package com.shuwei.dish.match.model + +/** + * 设置页面的列表项实体类 + * + * @param type 菜单项类型,用于唯一标识每一项 + * @param title 主标题文字 + * @param subtitle 副标题文字,仅部分项目(如菜品模式)有值 + * @param isHidden 是否为隐藏项,隐藏项需触发开发者模式后才显示 + * @param onClick 点击回调,初始化时直接注入对应的业务逻辑 + */ +data class SettingItem( + val type: Type, + val title: String, + val subtitle: String? = null, + val isHidden: Boolean = false, + val onClick: () -> Unit +) { + /** 设置菜单项类型枚举 */ + enum class Type { + /** 菜品模式切换 */ + COOK_MODE, + /** 调料区设置 */ + SEASONING_CONFIG, + /** 食材采集 */ + FOOD_COLLECT, + /** 数据库查看(隐藏项) */ + DB_INSPECT, + /** 秤数据监控(隐藏项) */ + SCALE_OBSERVE, + /** 切换环境(隐藏项) */ + ENV_SWITCH, + /** 数据清除(隐藏项) */ + CLEAR_DATA, + /** 测试调料拿取(隐藏项) */ + TEST_SEASONING, + } +} diff --git a/app/src/main/java/com/shuwei/dish/match/ui/SettingActivity.kt b/app/src/main/java/com/shuwei/dish/match/ui/SettingActivity.kt index 4c31aea..cfae2ec 100644 --- a/app/src/main/java/com/shuwei/dish/match/ui/SettingActivity.kt +++ b/app/src/main/java/com/shuwei/dish/match/ui/SettingActivity.kt @@ -9,10 +9,13 @@ import android.os.Build import android.os.Bundle import android.provider.Settings import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.LinearLayoutManager +import com.shuwei.dish.match.adapter.SettingAdapter import com.shuwei.dish.match.base.BaseActivity import com.shuwei.dish.match.databinding.ActivitySettingBinding import com.shuwei.dish.match.dialog.CommonDialog import com.shuwei.dish.match.dialog.EnvSwitchDialog +import com.shuwei.dish.match.model.SettingItem import com.shuwei.dish.match.scale.ScaleServiceManager import com.shuwei.dish.match.utils.SpTool import com.shuwei.dish.match.utils.ext.clickWithDebounce @@ -20,8 +23,8 @@ import com.shuwei.dish.match.utils.ext.startActivity import com.shuwei.dish.match.utils.ext.visible /** - * 设置Activity - * 功能:管理多个设置相关的Fragment,支持Fragment切换 + * 设置页面 + * 使用 RecyclerView 展示设置菜单项,点击逻辑内聚在各 SettingItem 的 onClick 中 */ class SettingActivity : BaseActivity() { @@ -30,10 +33,11 @@ class SettingActivity : BaseActivity() { } private lateinit var binding: ActivitySettingBinding -// private val cameraUtils: CameraUtils by lazy { -// CameraUtils(this) -// } -// private lateinit var previewView: PreviewView + + /** 包含全部菜单项的完整列表(含隐藏项) */ + private val allItems: List by lazy { buildAllItems() } + + private val adapter = SettingAdapter() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -46,58 +50,84 @@ class SettingActivity : BaseActivity() { it.text = "设备设置" }, rightIconAction = { it.visible() + // 点击右上角图标,展示全部隐藏的开发者选项 it.clickWithDebounce { - binding.llDbInspect.visible() - binding.llScaleObserve.visible() - binding.llClearData.visible() - binding.llEnvSwitch.visible() - binding.llTestSeasoning.visible() + adapter.submitList(allItems.toList()) } }) initView() - -// // 默认显示设备配置Fragment -// if (savedInstanceState == null) { -// showDeviceConfigFragment() -// } -// -// initUI() } - private fun initView() { - binding.tvCurrentMode.text = when (SpTool.cookMode) { - 0 -> "当前:制作模式" - 1 -> "当前:采样模式" - else -> "当前:未知模式" - } - binding.llCookMode.clickWithDebounce { - SingleFragmentActivity.start(this, SingleFragmentActivity.PageType.COOK_MODE) - } - binding.llSeasoningConfig.clickWithDebounce { - SingleFragmentActivity.start(this, SingleFragmentActivity.PageType.SEASONING_CONFIG) - } - binding.llFoodCollect.clickWithDebounce { - checkCameraPermission() - } - binding.llDbInspect.clickWithDebounce { - SingleFragmentActivity.start(this, SingleFragmentActivity.PageType.DB_INSPECT) - } - binding.llScaleObserve.clickWithDebounce { - startActivity() - } - binding.llClearData.clickWithDebounce { - showClearDataDialog() - } - binding.llEnvSwitch.clickWithDebounce { - EnvSwitchDialog(this).show() - } - binding.llTestSeasoning.clickWithDebounce { - startActivity { } - } + binding.rvSettings.layoutManager = LinearLayoutManager(this) + binding.rvSettings.adapter = adapter + // 默认只展示非隐藏项 + adapter.submitList(allItems.filter { !it.isHidden }) } + /** + * 构建完整的设置菜单列表,每项的 onClick 直接注入对应业务逻辑 + */ + private fun buildAllItems(): List = listOf( + SettingItem( + type = SettingItem.Type.COOK_MODE, + title = "菜品模式", + subtitle = when (SpTool.cookMode) { + 0 -> "当前:制作模式" + 1 -> "当前:采样模式" + else -> "当前:未知模式" + }, + onClick = { + SingleFragmentActivity.start(this, SingleFragmentActivity.PageType.COOK_MODE) + } + ), + SettingItem( + type = SettingItem.Type.SEASONING_CONFIG, + title = "调料区设置", + onClick = { + SingleFragmentActivity.start(this, SingleFragmentActivity.PageType.SEASONING_CONFIG) + } + ), + SettingItem( + type = SettingItem.Type.FOOD_COLLECT, + title = "食材采集", + onClick = { checkCameraPermission() } + ), + SettingItem( + type = SettingItem.Type.DB_INSPECT, + title = "数据库查看", + isHidden = true, + onClick = { + SingleFragmentActivity.start(this, SingleFragmentActivity.PageType.DB_INSPECT) + } + ), + SettingItem( + type = SettingItem.Type.SCALE_OBSERVE, + title = "秤数据监控", + isHidden = true, + onClick = { startActivity() } + ), + SettingItem( + type = SettingItem.Type.ENV_SWITCH, + title = "切换环境", + isHidden = true, + onClick = { EnvSwitchDialog(this).show() } + ), + SettingItem( + type = SettingItem.Type.CLEAR_DATA, + title = "数据清除", + isHidden = true, + onClick = { showClearDataDialog() } + ), + SettingItem( + type = SettingItem.Type.TEST_SEASONING, + title = "测试调料拿取", + isHidden = true, + onClick = { startActivity { } } + ), + ) + /** * 弹出清除测试数据的二次确认弹窗 */ @@ -123,12 +153,11 @@ class SettingActivity : BaseActivity() { } /** - * 检查相机权限并显示 CollectFragment + * 检查相机权限,有权限则直接打开采集页,否则发起授权请求 */ @SuppressLint("ObsoleteSdkInt") private fun checkCameraPermission() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { - // Android 6.0 以下,直接打开 openCollectPage() return } @@ -137,16 +166,12 @@ class SettingActivity : BaseActivity() { Manifest.permission.CAMERA ) == PackageManager.PERMISSION_GRANTED ) { - // 权限已授予,直接打开 openCollectPage() } else { - // 权限未授予,申请权限 requestPermission(Manifest.permission.CAMERA) { isGranted -> if (isGranted) { - // 权限已授予,直接打开 openCollectPage() } else { - // 权限被拒绝 showNotGrantedCameraPermissionDialog() } } @@ -168,197 +193,4 @@ class SettingActivity : BaseActivity() { } .show() } - -// -// /** -// * 初始化UI和事件监听 -// */ -// private fun initUI() { -// // 设备配置按钮点击事件 -// binding.btnDeviceConfig.setOnClickListener { -// showDeviceConfigFragment() -// -// loadTabStyle(button = binding.btnDeviceConfig, isSelected = true) -// loadTabStyle(button = binding.btnSeasoningConfig, isSelected = false) -// loadTabStyle(button = binding.btnFoodCollect, isSelected = false) -// } -// -// // 调料配置按钮点击事件 -// binding.btnSeasoningConfig.setOnClickListener { -// showSeasoningConfigFragment() -// -// loadTabStyle(button = binding.btnDeviceConfig, isSelected = false) -// loadTabStyle(button = binding.btnSeasoningConfig, isSelected = true) -// loadTabStyle(button = binding.btnFoodCollect, isSelected = false) -// } -// -// // 菜品采集按钮点击事件 -// binding.btnFoodCollect.setOnClickListener { -// checkCameraPermissionAndShowFragment() -// -// loadTabStyle(button = binding.btnDeviceConfig, isSelected = false) -// loadTabStyle(button = binding.btnSeasoningConfig, isSelected = false) -// loadTabStyle(button = binding.btnFoodCollect, isSelected = true) -// } -// -// // 主设备显示「秤数据监控」入口 -// if (GlobalData.deviceRole == DeviceRole.MASTER) { -// binding.btnScaleMonitor.visible() -// binding.btnScaleMonitor.setOnClickListener { -// startActivity() -// } -// } -// -// // 初始化按钮颜色(默认设备配置为选中状态) -// -// loadTabStyle(button = binding.btnDeviceConfig, isSelected = true) -// loadTabStyle(button = binding.btnSeasoningConfig, isSelected = false) -// loadTabStyle(button = binding.btnFoodCollect, isSelected = false) -// } -// -// /** -// * 加载顶部Tab按钮样式 -// * -// * @param button 按钮 -// * @param isSelected 是否选中 -// */ -// private fun loadTabStyle(button: AppCompatButton, isSelected: Boolean) { -// button.apply { -// if (isSelected){ -// // 选中 -// setTextColor(Color.WHITE) -// textSize = 28f -// setTypeface(null, android.graphics.Typeface.BOLD) -// background = ContextCompat.getDrawable(this@SettingActivity, R.drawable.bg_btn_underline) -// } else { -// // 未选中 -// setTextColor("#5E7585".toColorInt()) -// textSize = 26f -// setTypeface(null, android.graphics.Typeface.NORMAL) -// background = null -// } -// } -// } -// -// /** -// * 检查相机权限并显示 CollectFragment -// */ -// @SuppressLint("ObsoleteSdkInt") -// private fun checkCameraPermissionAndShowFragment() { -// val collectFragment = fragmentList[2] -// if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { -// // Android 6.0 以下,直接显示 Fragment -// showFragment(collectFragment) -// return -// } -// if (ContextCompat.checkSelfPermission( -// this, -// Manifest.permission.CAMERA -// ) == PackageManager.PERMISSION_GRANTED -// ) { -// // 权限已授予,直接显示 Fragment -// showFragment(collectFragment) -// } else { -// // 权限未授予,申请权限 -// requestPermission(Manifest.permission.CAMERA) { isGranted -> -// if (isGranted) { -// // 权限已授予,显示 CollectFragment -// showFragment(collectFragment) -// } else { -// // 权限被拒绝 -// toast("暂无相机权限,无法使用菜品采集功能") -// } -// } -// } -// } -// -// /** -// * 初始化相机 -// * @param container 相机预览容器 -// */ -// fun initCamera(container: ViewGroup) { -// cameraUtils.initCamera() -// val previewBinding = -// LayoutCameraPreviewBinding.inflate(layoutInflater, container) -// previewView = previewBinding.previewView.also { -// it.updateLayoutParams { -// width = 456.dp -// height = 342.dp -// } -// } -// cameraUtils.setPreviewController(previewView) -// } -// -// /** -// * Activity 恢复时绑定相机 -// */ -// override fun onResume() { -// super.onResume() -// cameraUtils.bind() -// } -// -// /** -// * Activity 暂停时解绑相机 -// */ -// override fun onPause() { -// super.onPause() -// cameraUtils.unbind() -// } -// -// /** -// * 提供给 Fragment 调用的拍照方法 -// */ -// fun takePhoto(succCallback: (Uri) -> Unit, failCallback: (msg: String) -> Unit = {}) { -// cameraUtils.takePhoto(succCallback = succCallback, failCallback = failCallback) -// } -// -// /** -// * 显示设备切换Fragment -// */ -// private fun showDeviceConfigFragment() { -// showFragment(fragmentList[0]) -// } -// -// /** -// * 显示设调料配置Fragment -// */ -// private fun showSeasoningConfigFragment() { -// showFragment(fragmentList[1]) -// } -// -// private val fragmentList = mutableListOf().apply { -// add(DeviceConfigFragment()) -// add(SeasoningConfigFragment()) -// add(CollectFragment()) -// } -// -// /** -// * 显示指定的 Fragment -// * 使用 add/show/hide 方式管理 Fragment,避免重复创建 -// * 已添加的 Fragment 直接显示,未添加的 Fragment 先添加再显示 -// */ -// private fun showFragment(fragment: Fragment) { -// runCatching { -// supportFragmentManager.beginTransaction().apply { -// // 如果 Fragment 还未添加到容器中,则添加 -// if (!fragment.isAdded) { -// add(binding.fragmentContainer.id, fragment) -// } else { -// // 已添加过,直接显示 -// show(fragment) -// } -// -// // 隐藏其他 Fragment -// fragmentList.forEach { otherFragment -> -// if (otherFragment != fragment && otherFragment.isAdded) { -// hide(otherFragment) -// } -// } -// -// commit() -// } -// }.onFailure { -// it.printStackTrace() -// } -// } } diff --git a/app/src/main/res/layout/activity_setting.xml b/app/src/main/res/layout/activity_setting.xml index 33ccc06..3bf2d45 100644 --- a/app/src/main/res/layout/activity_setting.xml +++ b/app/src/main/res/layout/activity_setting.xml @@ -5,328 +5,15 @@ android:layout_height="match_parent" android:orientation="vertical" tools:background="@color/bg_color" - tools:ignore="HardcodedText,UnusedAttribute"> + tools:ignore="UnusedAttribute"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + android:layout_height="match_parent" + android:clipToPadding="false" + android:paddingBottom="30dp" + android:overScrollMode="never" + tools:listitem="@layout/list_item_setting"/> diff --git a/app/src/main/res/layout/list_item_setting.xml b/app/src/main/res/layout/list_item_setting.xml new file mode 100644 index 0000000..b9c1eb3 --- /dev/null +++ b/app/src/main/res/layout/list_item_setting.xml @@ -0,0 +1,46 @@ + + + + + + + + + + +