refactor(base): 重构基础组件和数据库访问层
- 修复 BaseActivity 中 rightIconActon 方法名拼写错误 - 重命名 appViewModel 为 dbViewModel 以统一数据库访问实例 - 优化 BaseApp 中的共享偏好设置获取逻辑 - 移除 GlobalData 中硬编码的应用ID和SDK密钥 - 重命名 NetworkUtils 为 NetworkUtil 并增强网络连接检测 - 重构 RemoteRepository 中的API调用方法结构 - 在多个Activity和Fragment中统一使用dbViewModel替代appViewModel - 优化食品列表合并烹饪中条目的逻辑处理 - 调整文件上传时的媒体类型定义 - 清理注释和代码结构以提高可维护性
This commit is contained in:
@@ -92,13 +92,13 @@ open class BaseActivity : AppCompatActivity() {
|
||||
titleBarAction: ((FrameLayout) -> Unit)? = null,
|
||||
backAction: ((ImageView) -> Unit)? = null,
|
||||
titleAction: ((TextView) -> Unit)? = null,
|
||||
rightIconActon: ((ImageView) -> Unit)? = null
|
||||
rightIconAction: ((ImageView) -> Unit)? = null
|
||||
) {
|
||||
binding.llTitleBar.visible()
|
||||
titleBarAction?.invoke(binding.llTitleBar)
|
||||
backAction?.invoke(binding.ivBack)
|
||||
titleAction?.invoke(binding.tvTitle)
|
||||
rightIconActon?.invoke(binding.ivRightIcon)
|
||||
rightIconAction?.invoke(binding.ivRightIcon)
|
||||
}
|
||||
|
||||
fun setHeaderBgVisible(show: Boolean) {
|
||||
@@ -182,7 +182,7 @@ open class BaseActivity : AppCompatActivity() {
|
||||
|
||||
|
||||
val netViewModel: NetViewModel by viewModels()
|
||||
val appViewModel: DbViewModel by viewModels()
|
||||
val dbViewModel: DbViewModel by viewModels()
|
||||
|
||||
private var singlePermissionCallback: ((isGranted: Boolean) -> Unit)? = null
|
||||
private var multiplePermissionsCallback: ((isGranted: Boolean) -> Unit)? = null
|
||||
|
||||
@@ -20,29 +20,19 @@ import com.shuwei.dish.match.utils.CrashHandler
|
||||
import com.shuwei.dish.match.utils.WeightUtil
|
||||
import com.shuwei.dish.match.utils.Weigher2
|
||||
|
||||
|
||||
/**
|
||||
* BaseApp is the main application class that extends Android's Application class.
|
||||
* It handles initialization of core components, device role determination,
|
||||
* and service management for the weighing system.
|
||||
*/
|
||||
class BaseApp : Application() {
|
||||
|
||||
// Lazy initialization of the database instance
|
||||
val database by lazy { DatabaseProvider(this).instance }
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
// Set the application instance
|
||||
instance = this
|
||||
// 读取本地保存的环境地址,覆盖默认值
|
||||
val savedBaseUrl = SpTool.baseUrl
|
||||
if (savedBaseUrl.isNotEmpty()) {
|
||||
GlobalData.appBaseUrl = savedBaseUrl
|
||||
}
|
||||
// Initialize crash handler for error tracking
|
||||
CrashHandler.init(this)
|
||||
// Get and store the unique device ID
|
||||
val deviceId = AppUtil.getUDID(this)
|
||||
Log.d(TAG, "onCreate: deviceId=$deviceId")
|
||||
GlobalData.deviceId = deviceId
|
||||
@@ -88,24 +78,21 @@ class BaseApp : Application() {
|
||||
|
||||
companion object {
|
||||
private val TAG = "BaseApp"
|
||||
// const val canteenId = "1678234139391512577"
|
||||
var canteenId = "0"
|
||||
// var configUrl = ""
|
||||
|
||||
// var token: String? = null
|
||||
// var deviceId: String? = null
|
||||
var appVersion: String = "1"
|
||||
@Volatile
|
||||
private var sharedPref: SharedPreferences? = null
|
||||
|
||||
public var instance: BaseApp? = null
|
||||
fun getSharedPref(): SharedPreferences? {
|
||||
if (sharedPref != null) {
|
||||
return sharedPref
|
||||
lateinit var instance: BaseApp
|
||||
|
||||
/** 双重检查锁,保证多线程下只初始化一次 */
|
||||
fun getSharedPref(): SharedPreferences {
|
||||
return sharedPref ?: synchronized(this) {
|
||||
sharedPref ?: instance.getSharedPreferences(
|
||||
instance.getString(R.string.sp_save_name),
|
||||
Context.MODE_PRIVATE
|
||||
).also { sharedPref = it }
|
||||
}
|
||||
val saveName = instance?.getString(R.string.sp_save_name)
|
||||
sharedPref = instance?.getSharedPreferences(saveName, Context.MODE_PRIVATE)
|
||||
return sharedPref
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,8 +25,6 @@ object GlobalData {
|
||||
* 当前设备角色,启动时从 SpTool 读取,默认为 SLAVE
|
||||
*/
|
||||
var deviceRole: DeviceRole = DeviceRole.SLAVE
|
||||
var appId = "Hkz1rBk6PZXbS8KwKr67K2eZtsz8bRoMHLg64bUdgCZj"
|
||||
var sdkKey = "AabXs3sHM8UhhE7oCGf4LVMLrdkGb1nJNksbjjTdVt7k"
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -225,7 +225,7 @@ class NetViewModel(
|
||||
params: MutableMap<String, RequestBody>
|
||||
) {
|
||||
val fileParts = fileList.map { file ->
|
||||
file.asRequestBody("image/jpeg".toMediaTypeOrNull())
|
||||
file.asRequestBody("multipart/form-data".toMediaTypeOrNull())
|
||||
.let { MultipartBody.Part.createFormData("foodPics", file.name, it) }
|
||||
}
|
||||
viewModelScope.launch {
|
||||
|
||||
@@ -5,7 +5,6 @@ import com.shuwei.dish.match.entity.FoodRecord
|
||||
import com.shuwei.dish.match.entity.GoodsItem
|
||||
import okhttp3.MultipartBody
|
||||
import okhttp3.RequestBody
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* 网络数据仓库,封装所有 ApiService 调用
|
||||
@@ -13,104 +12,42 @@ import java.io.File
|
||||
*/
|
||||
class RemoteRepository {
|
||||
|
||||
/**
|
||||
* 提交制作菜品
|
||||
* @param entity 菜品实体
|
||||
* @return UiState 包装的结果,Success 表示提交成功,Error 携带错误信息
|
||||
*/
|
||||
suspend fun submitCookFood(entity: CookFoodDTO): UiState<Any?> {
|
||||
/** 统一封装 API 调用:处理响应映射和异常转换,返回 UiState */
|
||||
private suspend fun <T> safeApiCall(call: suspend () -> ApiResponse<T>): UiState<T?> {
|
||||
return try {
|
||||
val resp = apiService.submitCookFood(param = entity)
|
||||
val resp = call()
|
||||
if (resp.isSuccess()) UiState.Success(resp.data)
|
||||
else UiState.Error(resp.code, resp.msg ?: "")
|
||||
} catch (e: Exception) {
|
||||
val ex = getApiException(e)
|
||||
UiState.Error("-1", ex.errorMsg)
|
||||
UiState.Error("-1", getApiException(e).errorMsg)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询菜品详情
|
||||
* @param foodId 菜品 ID
|
||||
* @return UiState 包装的结果,Success 携带详情数据,Error 携带错误信息
|
||||
*/
|
||||
suspend fun getFoodDetail(foodId: String): UiState<CookFoodDTO?> {
|
||||
return try {
|
||||
val resp = apiService.getFoodDetail(foodId = foodId)
|
||||
if (resp.isSuccess()) UiState.Success(resp.data)
|
||||
else UiState.Error(resp.code, resp.msg ?: "")
|
||||
} catch (e: Exception) {
|
||||
val ex = getApiException(e)
|
||||
UiState.Error("-1", ex.errorMsg)
|
||||
}
|
||||
}
|
||||
/** 提交制作菜品 */
|
||||
suspend fun submitCookFood(entity: CookFoodDTO): UiState<Any?> =
|
||||
safeApiCall { apiService.submitCookFood(param = entity) }
|
||||
|
||||
/**
|
||||
* 搜索菜品列表
|
||||
* @param param 查询参数
|
||||
* @return UiState 包装的结果,Success 携带列表数据,Error 携带错误信息
|
||||
*/
|
||||
suspend fun searchFoodList(param: MutableMap<String, Any>): UiState<MutableList<FoodRecord>?> {
|
||||
return try {
|
||||
val resp = apiService.searchFoodList(param = param)
|
||||
if (resp.isSuccess()) UiState.Success(resp.data)
|
||||
else UiState.Error(resp.code, resp.msg ?: "")
|
||||
} catch (e: Exception) {
|
||||
val ex = getApiException(e)
|
||||
UiState.Error("-1", ex.errorMsg)
|
||||
}
|
||||
}
|
||||
/** 查询菜品详情 */
|
||||
suspend fun getFoodDetail(foodId: String): UiState<CookFoodDTO?> =
|
||||
safeApiCall { apiService.getFoodDetail(foodId = foodId) }
|
||||
|
||||
/**
|
||||
* 查询采样数据列表
|
||||
* @param param 查询参数
|
||||
* @return UiState 包装的结果,Success 携带列表数据,Error 携带错误信息
|
||||
*/
|
||||
suspend fun getSamplingList(param: MutableMap<String, Any>): UiState<MutableList<FoodRecord>?> {
|
||||
return try {
|
||||
val resp = apiService.getSamplingList(param = param)
|
||||
if (resp.isSuccess()) UiState.Success(resp.data)
|
||||
else UiState.Error(resp.code, resp.msg ?: "")
|
||||
} catch (e: Exception) {
|
||||
val ex = getApiException(e)
|
||||
UiState.Error("-1", ex.errorMsg)
|
||||
}
|
||||
}
|
||||
/** 搜索菜品列表 */
|
||||
suspend fun searchFoodList(param: MutableMap<String, Any>): UiState<MutableList<FoodRecord>?> =
|
||||
safeApiCall { apiService.searchFoodList(param = param) }
|
||||
|
||||
/**
|
||||
* 查询物品信息列表(食材 goodsType=0,调料 goodsType=1 共用)
|
||||
* @param param 查询参数
|
||||
* @return UiState 包装的结果,Success 携带列表数据,Error 携带错误信息
|
||||
*/
|
||||
suspend fun queryGoodsList(param: MutableMap<String, Any>): UiState<MutableList<GoodsItem>?> {
|
||||
return try {
|
||||
val resp = apiService.queryGoodsList(param = param)
|
||||
if (resp.isSuccess()) UiState.Success(resp.data)
|
||||
else UiState.Error(resp.code, resp.msg ?: "")
|
||||
} catch (e: Exception) {
|
||||
val ex = getApiException(e)
|
||||
UiState.Error("-1", ex.errorMsg)
|
||||
}
|
||||
}
|
||||
/** 查询采样数据列表 */
|
||||
suspend fun getSamplingList(param: MutableMap<String, Any>): UiState<MutableList<FoodRecord>?> =
|
||||
safeApiCall { apiService.getSamplingList(param = param) }
|
||||
|
||||
/**
|
||||
* 上次采集数据
|
||||
* @param params 参数
|
||||
* @param foodPics 图片
|
||||
* @return UiState 包装的结果,Success 携带列表数据,Error 携带错误信息
|
||||
*/
|
||||
/** 查询物品信息列表(食材 goodsType=0,调料 goodsType=1 共用) */
|
||||
suspend fun queryGoodsList(param: MutableMap<String, Any>): UiState<MutableList<GoodsItem>?> =
|
||||
safeApiCall { apiService.queryGoodsList(param = param) }
|
||||
|
||||
/** 上传采集数据 */
|
||||
suspend fun uploadFoodVectorData(
|
||||
params: MutableMap<String, RequestBody>,
|
||||
foodPics: List<MultipartBody.Part>
|
||||
): UiState<List<String>?> {
|
||||
return try {
|
||||
val resp = apiService.uploadFoodVectorData(params = params, foodPics = foodPics)
|
||||
if (resp.isSuccess()) UiState.Success(resp.data)
|
||||
else UiState.Error(resp.code, resp.msg ?: "")
|
||||
} catch (e: Exception) {
|
||||
val ex = getApiException(e)
|
||||
UiState.Error("-1", ex.errorMsg)
|
||||
}
|
||||
}
|
||||
): UiState<List<String>?> =
|
||||
safeApiCall { apiService.uploadFoodVectorData(params = params, foodPics = foodPics) }
|
||||
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ class CollectedFoodActivity : BaseActivity() {
|
||||
.setContent(content)
|
||||
.setNegativeButton("取消")
|
||||
.setPositiveButton("确认") {
|
||||
appViewModel.removeCollectedFood(
|
||||
dbViewModel.removeCollectedFood(
|
||||
foodName = foodName,
|
||||
nameFilter = binding.editSearch.text.toString()
|
||||
)
|
||||
@@ -95,7 +95,7 @@ class CollectedFoodActivity : BaseActivity() {
|
||||
}
|
||||
}, titleAction = {
|
||||
it.text = "已采集食材"
|
||||
}, rightIconActon = {
|
||||
}, rightIconAction = {
|
||||
it.gone()
|
||||
}, backAction = {
|
||||
it.visible()
|
||||
@@ -110,7 +110,7 @@ class CollectedFoodActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
private fun loadCollectedFoodList(name: String = "") {
|
||||
appViewModel.loadCollectedFoodList(nameFilter = name)
|
||||
dbViewModel.loadCollectedFoodList(nameFilter = name)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,7 +120,7 @@ class CollectedFoodActivity : BaseActivity() {
|
||||
private fun initObserver() {
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
appViewModel.collectedFoodListState.collect { items ->
|
||||
dbViewModel.collectedFoodListState.collect { items ->
|
||||
foodList.clear()
|
||||
foodList.addAll(items)
|
||||
adapter.notifyDataSetChanged()
|
||||
|
||||
@@ -47,7 +47,7 @@ class CookingModeActivity : BaseActivity() {
|
||||
it.visible()
|
||||
}, titleAction = {
|
||||
it.text = "选择菜品"
|
||||
}, rightIconActon = {
|
||||
}, rightIconAction = {
|
||||
it.visible()
|
||||
it.setImageResource(R.drawable.ic_setting)
|
||||
it.setOnClickListener {
|
||||
@@ -63,7 +63,7 @@ class CookingModeActivity : BaseActivity() {
|
||||
|
||||
|
||||
fun getCookFoodList() {
|
||||
appViewModel.getCookFoodList(cookMode = 0, dinnerType = dinnerType)
|
||||
dbViewModel.getCookFoodList(cookMode = 0, dinnerType = dinnerType)
|
||||
}
|
||||
|
||||
private var configFinished = false
|
||||
@@ -73,7 +73,7 @@ class CookingModeActivity : BaseActivity() {
|
||||
// block()
|
||||
// return
|
||||
// }
|
||||
// appViewModel.loadSeasoning {
|
||||
// dbViewModel.loadSeasoning {
|
||||
// if (it.isEmpty()) {
|
||||
// showDeviceConfigDialog()
|
||||
// return@loadSeasoning
|
||||
@@ -96,7 +96,7 @@ class CookingModeActivity : BaseActivity() {
|
||||
/** 切换餐次时清空输入框,用此标志跳过 afterTextChanged 的查询触发 */
|
||||
private var isClearingByTabSwitch = false
|
||||
|
||||
fun addViewListener() {
|
||||
private fun addViewListener() {
|
||||
binding.dishRadioGroup.setOnCheckedChangeListener { _, checkedId ->
|
||||
dinnerType = when (checkedId) {
|
||||
R.id.rbBreakfast -> "1"
|
||||
@@ -157,7 +157,7 @@ class CookingModeActivity : BaseActivity() {
|
||||
|
||||
fun deleteCookFoodAndGoods(foodId: String, dinnerType: String, action: () -> Unit) {
|
||||
lifecycleScope.launch {
|
||||
appViewModel.deleteCookFoodAndGoods(cookMode = 0, foodId = foodId, dinnerType = dinnerType)
|
||||
dbViewModel.deleteCookFoodAndGoods(cookMode = 0, foodId = foodId, dinnerType = dinnerType)
|
||||
action()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
// it.visible()
|
||||
// }, titleAction = {
|
||||
// it.text = "设备配置"
|
||||
// }, rightIconActon = {
|
||||
// }, rightIconAction = {
|
||||
// it.gone()
|
||||
//// it.alpha = 0.0F
|
||||
//// it.setImageResource(R.drawable.ic_setting)
|
||||
|
||||
@@ -78,7 +78,7 @@ class FoodSearchActivity : BaseActivity() {
|
||||
it.visible()
|
||||
}, titleAction = {
|
||||
it.text = "菜品搜索"
|
||||
}, rightIconActon = {
|
||||
}, rightIconAction = {
|
||||
it.gone()
|
||||
it.setImageResource(R.drawable.ic_setting)
|
||||
it.setOnClickListener {
|
||||
|
||||
@@ -66,18 +66,18 @@ class HomeActivity : BaseActivity() {
|
||||
// startActivity<SamplingListActivity>()
|
||||
// }
|
||||
|
||||
// appViewModel.deleteSeasoningBySort(12)
|
||||
// appViewModel.deleteSeasoningBySort(11)
|
||||
// appViewModel.deleteSeasoningBySort(13)
|
||||
// appViewModel.deleteSeasoningBySort(14)
|
||||
// appViewModel.deleteCookFoodAndGoods(0,"") {}
|
||||
// appViewModel.getCookFoodGoodsList("") {goodsList->
|
||||
// dbViewModel.deleteSeasoningBySort(12)
|
||||
// dbViewModel.deleteSeasoningBySort(11)
|
||||
// dbViewModel.deleteSeasoningBySort(13)
|
||||
// dbViewModel.deleteSeasoningBySort(14)
|
||||
// dbViewModel.deleteCookFoodAndGoods(0,"") {}
|
||||
// dbViewModel.getCookFoodGoodsList("") {goodsList->
|
||||
// goodsList.forEach {
|
||||
// it.foodId = "1594990392084779010"
|
||||
// appViewModel.updateGoods(it)
|
||||
// dbViewModel.updateGoods(it)
|
||||
// }
|
||||
// }
|
||||
// appViewModel.clearAllSeasoning(){}
|
||||
// dbViewModel.clearAllSeasoning(){}
|
||||
|
||||
|
||||
// binding.btnDeviceConfig.setOnClickListener {
|
||||
@@ -141,14 +141,14 @@ class HomeActivity : BaseActivity() {
|
||||
|
||||
private fun goSampling() {
|
||||
lifecycleScope.launch {
|
||||
val slots = appViewModel.loadSeasoningSlot()
|
||||
val slots = dbViewModel.loadSeasoningSlot()
|
||||
if (slots.isEmpty()) {
|
||||
// 无调料信息,打开采样历史列表页面,点击设置配置调料信息
|
||||
startActivity<SamplingModeActivity>()
|
||||
finish()
|
||||
return@launch
|
||||
}
|
||||
val count = appViewModel.countCookFood(cookMode = 1)
|
||||
val count = dbViewModel.countCookFood(cookMode = 1)
|
||||
if (count > 0) {
|
||||
// 有烹饪中数据,打开采样历史列表页面
|
||||
startActivity<SamplingModeActivity>()
|
||||
|
||||
@@ -18,7 +18,7 @@ import com.shuwei.dish.match.objbox.FoodModule
|
||||
import com.shuwei.dish.match.scale.ScaleServiceManager
|
||||
import com.shuwei.dish.match.utils.AddressUtil
|
||||
import com.shuwei.dish.match.utils.AppUtil
|
||||
import com.shuwei.dish.match.utils.NetworkUtils
|
||||
import com.shuwei.dish.match.utils.NetworkUtil
|
||||
import com.shuwei.dish.match.utils.SpTool
|
||||
import com.shuwei.dish.match.utils.ext.gone
|
||||
import com.shuwei.dish.match.utils.ext.startActivity
|
||||
@@ -54,7 +54,7 @@ class InitActivity : BaseActivity() {
|
||||
countdownHandler.postDelayed(this, 100)
|
||||
} else {
|
||||
// 倒计时结束,最后检测一次网络
|
||||
if (NetworkUtils.isNetworkConnected(this@InitActivity)) {
|
||||
if (NetworkUtil.isNetworkConnected(this@InitActivity)) {
|
||||
startNextPage()
|
||||
} else {
|
||||
// 网络未连接,显示"连接网络"按钮
|
||||
@@ -116,13 +116,13 @@ class InitActivity : BaseActivity() {
|
||||
|
||||
private fun goSampling() {
|
||||
lifecycleScope.launch {
|
||||
val slots = appViewModel.loadSeasoningSlot()
|
||||
val slots = dbViewModel.loadSeasoningSlot()
|
||||
if (slots.isEmpty()) {
|
||||
// 无调料信息,打开采样历史列表页面,点击设置配置调料信息
|
||||
startActivity<SamplingModeActivity>()
|
||||
return@launch
|
||||
}
|
||||
val count = appViewModel.countCookFood(cookMode = 1)
|
||||
val count = dbViewModel.countCookFood(cookMode = 1)
|
||||
if (count > 0) {
|
||||
// 有烹饪中数据,打开采样历史列表页面
|
||||
startActivity<SamplingModeActivity>()
|
||||
@@ -169,7 +169,7 @@ class InitActivity : BaseActivity() {
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if (NetworkUtils.isNetworkConnected(this)) {
|
||||
if (NetworkUtil.isNetworkConnected(this)) {
|
||||
// 有网络时隐藏网络检测区域,直接跳转
|
||||
binding.llNetwork.gone()
|
||||
startNextPage(withDelay = false)
|
||||
@@ -213,7 +213,7 @@ class InitActivity : BaseActivity() {
|
||||
* 检测网络连接
|
||||
*/
|
||||
private fun checkNetworkConnection() {
|
||||
if (NetworkUtils.isNetworkConnected(this)) {
|
||||
if (NetworkUtil.isNetworkConnected(this)) {
|
||||
// 网络连接成功,停止倒计时并跳转到 HomeActivity
|
||||
countdownHandler.removeCallbacks(countdownTask)
|
||||
startNextPage()
|
||||
|
||||
@@ -81,7 +81,7 @@ class MasterScaleActivity : BaseActivity() {
|
||||
/** 从 Room 加载槽位配置到 slotNameMap,加载完成后启动数据观测 */
|
||||
private fun loadSlotNames() {
|
||||
lifecycleScope.launch {
|
||||
val slots = appViewModel.loadSeasoningSlot()
|
||||
val slots = dbViewModel.loadSeasoningSlot()
|
||||
slots.forEach { slot ->
|
||||
slotNameMap["${slot.deviceId}#${slot.address}"] = slot.goodsName
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ class PrepareFoodActivity : BaseActivity() {
|
||||
it.visible()
|
||||
}, titleAction = {
|
||||
it.text = titleText
|
||||
}, rightIconActon = {
|
||||
}, rightIconAction = {
|
||||
it.gone()
|
||||
}, backAction = {
|
||||
it.setOnClickListener {
|
||||
|
||||
@@ -57,7 +57,7 @@ class SamplingModeActivity : BaseActivity() {
|
||||
it.visible()
|
||||
}, titleAction = {
|
||||
it.text = "采样历史"
|
||||
}, rightIconActon = {
|
||||
}, rightIconAction = {
|
||||
it.visible()
|
||||
it.setImageResource(R.drawable.ic_setting)
|
||||
it.setOnClickListener {
|
||||
@@ -70,7 +70,7 @@ class SamplingModeActivity : BaseActivity() {
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
fun getCookFoodList() {
|
||||
appViewModel.getCookFoodListWithCallback(cookMode = 1) { cookFoodEntities ->
|
||||
dbViewModel.getCookFoodListWithCallback(cookMode = 1) { cookFoodEntities ->
|
||||
// 回调期间用户可能已切换 Tab,需再次校验
|
||||
if (binding.rbSamplingCooking.isChecked.not()) return@getCookFoodListWithCallback
|
||||
delayDismissLoading()
|
||||
@@ -103,7 +103,7 @@ class SamplingModeActivity : BaseActivity() {
|
||||
|
||||
fun deleteCookFoodAndGoods(foodId: String, dinnerType: String, action: () -> Unit) {
|
||||
lifecycleScope.launch {
|
||||
appViewModel.deleteCookFoodAndGoods(cookMode = 1, foodId = foodId, dinnerType = dinnerType)
|
||||
dbViewModel.deleteCookFoodAndGoods(cookMode = 1, foodId = foodId, dinnerType = dinnerType)
|
||||
action()
|
||||
}
|
||||
}
|
||||
@@ -399,7 +399,7 @@ class SamplingModeActivity : BaseActivity() {
|
||||
return
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
val slots = appViewModel.loadSeasoningSlot()
|
||||
val slots = dbViewModel.loadSeasoningSlot()
|
||||
if (slots.isEmpty()) {
|
||||
showDeviceConfigDialog()
|
||||
return@launch
|
||||
|
||||
@@ -44,7 +44,7 @@ class SettingActivity : BaseActivity() {
|
||||
it.visible()
|
||||
}, titleAction = {
|
||||
it.text = "设备设置"
|
||||
}, rightIconActon = {
|
||||
}, rightIconAction = {
|
||||
it.visible()
|
||||
it.clickWithDebounce {
|
||||
binding.llDbInspect.visible()
|
||||
@@ -107,7 +107,7 @@ class SettingActivity : BaseActivity() {
|
||||
.setContent("将物理删除全部 4 张表数据(菜品、食材、调料、槽位),此操作不可恢复,同时重置菜品模式和食堂id,确认继续?")
|
||||
.setNegativeButton("取消")
|
||||
.setPositiveButton("确认") {
|
||||
appViewModel.clearAllData {
|
||||
dbViewModel.clearAllData {
|
||||
SpTool.cookMode = -1
|
||||
SpTool.canteenId = "0"
|
||||
// 通知所有已连接子设备同步清除数据
|
||||
|
||||
@@ -81,7 +81,7 @@ class SingleFragmentActivity : BaseActivity() {
|
||||
setTitleBar(
|
||||
titleBarAction = { it.visible() },
|
||||
titleAction = { it.text = getTitleForPage(pageType) },
|
||||
rightIconActon = { it.gone() }
|
||||
rightIconAction = { it.gone() }
|
||||
)
|
||||
|
||||
// 首次创建时加载 Fragment,避免屏幕旋转重复添加
|
||||
|
||||
@@ -162,7 +162,7 @@ class SlaveActivity : BaseActivity() {
|
||||
*/
|
||||
private fun loadSlotsFromDb() {
|
||||
lifecycleScope.launch {
|
||||
val slots = appViewModel.getSeasoningSlotsByDeviceId(GlobalData.deviceId)
|
||||
val slots = dbViewModel.getSeasoningSlotsByDeviceId(GlobalData.deviceId)
|
||||
applySlots(slots)
|
||||
}
|
||||
}
|
||||
@@ -179,8 +179,8 @@ class SlaveActivity : BaseActivity() {
|
||||
?: return@onSeasoningConfig
|
||||
lifecycleScope.launch {
|
||||
// 全量替换:先删除本机所有旧槽位,再写入最新配置
|
||||
appViewModel.deleteAllSlotsByDeviceId(GlobalData.deviceId)
|
||||
appViewModel.upsertAllSeasoningSlots(mySlots)
|
||||
dbViewModel.deleteAllSlotsByDeviceId(GlobalData.deviceId)
|
||||
dbViewModel.upsertAllSeasoningSlots(mySlots)
|
||||
applySlots(mySlots)
|
||||
}
|
||||
}
|
||||
@@ -194,7 +194,7 @@ class SlaveActivity : BaseActivity() {
|
||||
private fun listenClearData() {
|
||||
ScaleServiceManager.onClearData = {
|
||||
lifecycleScope.launch {
|
||||
appViewModel.clearAllData {
|
||||
dbViewModel.clearAllData {
|
||||
SpTool.cookMode = -1
|
||||
SpTool.canteenId = "0"
|
||||
runOnUiThread { applySlots(emptyList()) }
|
||||
|
||||
@@ -126,7 +126,7 @@ class SubmitFoodActivity : BaseActivity() {
|
||||
it.visible()
|
||||
}, titleAction = {
|
||||
it.text = food?.foodName
|
||||
}, rightIconActon = {
|
||||
}, rightIconAction = {
|
||||
it.gone()
|
||||
}, backAction = {
|
||||
it.setOnClickListener {
|
||||
@@ -179,7 +179,7 @@ class SubmitFoodActivity : BaseActivity() {
|
||||
*/
|
||||
private fun loadSlotsThenObserveScales() {
|
||||
lifecycleScope.launch {
|
||||
val slots = appViewModel.loadSeasoningSlot()
|
||||
val slots = dbViewModel.loadSeasoningSlot()
|
||||
slots.forEach { slot ->
|
||||
slotMap["${slot.deviceId}#${slot.address}"] = slot.goodsId to slot.goodsName
|
||||
}
|
||||
@@ -188,7 +188,7 @@ class SubmitFoodActivity : BaseActivity() {
|
||||
val foodId = food?.foodId ?: return@launch
|
||||
val cookMode = food?.cookMode ?: return@launch
|
||||
val list =
|
||||
appViewModel.getCookFoodGoodsList(foodId, cookMode, food?.dinnerType ?: "0")
|
||||
dbViewModel.getCookFoodGoodsList(foodId, cookMode, food?.dinnerType ?: "0")
|
||||
goodsList = list
|
||||
prefillSeasoningFromGoodsList(list)
|
||||
} else {
|
||||
@@ -387,7 +387,7 @@ class SubmitFoodActivity : BaseActivity() {
|
||||
seasoningAdapter.items
|
||||
.filter { it.useWeight > 0.0 }
|
||||
.forEach { goodsList?.add(buildSeasoningEntity(it)) }
|
||||
appViewModel.saveCookFoodAndGoods(
|
||||
dbViewModel.saveCookFoodAndGoods(
|
||||
cookMode = food!!.cookMode,
|
||||
entity = cookFoodEntity,
|
||||
list = goodsList
|
||||
@@ -440,7 +440,7 @@ class SubmitFoodActivity : BaseActivity() {
|
||||
* 从本地 dm_seasoning 表补充完整字段(popularName、zjmCode、materId、goodsCode 等)
|
||||
*/
|
||||
private suspend fun buildSeasoningEntity(item: SeasoningWeightAdapter.Item): CookFoodGoodsEntity {
|
||||
val seasoning = appViewModel.getSeasoningByGoodsId(item.goodsId)
|
||||
val seasoning = dbViewModel.getSeasoningByGoodsId(item.goodsId)
|
||||
return CookFoodGoodsEntity().also { entity ->
|
||||
entity.foodId = cookFoodEntity.foodId
|
||||
entity.goodsId = item.goodsId
|
||||
@@ -465,7 +465,7 @@ class SubmitFoodActivity : BaseActivity() {
|
||||
}
|
||||
// 用 viewModelScope 执行删除,不受当前 Activity 生命周期影响
|
||||
// singleTask 跳转会销毁本 Activity 并取消 lifecycleScope,导致删除被中断
|
||||
appViewModel.markSubmittedAndDeleteAsync(
|
||||
dbViewModel.markSubmittedAndDeleteAsync(
|
||||
cookMode = food!!.cookMode,
|
||||
foodId = food!!.foodId!!,
|
||||
dinnerType = food!!.dinnerType
|
||||
|
||||
@@ -87,12 +87,12 @@ class DbInspectFragment : BaseFragment<FragmentDbInspectBinding>() {
|
||||
|
||||
// 加载更多按钮
|
||||
binding.tvLoadMore.setOnClickListener {
|
||||
currentActivity.appViewModel.loadMoreDbInspect(currentTableIndex, showDel)
|
||||
currentActivity.dbViewModel.loadMoreDbInspect(currentTableIndex, showDel)
|
||||
}
|
||||
|
||||
// 订阅 UI 状态
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
currentActivity.appViewModel.dbInspectState.collect { state ->
|
||||
currentActivity.dbViewModel.dbInspectState.collect { state ->
|
||||
renderState(state)
|
||||
}
|
||||
}
|
||||
@@ -105,7 +105,7 @@ class DbInspectFragment : BaseFragment<FragmentDbInspectBinding>() {
|
||||
}
|
||||
|
||||
private fun loadFirstPage() {
|
||||
currentActivity.appViewModel.loadDbInspect(currentTableIndex, showDel)
|
||||
currentActivity.dbViewModel.loadDbInspect(currentTableIndex, showDel)
|
||||
}
|
||||
|
||||
private fun renderState(state: DbViewModel.DbInspectUiState) {
|
||||
|
||||
@@ -194,7 +194,7 @@ class FoodListFragment : BaseFragment<FragmentFoodListBinding>() {
|
||||
)
|
||||
foodName?.let { param["foodName"] = it }
|
||||
if (pageNo == 1) {
|
||||
pendingLocalList = activity.appViewModel.getCookFoodListDirect(
|
||||
pendingLocalList = activity.dbViewModel.getCookFoodListDirect(
|
||||
cookMode = 0,
|
||||
dinnerType = dinnerType
|
||||
)
|
||||
@@ -285,45 +285,69 @@ class FoodListFragment : BaseFragment<FragmentFoodListBinding>() {
|
||||
if (pageNo == 1) list.clear()
|
||||
|
||||
val mergedList = records?.toMutableList() ?: mutableListOf()
|
||||
|
||||
if (!effectiveLocalList.isNullOrEmpty()) {
|
||||
val cookingItems = mutableListOf<FoodRecord>()
|
||||
effectiveLocalList.forEachIndexed { index, entity ->
|
||||
val food = mergedList.firstOrNull { it.foodId == entity.foodId }
|
||||
if (food != null) {
|
||||
mergedList.remove(food)
|
||||
food.isCooking = true
|
||||
food.sort = index
|
||||
food.dinnerType = entity.dinnerType ?: "0"
|
||||
cookingItems.add(food)
|
||||
} else {
|
||||
cookingItems.add(
|
||||
FoodRecord(
|
||||
foodId = entity.foodId,
|
||||
foodName = entity.foodName,
|
||||
sort = index,
|
||||
dinnerType = entity.dinnerType ?: "0",
|
||||
isCooking = true
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
mergedList.addAll(0, cookingItems)
|
||||
}
|
||||
|
||||
if (pageNo >= 2 && !localList.isNullOrEmpty()) {
|
||||
val localIds = localList.map { it.foodId }.toHashSet()
|
||||
mergedList.removeAll { it.foodId in localIds }
|
||||
}
|
||||
|
||||
list.addAll(mergedList)
|
||||
dishAdapter.notifyDataSetChanged()
|
||||
val isLoadMoreEnable = (records?.size ?: 0) >= pageSize
|
||||
binding.refreshLayout.setEnableRefresh(true)
|
||||
binding.refreshLayout.setEnableLoadMore(isLoadMoreEnable)
|
||||
if (isLoadMoreEnable) pageNo++
|
||||
mergeCookingItems(mergedList, effectiveLocalList)
|
||||
deduplicateForPaging(mergedList, localList)
|
||||
renderList(mergedList, records)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将本地烹饪中条目置顶合并到网络列表:
|
||||
* 网络列表中已有的条目标记 isCooking 并移至顶部,没有的则新建占位条目
|
||||
*/
|
||||
private fun mergeCookingItems(
|
||||
mergedList: MutableList<FoodRecord>,
|
||||
cookingEntities: List<CookFoodEntity>?
|
||||
) {
|
||||
if (cookingEntities.isNullOrEmpty()) return
|
||||
val cookingItems = mutableListOf<FoodRecord>()
|
||||
cookingEntities.forEachIndexed { index, entity ->
|
||||
val existing = mergedList.firstOrNull { it.foodId == entity.foodId }
|
||||
if (existing != null) {
|
||||
mergedList.remove(existing)
|
||||
existing.isCooking = true
|
||||
existing.sort = index
|
||||
existing.dinnerType = entity.dinnerType ?: "0"
|
||||
cookingItems.add(existing)
|
||||
} else {
|
||||
cookingItems.add(
|
||||
FoodRecord(
|
||||
foodId = entity.foodId,
|
||||
foodName = entity.foodName,
|
||||
sort = index,
|
||||
dinnerType = entity.dinnerType ?: "0",
|
||||
isCooking = true
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
mergedList.addAll(0, cookingItems)
|
||||
}
|
||||
|
||||
/**
|
||||
* 翻页时从网络结果中剔除第一页已加载的本地烹饪中条目,避免重复出现
|
||||
*/
|
||||
private fun deduplicateForPaging(
|
||||
mergedList: MutableList<FoodRecord>,
|
||||
localList: List<CookFoodEntity>?
|
||||
) {
|
||||
if (pageNo < 2 || localList.isNullOrEmpty()) return
|
||||
val localIds = localList.map { it.foodId }.toHashSet()
|
||||
mergedList.removeAll { it.foodId in localIds }
|
||||
}
|
||||
|
||||
/**
|
||||
* 将合并结果追加到列表并刷新 UI,按网络返回条数决定是否开启加载更多
|
||||
*/
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private fun renderList(mergedList: List<FoodRecord>, records: List<FoodRecord>?) {
|
||||
list.addAll(mergedList)
|
||||
dishAdapter.notifyDataSetChanged()
|
||||
val isLoadMoreEnable = (records?.size ?: 0) >= pageSize
|
||||
binding.refreshLayout.setEnableRefresh(true)
|
||||
binding.refreshLayout.setEnableLoadMore(isLoadMoreEnable)
|
||||
if (isLoadMoreEnable) pageNo++
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ class SeasoningConfigFragment : BaseFragment<FragmentSeasoningConfigBinding>() {
|
||||
) = FragmentSeasoningConfigBinding.inflate(inflater, container, false)
|
||||
|
||||
private lateinit var currentActivity: SingleFragmentActivity
|
||||
// private lateinit var appViewModel: DbViewModel
|
||||
// private lateinit var dbViewModel: DbViewModel
|
||||
|
||||
private val adapter22 by lazy { buildAdapter22() }
|
||||
private val adapter18 by lazy {
|
||||
@@ -186,7 +186,7 @@ class SeasoningConfigFragment : BaseFragment<FragmentSeasoningConfigBinding>() {
|
||||
onUpdateName(name)
|
||||
lifecycleScope.launch {
|
||||
// 保存槽位配置
|
||||
currentActivity.appViewModel.upsertSeasoningSlot(
|
||||
currentActivity.dbViewModel.upsertSeasoningSlot(
|
||||
SeasoningSlotEntity(
|
||||
deviceId = deviceId,
|
||||
address = address,
|
||||
@@ -195,7 +195,7 @@ class SeasoningConfigFragment : BaseFragment<FragmentSeasoningConfigBinding>() {
|
||||
)
|
||||
)
|
||||
// 按 goodsId 去重保存完整调料信息到 dm_seasoning
|
||||
currentActivity.appViewModel.upsertSeasoningByGoodsId(item.toSeasoningEntity())
|
||||
currentActivity.dbViewModel.upsertSeasoningByGoodsId(item.toSeasoningEntity())
|
||||
broadcastAllSlots()
|
||||
}
|
||||
}
|
||||
@@ -205,7 +205,7 @@ class SeasoningConfigFragment : BaseFragment<FragmentSeasoningConfigBinding>() {
|
||||
/** 将单个槽位写入 Room,再广播全量配置给子设备 */
|
||||
private fun saveSlotAndBroadcast(slot: SeasoningSlotEntity) {
|
||||
lifecycleScope.launch {
|
||||
currentActivity.appViewModel.upsertSeasoningSlot(slot)
|
||||
currentActivity.dbViewModel.upsertSeasoningSlot(slot)
|
||||
broadcastAllSlots()
|
||||
}
|
||||
}
|
||||
@@ -233,14 +233,14 @@ class SeasoningConfigFragment : BaseFragment<FragmentSeasoningConfigBinding>() {
|
||||
/** 从 Room 删除指定槽位,再广播全量配置给子设备 */
|
||||
private fun deleteSlotAndBroadcast(deviceId: String, address: Int) {
|
||||
lifecycleScope.launch {
|
||||
currentActivity.appViewModel.deleteSeasoningSlot(deviceId, address)
|
||||
currentActivity.dbViewModel.deleteSeasoningSlot(deviceId, address)
|
||||
broadcastAllSlots()
|
||||
}
|
||||
}
|
||||
|
||||
/** 读取全量槽位配置并通过 wsClient 推送给所有已连接子设备 */
|
||||
private suspend fun broadcastAllSlots() {
|
||||
val allSlots = currentActivity.appViewModel.loadSeasoningSlot().map {
|
||||
val allSlots = currentActivity.dbViewModel.loadSeasoningSlot().map {
|
||||
SlotConfig(it.deviceId, it.address, it.goodsId, it.goodsName)
|
||||
}
|
||||
ScaleServiceManager.sendSeasoningConfig(allSlots)
|
||||
@@ -249,7 +249,7 @@ class SeasoningConfigFragment : BaseFragment<FragmentSeasoningConfigBinding>() {
|
||||
// /** 初始化 ViewModel */
|
||||
// private fun initViewModel() {
|
||||
// val factory = AppFactory(DbRepository(BaseApp.instance!!.database.appDao()))
|
||||
// appViewModel = ViewModelProvider(this, factory)[DbViewModel::class.java]
|
||||
// dbViewModel = ViewModelProvider(this, factory)[DbViewModel::class.java]
|
||||
// }
|
||||
|
||||
|
||||
@@ -292,9 +292,9 @@ class SeasoningConfigFragment : BaseFragment<FragmentSeasoningConfigBinding>() {
|
||||
adapter22.update(emptyList())
|
||||
adapter18.update(emptyList())
|
||||
lifecycleScope.launch {
|
||||
val slots22 = currentActivity.appViewModel.getSeasoningSlotsByDeviceId(ScaleDeviceConfig.DEVICE_ID_22)
|
||||
val slots18 = currentActivity.appViewModel.getSeasoningSlotsByDeviceId(ScaleDeviceConfig.DEVICE_ID_18)
|
||||
val slotsOil = currentActivity.appViewModel.getSeasoningSlotsByDeviceId(ScaleDeviceConfig.DEVICE_ID_1)
|
||||
val slots22 = currentActivity.dbViewModel.getSeasoningSlotsByDeviceId(ScaleDeviceConfig.DEVICE_ID_22)
|
||||
val slots18 = currentActivity.dbViewModel.getSeasoningSlotsByDeviceId(ScaleDeviceConfig.DEVICE_ID_18)
|
||||
val slotsOil = currentActivity.dbViewModel.getSeasoningSlotsByDeviceId(ScaleDeviceConfig.DEVICE_ID_1)
|
||||
slots22.forEach { slot ->
|
||||
val pos = ScaleDeviceConfig.SCALE_ORDER_22.indexOf(slot.address)
|
||||
if (pos >= 0) adapter22.updateItemName(pos, slot.goodsName)
|
||||
|
||||
@@ -3,15 +3,28 @@ package com.shuwei.dish.match.utils
|
||||
import android.content.Context
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.LinkProperties
|
||||
import android.net.NetworkCapabilities
|
||||
import android.net.wifi.WifiManager
|
||||
import android.os.Build
|
||||
import java.net.Inet4Address
|
||||
|
||||
/**
|
||||
* 网络工具类
|
||||
* 网络工具类,提供网络状态检测和本机 IP 获取功能
|
||||
*/
|
||||
object NetworkUtil {
|
||||
|
||||
/**
|
||||
* 检测设备是否连接到网络
|
||||
* @param context 应用上下文
|
||||
* @return true 表示已连接网络,false 表示未连接
|
||||
*/
|
||||
fun isNetworkConnected(context: Context): Boolean {
|
||||
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
val network = cm.activeNetwork ?: return false
|
||||
val capabilities = cm.getNetworkCapabilities(network) ?: return false
|
||||
return capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取本机局域网 IPv4 地址
|
||||
* - Android 12+(API 31+):使用 ConnectivityManager + LinkProperties,避免废弃 API
|
||||
@@ -60,3 +73,4 @@ object NetworkUtil {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
package com.shuwei.dish.match.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.NetworkCapabilities
|
||||
|
||||
/**
|
||||
* 网络连接检测工具类
|
||||
* 提供检测设备网络连接状态的功能
|
||||
*/
|
||||
object NetworkUtils {
|
||||
|
||||
/**
|
||||
* 检测设备是否连接到网络
|
||||
* @param context 应用上下文
|
||||
* @return true 表示已连接网络,false 表示未连接
|
||||
*/
|
||||
fun isNetworkConnected(context: Context): Boolean {
|
||||
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
val network = connectivityManager.activeNetwork ?: return false
|
||||
val capabilities = connectivityManager.getNetworkCapabilities(network) ?: return false
|
||||
return capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user