Compare commits
12
Commits
75830b9204
...
f3d57177b8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f3d57177b8 | ||
|
|
267628411a | ||
|
|
58fb78c7bd | ||
|
|
9f0671410f | ||
|
|
0243fe0dc8 | ||
|
|
df0580d68f | ||
|
|
deab289747 | ||
|
|
debc7a0740 | ||
|
|
441cffe4da | ||
|
|
3581975ab0 | ||
|
|
9e99e6ef6d | ||
|
|
16fe64e9fe |
@@ -115,6 +115,11 @@
|
||||
android:theme="@style/Theme.DishMatch.NoSplash"
|
||||
android:screenOrientation="portrait"
|
||||
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
|
||||
<activity
|
||||
android:name="com.shuwei.dish.match.ui.CollectedFoodActivity"
|
||||
android:theme="@style/Theme.DishMatch.NoSplash"
|
||||
android:screenOrientation="portrait"
|
||||
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
|
||||
<activity
|
||||
android:name="com.shuwei.dish.match.ui.SlaveActivity"
|
||||
android:theme="@style/Theme.DishMatch.NoSplash"
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
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.ListItemCollectedFoodBinding
|
||||
import com.shuwei.dish.match.entity.CollectedFoodItem
|
||||
|
||||
/**
|
||||
* 已采集食材列表适配器
|
||||
* 展示食材名称和已采集数量,支持删除操作
|
||||
*/
|
||||
class CollectedFoodAdapter(list: MutableList<CollectedFoodItem>) :
|
||||
BaseQuickAdapter<CollectedFoodItem, CollectedFoodAdapter.VH>(list) {
|
||||
|
||||
/** ViewHolder,持有列表项 ViewBinding */
|
||||
inner class VH(val binding: ListItemCollectedFoodBinding) : QuickViewHolder(binding.root)
|
||||
|
||||
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
|
||||
val binding = ListItemCollectedFoodBinding.inflate(LayoutInflater.from(context), parent, false)
|
||||
return VH(binding)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: VH, position: Int, item: CollectedFoodItem?) {
|
||||
item ?: return
|
||||
holder.binding.tvFoodName.text = item.foodName.split("WP").first()
|
||||
holder.binding.tvCollectCount.text = "已采集${item.collectCount}"
|
||||
}
|
||||
}
|
||||
@@ -21,9 +21,8 @@ import androidx.core.view.WindowInsetsControllerCompat
|
||||
import com.shuwei.dish.match.R
|
||||
import com.shuwei.dish.match.databinding.ActivityBaseBinding
|
||||
import com.shuwei.dish.match.dialog.Loading
|
||||
import com.shuwei.dish.match.entity.CookFoodGoodsEntity
|
||||
import com.shuwei.dish.match.entity.SeasoningEntity
|
||||
import com.shuwei.dish.match.net.NetViewModel
|
||||
import com.shuwei.dish.match.db.DbViewModel
|
||||
import com.shuwei.dish.match.ui.InitActivity
|
||||
import com.shuwei.dish.match.utils.ActivityManager
|
||||
import com.shuwei.dish.match.utils.ext.dp
|
||||
@@ -41,8 +40,6 @@ open class BaseActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var binding: ActivityBaseBinding
|
||||
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
// 提前隐藏系统栏,避免窗口创建时导航栏闪烁
|
||||
@@ -183,22 +180,7 @@ open class BaseActivity : AppCompatActivity() {
|
||||
|
||||
|
||||
val netViewModel: NetViewModel by viewModels()
|
||||
fun queryGoodsList(
|
||||
param: MutableMap<String, Any>,
|
||||
onSuccess: (MutableList<CookFoodGoodsEntity>?) -> Unit,
|
||||
onFailure: (String, String) -> Unit
|
||||
) {
|
||||
netViewModel.queryGoodsList(param, onSuccess, onFailure)
|
||||
}
|
||||
|
||||
fun querySeasoningList(
|
||||
param: MutableMap<String, Any>,
|
||||
onSuccess: (MutableList<SeasoningEntity>?) -> Unit,
|
||||
onFailure: (String, String) -> Unit
|
||||
) {
|
||||
netViewModel.querySeasoningList(param, onSuccess, onFailure)
|
||||
}
|
||||
|
||||
val appViewModel: DbViewModel by viewModels()
|
||||
|
||||
private var permissionCallback: ((isGranted: Boolean) -> Unit)? = null
|
||||
private var activityCallback: ((intent: Intent?) -> Unit)? = null
|
||||
|
||||
@@ -6,7 +6,9 @@ import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import com.shuwei.dish.match.db.dao.AppDao
|
||||
import com.shuwei.dish.match.db.dao.CookFoodDao
|
||||
import com.shuwei.dish.match.db.dao.CookFoodGoodsDao
|
||||
import com.shuwei.dish.match.db.dao.SeasoningDao
|
||||
import com.shuwei.dish.match.db.dao.SeasoningSlotDao
|
||||
import com.shuwei.dish.match.entity.CookFoodEntity
|
||||
import com.shuwei.dish.match.entity.CookFoodGoodsEntity
|
||||
@@ -27,11 +29,12 @@ import com.shuwei.dish.match.entity.SeasoningSlotEntity
|
||||
exportSchema = true
|
||||
)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
// abstract fun seasoningDao(): SeasoningDao
|
||||
// abstract fun cookFoodDao(): CookFoodDao
|
||||
// abstract fun cookFoodGoodsDao(): CookFoodGoodsDao
|
||||
|
||||
abstract fun appDao(): AppDao
|
||||
abstract fun cookFoodDao(): CookFoodDao
|
||||
|
||||
abstract fun cookFoodGoodsDao(): CookFoodGoodsDao
|
||||
|
||||
abstract fun seasoningDao(): SeasoningDao
|
||||
|
||||
abstract fun seasoningSlotDao(): SeasoningSlotDao
|
||||
|
||||
|
||||
+57
-35
@@ -1,110 +1,103 @@
|
||||
package com.shuwei.dish.match.db
|
||||
|
||||
import com.shuwei.dish.match.base.BaseApp
|
||||
import com.shuwei.dish.match.db.dao.AppDao
|
||||
import com.shuwei.dish.match.db.dao.SeasoningSlotDao
|
||||
import com.shuwei.dish.match.entity.CookFoodEntity
|
||||
import com.shuwei.dish.match.entity.CookFoodGoodsEntity
|
||||
import com.shuwei.dish.match.entity.SeasoningEntity
|
||||
import com.shuwei.dish.match.entity.SeasoningSlotEntity
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
|
||||
class AppRepository(val appDao: AppDao, val seasoningSlotDao: SeasoningSlotDao) {
|
||||
class DbRepository {
|
||||
|
||||
private val db = BaseApp.instance!!.database
|
||||
|
||||
suspend fun insertCookFood(item: CookFoodEntity) = withContext(Dispatchers.IO) {
|
||||
appDao.insertCookFood(item)
|
||||
db.cookFoodDao().insertCookFood(item)
|
||||
}
|
||||
|
||||
suspend fun updateCookFood(item: CookFoodEntity) = withContext(Dispatchers.IO) {
|
||||
appDao.updateCookFood(item)
|
||||
db.cookFoodDao().updateCookFood(item)
|
||||
}
|
||||
|
||||
suspend fun getCookFoodById(foodId: String, cookMode: Int) = withContext(Dispatchers.IO) {
|
||||
appDao.getCookFoodById(BaseApp.canteenId, foodId, cookMode)
|
||||
db.cookFoodDao().getCookFoodById(BaseApp.canteenId, foodId, cookMode)
|
||||
}
|
||||
|
||||
suspend fun getCookFoodList(cookMode: Int, dinnerType: String) = withContext(Dispatchers.IO) {
|
||||
appDao.getCookFoodList(BaseApp.canteenId, cookMode, dinnerType)
|
||||
db.cookFoodDao().getCookFoodList(BaseApp.canteenId, cookMode, dinnerType)
|
||||
}
|
||||
|
||||
suspend fun countCookFood(cookMode: Int) = withContext(Dispatchers.IO) {
|
||||
appDao.countCookFood(BaseApp.canteenId, cookMode)
|
||||
db.cookFoodDao().countCookFood(BaseApp.canteenId, cookMode)
|
||||
}
|
||||
|
||||
suspend fun deleteCookFood(foodId: String, cookMode: Int) = withContext(Dispatchers.IO) {
|
||||
appDao.deleteCookFood(BaseApp.canteenId, foodId, cookMode)
|
||||
db.cookFoodDao().deleteCookFood(BaseApp.canteenId, foodId, cookMode)
|
||||
}
|
||||
|
||||
suspend fun deleteCookFoodGoodsList(pid:Long, foodId: String) = withContext(Dispatchers.IO) {
|
||||
appDao.deleteCookFoodGoodsList(pid, foodId)
|
||||
suspend fun deleteCookFoodGoodsList(pid: Long, foodId: String) = withContext(Dispatchers.IO) {
|
||||
db.cookFoodGoodsDao().deleteCookFoodGoodsList(pid, foodId)
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------
|
||||
|
||||
// suspend fun insertGoods(item: CookFoodGoodsEntity) = withContext(Dispatchers.IO) {
|
||||
// appDao.insertGoods(item)
|
||||
// }
|
||||
|
||||
suspend fun insertGoodsList(items: MutableList<CookFoodGoodsEntity>) =
|
||||
withContext(Dispatchers.IO) {
|
||||
appDao.insertGoodsList(items)
|
||||
db.cookFoodGoodsDao().insertGoodsList(items)
|
||||
}
|
||||
|
||||
// suspend fun updateGoods(item: CookFoodGoodsEntity) = withContext(Dispatchers.IO) {
|
||||
// appDao.updateGoods(item)
|
||||
// }
|
||||
|
||||
suspend fun getCookFoodGoodsList(pid:Long, foodId: String) = withContext(Dispatchers.IO) {
|
||||
appDao.getCookFoodGoodsList(pid, foodId)
|
||||
suspend fun getCookFoodGoodsList(pid: Long, foodId: String) = withContext(Dispatchers.IO) {
|
||||
db.cookFoodGoodsDao().getCookFoodGoodsList(pid, foodId)
|
||||
}
|
||||
|
||||
suspend fun getCookFoodGoodsListByType(
|
||||
foodId: String,
|
||||
materialType: Int
|
||||
) = withContext(Dispatchers.IO) {
|
||||
appDao.getCookFoodGoodsListByType(foodId, materialType)
|
||||
db.cookFoodGoodsDao().getCookFoodGoodsListByType(foodId, materialType)
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------
|
||||
|
||||
suspend fun getSeasoningById(id: Long) = withContext(Dispatchers.IO) {
|
||||
appDao.getSeasoningById(id)
|
||||
db.seasoningDao().getSeasoningById(id)
|
||||
}
|
||||
|
||||
suspend fun getSeasoningBySort(sort:Int) = withContext(Dispatchers.IO) {
|
||||
appDao.getSeasoningBySort(sort)
|
||||
suspend fun getSeasoningBySort(sort: Int) = withContext(Dispatchers.IO) {
|
||||
db.seasoningDao().getSeasoningBySort(sort)
|
||||
}
|
||||
|
||||
suspend fun getSeasoningByGoodsId(goodsId: Int) = withContext(Dispatchers.IO) {
|
||||
appDao.getSeasoningByGoodsId(goodsId)
|
||||
db.seasoningDao().getSeasoningByGoodsId(goodsId)
|
||||
}
|
||||
|
||||
suspend fun getAllStream() = withContext(Dispatchers.IO) {
|
||||
appDao.getAllStream()
|
||||
db.seasoningDao().getAllStream()
|
||||
}
|
||||
|
||||
suspend fun search(query: String) = withContext(Dispatchers.IO) {
|
||||
appDao.search(query)
|
||||
db.seasoningDao().search(query)
|
||||
}
|
||||
|
||||
suspend fun clearAllSeasoning() = withContext(Dispatchers.IO) {
|
||||
appDao.clearAllSeasoning()
|
||||
db.seasoningDao().clearAllSeasoning()
|
||||
}
|
||||
|
||||
suspend fun deleteSeasoningBySort(sort: Int) = withContext(Dispatchers.IO) {
|
||||
appDao.deleteSeasoningBySort(sort)
|
||||
db.seasoningDao().deleteSeasoningBySort(sort)
|
||||
}
|
||||
|
||||
suspend fun insertSeasoningList(items: MutableList<SeasoningEntity>) =
|
||||
withContext(Dispatchers.IO) {
|
||||
appDao.insertSeasoningList(items)
|
||||
db.seasoningDao().insertSeasoningList(items)
|
||||
}
|
||||
|
||||
suspend fun updateSeasoning(item: SeasoningEntity) = withContext(Dispatchers.IO) {
|
||||
appDao.updateSeasoning(item)
|
||||
db.seasoningDao().updateSeasoning(item)
|
||||
}
|
||||
|
||||
suspend fun insertSeasoning(item: SeasoningEntity) = withContext(Dispatchers.IO) {
|
||||
appDao.insertSeasoning(item)
|
||||
db.seasoningDao().insertSeasoning(item)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,7 +106,36 @@ class AppRepository(val appDao: AppDao, val seasoningSlotDao: SeasoningSlotDao)
|
||||
* @return true 表示已有配置,false 表示未配置
|
||||
*/
|
||||
suspend fun hasSeasoningSlotConfig(deviceId: String) = withContext(Dispatchers.IO) {
|
||||
seasoningSlotDao.queryByDeviceId(deviceId).isNotEmpty()
|
||||
db.seasoningSlotDao().queryByDeviceId(deviceId).isNotEmpty()
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有设备的调料槽位配置
|
||||
*/
|
||||
suspend fun getAllSeasoningSlots() = withContext(Dispatchers.IO) {
|
||||
db.seasoningSlotDao().queryAll()
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询指定设备的调料槽位配置
|
||||
* @param deviceId 目标设备 ID
|
||||
*/
|
||||
suspend fun getSeasoningSlotsByDeviceId(deviceId: String) = withContext(Dispatchers.IO) {
|
||||
db.seasoningSlotDao().queryByDeviceId(deviceId)
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入或更新单个调料槽位配置
|
||||
*/
|
||||
suspend fun upsertSeasoningSlot(slot: SeasoningSlotEntity) = withContext(Dispatchers.IO) {
|
||||
db.seasoningSlotDao().upsert(slot)
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量插入或更新调料槽位配置
|
||||
*/
|
||||
suspend fun upsertAllSeasoningSlots(slots: List<SeasoningSlotEntity>) = withContext(Dispatchers.IO) {
|
||||
db.seasoningSlotDao().upsertAll(slots)
|
||||
}
|
||||
}
|
||||
//
|
||||
@@ -0,0 +1,290 @@
|
||||
package com.shuwei.dish.match.db
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.shuwei.dish.match.entity.CollectedFoodItem
|
||||
import com.shuwei.dish.match.entity.CookFoodEntity
|
||||
import com.shuwei.dish.match.objbox.ObjectBox
|
||||
import com.shuwei.dish.match.entity.CookFoodGoodsEntity
|
||||
import com.shuwei.dish.match.entity.SeasoningEntity
|
||||
import com.shuwei.dish.match.entity.SeasoningSlotEntity
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
|
||||
class DbViewModel : ViewModel() {
|
||||
|
||||
private val rep = DbRepository()
|
||||
|
||||
fun updateCookFood(entity: CookFoodEntity) {
|
||||
viewModelScope.launch {
|
||||
rep.updateCookFood(entity)
|
||||
}
|
||||
}
|
||||
|
||||
private val _cookFoodDetailState = MutableStateFlow<CookFoodEntity?>(null)
|
||||
val cookFoodDetailState: StateFlow<CookFoodEntity?> = _cookFoodDetailState.asStateFlow()
|
||||
|
||||
fun getCookFoodById(foodId: String, cookMode: Int) {
|
||||
viewModelScope.launch {
|
||||
_cookFoodDetailState.value = rep.getCookFoodById(foodId, cookMode)
|
||||
}
|
||||
}
|
||||
|
||||
private val _cookFoodListState = MutableStateFlow<MutableList<CookFoodEntity>?>(null)
|
||||
val cookFoodListState: StateFlow<MutableList<CookFoodEntity>?> = _cookFoodListState.asStateFlow()
|
||||
fun resetCookFoodList() {
|
||||
_cookFoodListState.value = null
|
||||
}
|
||||
fun getCookFoodList(
|
||||
cookMode: Int,
|
||||
dinnerType: String = "0"
|
||||
) {
|
||||
viewModelScope.launch {
|
||||
_cookFoodListState.value = rep.getCookFoodList(cookMode, dinnerType)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun countCookFood(cookMode: Int): Int {
|
||||
return rep.countCookFood(cookMode)
|
||||
}
|
||||
|
||||
// fun saveCookFood(cookMode: Int, entity: CookFoodEntity) {
|
||||
// viewModelScope.launch {
|
||||
// val data = rep.getCookFoodById(entity.foodId, cookMode)
|
||||
// if (data == null) {
|
||||
// rep.insertCookFood(entity)
|
||||
// return@launch
|
||||
// }
|
||||
// rep.updateCookFood(entity)
|
||||
// }
|
||||
// }
|
||||
|
||||
suspend fun saveCookFoodAndGoods(
|
||||
cookMode: Int,
|
||||
entity: CookFoodEntity,
|
||||
list: MutableList<CookFoodGoodsEntity>?
|
||||
) {
|
||||
val data = rep.getCookFoodById(entity.foodId, cookMode)
|
||||
if (data != null) {
|
||||
// 存在数据先删除
|
||||
rep.deleteCookFood(entity.foodId, cookMode)
|
||||
rep.deleteCookFoodGoodsList(data.id, entity.foodId)
|
||||
}
|
||||
// 重新保存数据
|
||||
rep.insertCookFood(entity)
|
||||
val newData = rep.getCookFoodById(entity.foodId, cookMode)
|
||||
list?.let { it ->
|
||||
it.forEach { goods ->
|
||||
goods.id = 0
|
||||
goods.pid = newData?.id ?: 0
|
||||
}
|
||||
rep.insertGoodsList(it)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun deleteCookFoodAndGoods(cookMode: Int, foodId: String) {
|
||||
val data = rep.getCookFoodById(foodId, cookMode)
|
||||
if (data != null) {
|
||||
rep.deleteCookFood(foodId = foodId, cookMode = cookMode)
|
||||
rep.deleteCookFoodGoodsList(pid = data.id, foodId = foodId)
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
suspend fun getCookFoodGoodsList(
|
||||
foodId: String,
|
||||
cookMode: Int
|
||||
): MutableList<CookFoodGoodsEntity> {
|
||||
val cookFood = rep.getCookFoodById(foodId, cookMode)
|
||||
return if (cookFood != null) rep.getCookFoodGoodsList(pid = cookFood.id, foodId = cookFood.foodId)
|
||||
else mutableListOf()
|
||||
}
|
||||
|
||||
// fun updateGoods(entity: CookFoodGoodsEntity) {
|
||||
// viewModelScope.launch {
|
||||
// rep.updateGoods(entity)
|
||||
// }
|
||||
// }
|
||||
|
||||
// fun saveCookFoodGoods(list: MutableList<CookFoodGoodsEntity>) {
|
||||
// viewModelScope.launch {
|
||||
// val foodId = list[0].foodId
|
||||
// val data: MutableList<CookFoodGoodsEntity>? =
|
||||
// rep.getCookFoodGoodsList(foodId!!)
|
||||
// if (data.isNullOrEmpty()) {
|
||||
// rep.insertGoodsList(list)
|
||||
// return@launch
|
||||
// }
|
||||
// val localDbSeasoningList = rep.getCookFoodGoodsListByType(foodId, 3)
|
||||
// localDbSeasoningList.forEach {
|
||||
// it.isDel = 1
|
||||
// //更新本地调料数据为已删除的状态
|
||||
// rep.updateGoods(it)
|
||||
// }
|
||||
// //筛选出调料数据保存,主辅材不会变更不需要再次处理
|
||||
// val saveSeasoningList = list.filter { it.materialType == 3 }
|
||||
// rep.insertGoodsList(saveSeasoningList.toMutableList())
|
||||
// }
|
||||
// }
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
// fun addSeasoning(list: MutableList<SeasoningEntity>, callback: () -> Unit) {
|
||||
// viewModelScope.launch {
|
||||
// rep.deleteBatch()
|
||||
// rep.insertSeasoningList(items = list)
|
||||
// callback()
|
||||
// }
|
||||
// }
|
||||
|
||||
private val loadSeasoningMutex = Mutex()
|
||||
|
||||
/**
|
||||
* 本地调料列表状态流
|
||||
*/
|
||||
private val _seasoningState = MutableStateFlow<MutableList<SeasoningEntity>>(mutableListOf())
|
||||
val seasoningState: StateFlow<MutableList<SeasoningEntity>> = _seasoningState.asStateFlow()
|
||||
|
||||
fun loadSeasoning() {
|
||||
if (loadSeasoningMutex.isLocked) return
|
||||
viewModelScope.launch {
|
||||
loadSeasoningMutex.withLock {
|
||||
_seasoningState.value = rep.getAllStream()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 所有设备调料槽位配置的 UI 状态流
|
||||
*/
|
||||
private val _seasoningSlotState = MutableStateFlow<List<SeasoningSlotEntity>>(emptyList())
|
||||
val seasoningSlotState: StateFlow<List<SeasoningSlotEntity>> = _seasoningSlotState.asStateFlow()
|
||||
|
||||
/**
|
||||
* 查询所有调料槽位配置,更新 seasoningSlotState 并返回结果
|
||||
* 声明为 suspend,调用方可在同一协程中直接使用返回值,无需等待 StateFlow 更新
|
||||
*/
|
||||
suspend fun loadSeasoningSlot(): List<SeasoningSlotEntity> {
|
||||
val slots = rep.getAllSeasoningSlots()
|
||||
_seasoningSlotState.value = slots
|
||||
return slots
|
||||
}
|
||||
|
||||
fun deleteSeasoningBySort(sort: Int) {
|
||||
viewModelScope.launch {
|
||||
rep.deleteSeasoningBySort(sort)
|
||||
}
|
||||
}
|
||||
|
||||
private val _clearAllSeasoningState = MutableStateFlow(false)
|
||||
val clearAllSeasoningState: StateFlow<Boolean> = _clearAllSeasoningState.asStateFlow()
|
||||
|
||||
fun clearAllSeasoning() {
|
||||
viewModelScope.launch {
|
||||
rep.clearAllSeasoning()
|
||||
_clearAllSeasoningState.value = true
|
||||
}
|
||||
}
|
||||
|
||||
private val _hasSeasoningSlotConfigState = MutableStateFlow(false)
|
||||
val hasSeasoningSlotConfigState: StateFlow<Boolean> = _hasSeasoningSlotConfigState.asStateFlow()
|
||||
|
||||
/**
|
||||
* 查询指定设备是否已配置调料槽位
|
||||
* @param deviceId 目标设备 ID
|
||||
*/
|
||||
fun hasSeasoningSlotConfig(deviceId: String) {
|
||||
viewModelScope.launch {
|
||||
_hasSeasoningSlotConfigState.value = rep.hasSeasoningSlotConfig(deviceId)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询指定设备的调料槽位配置
|
||||
*/
|
||||
suspend fun getSeasoningSlotsByDeviceId(deviceId: String) =
|
||||
rep.getSeasoningSlotsByDeviceId(deviceId)
|
||||
|
||||
/**
|
||||
* 插入或更新单个调料槽位配置
|
||||
*/
|
||||
suspend fun upsertSeasoningSlot(slot: SeasoningSlotEntity) =
|
||||
rep.upsertSeasoningSlot(slot)
|
||||
|
||||
/**
|
||||
* 批量插入或更新调料槽位配置
|
||||
*/
|
||||
suspend fun upsertAllSeasoningSlots(slots: List<SeasoningSlotEntity>) =
|
||||
rep.upsertAllSeasoningSlots(slots)
|
||||
|
||||
// fun updateAll(list: MutableList<SeasoningEntity>) {
|
||||
// viewModelScope.launch {
|
||||
// list.forEach {
|
||||
// rep.updateSeasoning(it)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
fun saveSeasoning(entity: SeasoningEntity, block: () -> Unit) {
|
||||
viewModelScope.launch {
|
||||
val list = rep.getSeasoningBySort(entity.sort)
|
||||
val size = list?.size?:0
|
||||
if (size == 1) {
|
||||
rep.updateSeasoning(entity.also { it.id = list!![0].id })
|
||||
block()
|
||||
return@launch
|
||||
}
|
||||
if (size > 1) {
|
||||
list?.forEach {
|
||||
rep.deleteSeasoningBySort(it.sort)
|
||||
}
|
||||
}
|
||||
entity.id = 0
|
||||
val id = rep.insertSeasoning(entity)
|
||||
entity.id = id
|
||||
block()
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 已采集食材列表 UI 状态流
|
||||
* 元素为按名称分组后的(名称,数量)数据
|
||||
*/
|
||||
private val _collectedFoodListState = MutableStateFlow<List<CollectedFoodItem>>(emptyList())
|
||||
val collectedFoodListState: StateFlow<List<CollectedFoodItem>> = _collectedFoodListState.asStateFlow()
|
||||
|
||||
/**
|
||||
* 加载已采集食材列表,按名称分组统计数量
|
||||
* 使用属性查询只读 name 字段,不加载 foodVector,节省内存
|
||||
* @param nameFilter 名称过滤关键词,为空时加载全部
|
||||
*/
|
||||
fun loadCollectedFoodList(nameFilter: String? = null) {
|
||||
viewModelScope.launch {
|
||||
val result = ObjectBox.queryFoodNameCounts(nameFilter)
|
||||
_collectedFoodListState.value = result.map { (name, count) ->
|
||||
CollectedFoodItem(foodName = name, collectCount = count)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定名称的所有采集记录,删除完成后刷新列表
|
||||
* @param foodName 食材名称
|
||||
* @param nameFilter 当前搜索关键词,用于删除后刷新列表
|
||||
*/
|
||||
fun removeCollectedFood(foodName: String, nameFilter: String? = null) {
|
||||
viewModelScope.launch {
|
||||
ObjectBox.remove(foodName)
|
||||
loadCollectedFoodList(nameFilter)
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
package com.shuwei.dish.match.db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
import com.shuwei.dish.match.entity.CookFoodEntity
|
||||
import com.shuwei.dish.match.entity.CookFoodGoodsEntity
|
||||
import com.shuwei.dish.match.entity.SeasoningEntity
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface AppDao {
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertCookFood(item: CookFoodEntity): Long
|
||||
|
||||
@Update
|
||||
suspend fun updateCookFood(item: CookFoodEntity)
|
||||
|
||||
@Query("SELECT * FROM dm_cook_food WHERE isDel = 0 AND canteenId = :canteenId AND foodId = :foodId AND cookMode = :cookMode")
|
||||
suspend fun getCookFoodById(canteenId:String, foodId: String, cookMode: Int): CookFoodEntity?
|
||||
|
||||
@Query("SELECT * FROM dm_cook_food WHERE isDel = 0 AND canteenId = :canteenId AND cookMode = :cookMode AND dinnerType = :dinnerType ORDER BY createTime DESC")
|
||||
suspend fun getCookFoodList(canteenId:String, cookMode: Int, dinnerType:String): MutableList<CookFoodEntity>?
|
||||
|
||||
@Query("SELECT count(1) FROM dm_cook_food WHERE isDel = 0 AND canteenId = :canteenId AND cookMode = :cookMode")
|
||||
suspend fun countCookFood(canteenId:String, cookMode: Int): Int
|
||||
|
||||
@Query("DELETE FROM dm_cook_food WHERE canteenId = :canteenId AND foodId = :foodId AND cookMode = :cookMode")
|
||||
suspend fun deleteCookFood(canteenId:String, foodId: String, cookMode: Int)
|
||||
|
||||
//--------------------------------------------------------------------------------------------
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertGoods(item: CookFoodGoodsEntity): Long
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertGoodsList(items: MutableList<CookFoodGoodsEntity>): Array<Long>
|
||||
|
||||
@Update
|
||||
suspend fun updateGoods(item: CookFoodGoodsEntity)
|
||||
|
||||
@Query("SELECT * FROM dm_cook_food_goods WHERE isDel = 0 AND pid = :pid AND foodId = :foodId")
|
||||
suspend fun getCookFoodGoodsList(pid:Long, foodId: String): MutableList<CookFoodGoodsEntity>
|
||||
|
||||
@Query("SELECT * FROM dm_cook_food_goods WHERE isDel = 0 AND foodId = :foodId AND materialType = :materialType")
|
||||
suspend fun getCookFoodGoodsListByType(
|
||||
foodId: String,
|
||||
materialType: Int
|
||||
): MutableList<CookFoodGoodsEntity>
|
||||
|
||||
@Query("DELETE FROM dm_cook_food_goods WHERE pid = :pid AND foodId = :foodId")
|
||||
suspend fun deleteCookFoodGoodsList(pid:Long, foodId: String)
|
||||
|
||||
//--------------------------------------------------------------------------------------------
|
||||
|
||||
@Query("SELECT * FROM dm_seasoning WHERE isDel = 0 AND id = :id")
|
||||
suspend fun getSeasoningById(id: Long): SeasoningEntity?
|
||||
|
||||
@Query("SELECT * FROM dm_seasoning WHERE isDel = 0 AND sort = :sort")
|
||||
suspend fun getSeasoningBySort(sort: Int): MutableList<SeasoningEntity>?
|
||||
|
||||
@Query("SELECT * FROM dm_seasoning WHERE isDel = 0 AND goodsId = :goodsId")
|
||||
suspend fun getSeasoningByGoodsId(goodsId: Int): SeasoningEntity?
|
||||
|
||||
// @Query("SELECT * FROM dm_seasoning WHERE isDel = 0 AND goodsId != -1 AND goodsName != '' ORDER BY sort ASC")
|
||||
// fun getAllStream(): Flow<MutableList<SeasoningEntity>>
|
||||
|
||||
@Query("SELECT * FROM dm_seasoning WHERE isDel = 0 AND goodsId != -1 AND goodsName != '' ORDER BY sort ASC")
|
||||
fun getAllStream(): MutableList<SeasoningEntity>
|
||||
|
||||
@Query("SELECT * FROM dm_seasoning WHERE isDel = 0 AND goodsName LIKE '%' || :query || '%'")
|
||||
suspend fun search(query: String): MutableList<SeasoningEntity>
|
||||
|
||||
@Query("DELETE FROM dm_seasoning WHERE isDel = 0 AND sort = :sort")
|
||||
suspend fun deleteSeasoningBySort(sort:Int): Int
|
||||
|
||||
@Query("DELETE FROM dm_seasoning WHERE isDel = 0")
|
||||
suspend fun clearAllSeasoning(): Int
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertSeasoningList(items: MutableList<SeasoningEntity>): Array<Long>
|
||||
|
||||
@Update
|
||||
suspend fun updateSeasoning(item: SeasoningEntity)
|
||||
|
||||
@Insert
|
||||
suspend fun insertSeasoning(item: SeasoningEntity): Long
|
||||
//--------------------------------------------------------------------------------------------
|
||||
}
|
||||
@@ -1,20 +1,30 @@
|
||||
//package com.shuwei.dish.match.db.dao
|
||||
//
|
||||
//import androidx.room.Dao
|
||||
//import androidx.room.Query
|
||||
//import com.shuwei.dish.match.db.BaseDao
|
||||
//import com.shuwei.dish.match.entity.CookFoodEntity
|
||||
//
|
||||
//@Dao
|
||||
//interface CookFoodDao : BaseDao<CookFoodEntity> {
|
||||
//
|
||||
// @Query("SELECT * FROM dm_cook_food WHERE isDel = 0 AND foodId = :foodId AND cookMode = :cookMode")
|
||||
// suspend fun getCookFoodById(foodId: String, cookMode:Int): CookFoodEntity?
|
||||
//
|
||||
// @Query("SELECT * FROM dm_cook_food WHERE isDel = 0 AND cookMode = :cookMode")
|
||||
// suspend fun getCookFoodList(cookMode:Int): MutableList<CookFoodEntity>?
|
||||
//
|
||||
// @Query("SELECT count(1) FROM dm_cook_food WHERE isDel = 0 AND cookMode = :cookMode")
|
||||
// suspend fun countCookFood(cookMode:Int): Int
|
||||
//
|
||||
//}
|
||||
package com.shuwei.dish.match.db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
import com.shuwei.dish.match.entity.CookFoodEntity
|
||||
|
||||
@Dao
|
||||
interface CookFoodDao {
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertCookFood(item: CookFoodEntity): Long
|
||||
|
||||
@Update
|
||||
suspend fun updateCookFood(item: CookFoodEntity)
|
||||
|
||||
@Query("SELECT * FROM dm_cook_food WHERE isDel = 0 AND canteenId = :canteenId AND foodId = :foodId AND cookMode = :cookMode")
|
||||
suspend fun getCookFoodById(canteenId: String, foodId: String, cookMode: Int): CookFoodEntity?
|
||||
|
||||
@Query("SELECT * FROM dm_cook_food WHERE isDel = 0 AND canteenId = :canteenId AND cookMode = :cookMode AND dinnerType = :dinnerType ORDER BY createTime DESC")
|
||||
suspend fun getCookFoodList(canteenId: String, cookMode: Int, dinnerType: String): MutableList<CookFoodEntity>?
|
||||
|
||||
@Query("SELECT count(1) FROM dm_cook_food WHERE isDel = 0 AND canteenId = :canteenId AND cookMode = :cookMode")
|
||||
suspend fun countCookFood(canteenId: String, cookMode: Int): Int
|
||||
|
||||
@Query("DELETE FROM dm_cook_food WHERE canteenId = :canteenId AND foodId = :foodId AND cookMode = :cookMode")
|
||||
suspend fun deleteCookFood(canteenId: String, foodId: String, cookMode: Int)
|
||||
}
|
||||
|
||||
@@ -1,29 +1,30 @@
|
||||
//package com.shuwei.dish.match.db.dao
|
||||
//
|
||||
//import androidx.room.Dao
|
||||
//import androidx.room.Query
|
||||
//import com.shuwei.dish.match.db.BaseDao
|
||||
//import com.shuwei.dish.match.entity.CookFoodGoodsEntity
|
||||
//
|
||||
//@Dao
|
||||
//interface CookFoodGoodsDao : BaseDao<CookFoodGoodsEntity> {
|
||||
//
|
||||
// @Query("SELECT * FROM dm_cook_food_goods WHERE isDel = 0 AND foodId = :foodId")
|
||||
// suspend fun getCookFoodGoodsList(foodId: String): MutableList<CookFoodGoodsEntity>
|
||||
//
|
||||
// @Query("SELECT * FROM dm_cook_food_goods WHERE isDel = 0 AND foodId = :foodId AND materialType = :materialType")
|
||||
// suspend fun getCookFoodGoodsListByType(foodId: String, materialType:Int): MutableList<CookFoodGoodsEntity>
|
||||
//
|
||||
//// @Query(
|
||||
//// """
|
||||
//// UPDATE dm_cook_food_goods
|
||||
//// SET goodsName=:entity.goodsName, foodId=:entity.foodId, relateionType=:entity.relateionType, sort=:entity.sort
|
||||
//// allEdible=:entity.allEdible, useWeight=:entity.useWeight, isDel=:entity.isDel, createTime=:entity.createTime
|
||||
//// WHERE isDel = 0
|
||||
//// AND foodId=:entity.foodId
|
||||
//// AND goodsId=:goodsId
|
||||
//// """
|
||||
//// )
|
||||
//// fun updateByGoodsId(entity: CookFoodGoodsEntity)
|
||||
//
|
||||
//}
|
||||
package com.shuwei.dish.match.db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
import com.shuwei.dish.match.entity.CookFoodGoodsEntity
|
||||
|
||||
@Dao
|
||||
interface CookFoodGoodsDao {
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertGoods(item: CookFoodGoodsEntity): Long
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertGoodsList(items: MutableList<CookFoodGoodsEntity>): Array<Long>
|
||||
|
||||
@Update
|
||||
suspend fun updateGoods(item: CookFoodGoodsEntity)
|
||||
|
||||
@Query("SELECT * FROM dm_cook_food_goods WHERE isDel = 0 AND pid = :pid AND foodId = :foodId")
|
||||
suspend fun getCookFoodGoodsList(pid: Long, foodId: String): MutableList<CookFoodGoodsEntity>
|
||||
|
||||
@Query("SELECT * FROM dm_cook_food_goods WHERE isDel = 0 AND foodId = :foodId AND materialType = :materialType")
|
||||
suspend fun getCookFoodGoodsListByType(foodId: String, materialType: Int): MutableList<CookFoodGoodsEntity>
|
||||
|
||||
@Query("DELETE FROM dm_cook_food_goods WHERE pid = :pid AND foodId = :foodId")
|
||||
suspend fun deleteCookFoodGoodsList(pid: Long, foodId: String)
|
||||
}
|
||||
|
||||
@@ -1,25 +1,42 @@
|
||||
//package com.shuwei.dish.match.db.dao
|
||||
//
|
||||
//import androidx.room.Dao
|
||||
//import androidx.room.Query
|
||||
//import com.shuwei.dish.match.db.BaseDao
|
||||
//import com.shuwei.dish.match.entity.SeasoningEntity
|
||||
//import kotlinx.coroutines.flow.Flow
|
||||
//
|
||||
//@Dao
|
||||
//interface SeasoningDao : BaseDao<SeasoningEntity> {
|
||||
//
|
||||
//// @Query("SELECT * FROM dm_seasoning WHERE isDel = 0 AND id = :id")
|
||||
//// suspend fun getSeasoningById(id: Long): SeasoningEntity?
|
||||
////
|
||||
//// @Query("SELECT * FROM dm_seasoning WHERE isDel = 0 ORDER BY sort ASC")
|
||||
//// fun getAllStream(): Flow<MutableList<SeasoningEntity>>
|
||||
////
|
||||
//// @Query("SELECT * FROM dm_seasoning WHERE isDel = 0 AND name LIKE '%' || :query || '%'")
|
||||
//// suspend fun search(query: String): MutableList<SeasoningEntity>
|
||||
////
|
||||
//// @Query("DELETE FROM dm_seasoning WHERE rowid IN " +
|
||||
//// "(SELECT rowid FROM dm_seasoning LIMIT 1000)")
|
||||
//// suspend fun deleteBatch(): Int
|
||||
//
|
||||
//}
|
||||
package com.shuwei.dish.match.db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
import com.shuwei.dish.match.entity.SeasoningEntity
|
||||
|
||||
@Dao
|
||||
interface SeasoningDao {
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertSeasoning(item: SeasoningEntity): Long
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertSeasoningList(items: MutableList<SeasoningEntity>): Array<Long>
|
||||
|
||||
@Update
|
||||
suspend fun updateSeasoning(item: SeasoningEntity)
|
||||
|
||||
@Query("SELECT * FROM dm_seasoning WHERE isDel = 0 AND id = :id")
|
||||
suspend fun getSeasoningById(id: Long): SeasoningEntity?
|
||||
|
||||
@Query("SELECT * FROM dm_seasoning WHERE isDel = 0 AND sort = :sort")
|
||||
suspend fun getSeasoningBySort(sort: Int): MutableList<SeasoningEntity>?
|
||||
|
||||
@Query("SELECT * FROM dm_seasoning WHERE isDel = 0 AND goodsId = :goodsId")
|
||||
suspend fun getSeasoningByGoodsId(goodsId: Int): SeasoningEntity?
|
||||
|
||||
@Query("SELECT * FROM dm_seasoning WHERE isDel = 0 AND goodsId != -1 AND goodsName != '' ORDER BY sort ASC")
|
||||
fun getAllStream(): MutableList<SeasoningEntity>
|
||||
|
||||
@Query("SELECT * FROM dm_seasoning WHERE isDel = 0 AND goodsName LIKE '%' || :query || '%'")
|
||||
suspend fun search(query: String): MutableList<SeasoningEntity>
|
||||
|
||||
@Query("DELETE FROM dm_seasoning WHERE isDel = 0 AND sort = :sort")
|
||||
suspend fun deleteSeasoningBySort(sort: Int): Int
|
||||
|
||||
@Query("DELETE FROM dm_seasoning WHERE isDel = 0")
|
||||
suspend fun clearAllSeasoning(): Int
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ open class CommonDialog(
|
||||
private lateinit var binding: DialogCommonBinding
|
||||
|
||||
private var titleText: String? = null
|
||||
private var contentText: String? = null
|
||||
private var contentText: CharSequence? = null
|
||||
private var negativeText = "取消"
|
||||
private var positiveText = "确认"
|
||||
private var neutralText: String? = null
|
||||
@@ -36,7 +36,7 @@ open class CommonDialog(
|
||||
fun setTitle(text: String): CommonDialog = apply { titleText = text }
|
||||
|
||||
/** 设置内容,为空时隐藏 */
|
||||
fun setContent(text: String): CommonDialog = apply { contentText = text }
|
||||
fun setContent(text: CharSequence): CommonDialog = apply { contentText = text }
|
||||
|
||||
/** 设置左侧取消按钮文字及点击回调(3按钮模式下对应顶部按钮) */
|
||||
fun setNegativeButton(text: String, onClick: (() -> Unit)? = null): CommonDialog = apply {
|
||||
|
||||
@@ -8,6 +8,9 @@ import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import androidx.core.view.isEmpty
|
||||
import androidx.core.widget.addTextChangedListener
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
@@ -17,9 +20,12 @@ import com.shuwei.dish.match.base.BaseActivity
|
||||
import com.shuwei.dish.match.base.BaseApp
|
||||
import com.shuwei.dish.match.databinding.DialogFoodSearchBinding
|
||||
import com.shuwei.dish.match.entity.CookFoodGoodsEntity
|
||||
import com.shuwei.dish.match.net.UiState
|
||||
import com.shuwei.dish.match.utils.KeyboardUtil
|
||||
import com.shuwei.dish.match.utils.ext.addOnActionSearchListener
|
||||
import com.shuwei.dish.match.utils.ext.toast
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* 食材搜索弹窗,继承 BottomSheetDialog 确保只初始化一次
|
||||
@@ -95,7 +101,9 @@ class FoodSearchDialog(
|
||||
}
|
||||
|
||||
binding.ivSearch.setOnClickListener { searchGoods(it) }
|
||||
binding.root.setOnClickListener { KeyboardUtil.hideKeyboard(it.context, it) }
|
||||
binding.root.setOnClickListener { KeyboardUtil.hideKeyboard(it) }
|
||||
|
||||
initObserver()
|
||||
|
||||
// 若有默认食材名称,自动填充并触发搜索
|
||||
if (!defGoodsName.isNullOrBlank()) {
|
||||
@@ -104,6 +112,26 @@ class FoodSearchDialog(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 收集 goodsListState,统一处理 Loading / Success / Error 状态
|
||||
*/
|
||||
private fun initObserver() {
|
||||
activity.lifecycleScope.launch {
|
||||
activity.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
activity.netViewModel.goodsListState.collect { state ->
|
||||
when (state) {
|
||||
is UiState.Success -> loadGoodsList(state.data)
|
||||
is UiState.Error -> {
|
||||
activity.toast(state.msg)
|
||||
finishRefresh()
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发搜索:校验输入、隐藏键盘、发起请求
|
||||
*/
|
||||
@@ -114,7 +142,7 @@ class FoodSearchDialog(
|
||||
}
|
||||
pageNo = 1
|
||||
getGoodsList()
|
||||
KeyboardUtil.hideKeyboard(v.context, v)
|
||||
KeyboardUtil.hideKeyboard(v)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,12 +158,7 @@ class FoodSearchDialog(
|
||||
if (!goodsName.isNullOrBlank()) {
|
||||
param["goodsName"] = goodsName!!
|
||||
}
|
||||
activity.queryGoodsList(param = param, onSuccess = {
|
||||
loadGoodsList(it)
|
||||
}, onFailure = { _, msg ->
|
||||
activity.toast(msg)
|
||||
finishRefresh()
|
||||
})
|
||||
activity.netViewModel.queryGoodsList(param)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,6 +18,9 @@ import android.view.WindowManager
|
||||
import androidx.core.graphics.toColorInt
|
||||
import androidx.core.view.isEmpty
|
||||
import androidx.core.widget.addTextChangedListener
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
@@ -27,6 +30,7 @@ import com.shuwei.dish.match.base.BaseActivity
|
||||
import com.shuwei.dish.match.base.BaseApp
|
||||
import com.shuwei.dish.match.databinding.DialogSeasoningSearchBinding
|
||||
import com.shuwei.dish.match.entity.SeasoningEntity
|
||||
import com.shuwei.dish.match.net.UiState
|
||||
import com.shuwei.dish.match.utils.KeyboardUtil
|
||||
import com.shuwei.dish.match.utils.WeightUtil
|
||||
import com.shuwei.dish.match.utils.ext.addOnActionSearchListener
|
||||
@@ -35,6 +39,7 @@ import com.shuwei.dish.match.utils.ext.buildSpannableString
|
||||
import com.shuwei.dish.match.utils.ext.dp
|
||||
import com.shuwei.dish.match.utils.ext.roundedDecimalPlace
|
||||
import com.shuwei.dish.match.utils.ext.toast
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* 调料搜索弹窗,继承 BottomSheetDialog 确保只初始化一次
|
||||
@@ -106,10 +111,10 @@ class SeasoningSearchDialog(
|
||||
}
|
||||
|
||||
// RecyclerView 初始化及滑动冲突处理
|
||||
binding.recyclerView.run {
|
||||
layoutManager = GridLayoutManager(activity, 2, GridLayoutManager.VERTICAL, false)
|
||||
adapter = this@SeasoningSearchDialog.adapter
|
||||
addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
binding.recyclerView.let {
|
||||
it.layoutManager = GridLayoutManager(activity, 2, GridLayoutManager.VERTICAL, false)
|
||||
it.adapter = adapter
|
||||
it.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(rv: RecyclerView, dx: Int, dy: Int) {
|
||||
super.onScrolled(rv, dx, dy)
|
||||
// 解决 RecyclerView 与 SmartRefreshLayout 滑动冲突
|
||||
@@ -127,7 +132,7 @@ class SeasoningSearchDialog(
|
||||
}
|
||||
|
||||
binding.ivSearch.setOnClickListener { searchGoods(it) }
|
||||
binding.root.setOnClickListener { KeyboardUtil.hideKeyboard(it.context, it) }
|
||||
binding.root.setOnClickListener { KeyboardUtil.hideKeyboard(it) }
|
||||
|
||||
// 去皮按钮
|
||||
binding.tvClear.setOnClickListener {
|
||||
@@ -147,6 +152,8 @@ class SeasoningSearchDialog(
|
||||
)
|
||||
binding.tvWeight.text = getTextSpan(0.0)
|
||||
|
||||
initObserver()
|
||||
|
||||
// 若有默认调料名称,自动填充并触发搜索
|
||||
if (!clickName.isNullOrBlank()) {
|
||||
binding.etSheetInput.setText(clickName.trim())
|
||||
@@ -155,6 +162,26 @@ class SeasoningSearchDialog(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 收集 seasoningListState,统一处理 Loading / Success / Error 状态
|
||||
*/
|
||||
private fun initObserver() {
|
||||
activity.lifecycleScope.launch {
|
||||
activity.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
activity.netViewModel.seasoningListState.collect { state ->
|
||||
when (state) {
|
||||
is UiState.Success -> loadGoodsList(state.data)
|
||||
is UiState.Error -> {
|
||||
activity.toast(state.msg)
|
||||
finishRefresh()
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发搜索:校验输入、隐藏键盘、发起请求
|
||||
*/
|
||||
@@ -165,7 +192,7 @@ class SeasoningSearchDialog(
|
||||
}
|
||||
pageNo = 1
|
||||
getGoodsList()
|
||||
KeyboardUtil.hideKeyboard(v.context, v)
|
||||
KeyboardUtil.hideKeyboard(v)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -181,12 +208,7 @@ class SeasoningSearchDialog(
|
||||
if (!goodsName.isNullOrBlank()) {
|
||||
param["goodsName"] = goodsName!!
|
||||
}
|
||||
activity.querySeasoningList(param = param, onSuccess = {
|
||||
loadGoodsList(it)
|
||||
}, onFailure = { _, msg ->
|
||||
activity.toast(msg)
|
||||
finishRefresh()
|
||||
})
|
||||
activity.netViewModel.querySeasoningList(param)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -106,7 +106,7 @@ class SeasoningSelectDialog(
|
||||
}
|
||||
|
||||
binding.ivSearch.setOnClickListener { searchGoods(it) }
|
||||
binding.root.setOnClickListener { KeyboardUtil.hideKeyboard(it.context, it) }
|
||||
binding.root.setOnClickListener { KeyboardUtil.hideKeyboard(it) }
|
||||
}
|
||||
|
||||
/** 弹窗显示时自动加载默认调料列表 */
|
||||
@@ -126,7 +126,7 @@ class SeasoningSelectDialog(
|
||||
}
|
||||
pageNo = 1
|
||||
getGoodsList()
|
||||
KeyboardUtil.hideKeyboard(v.context, v)
|
||||
KeyboardUtil.hideKeyboard( v)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.shuwei.dish.match.entity
|
||||
|
||||
/**
|
||||
* 已采集食材列表项数据模型
|
||||
* @param foodName 食材名称
|
||||
* @param collectCount 已采集数量
|
||||
*/
|
||||
data class CollectedFoodItem(
|
||||
val foodName: String = "",
|
||||
val collectCount: Int = 0
|
||||
)
|
||||
@@ -6,6 +6,9 @@ import com.shuwei.dish.match.entity.CookFoodEntity
|
||||
import com.shuwei.dish.match.entity.CookFoodGoodsEntity
|
||||
import com.shuwei.dish.match.entity.FoodRecord
|
||||
import com.shuwei.dish.match.entity.SeasoningEntity
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
@@ -16,81 +19,102 @@ class NetViewModel(
|
||||
private val repository: RemoteRepository = RemoteRepository()
|
||||
) : ViewModel() {
|
||||
|
||||
/**
|
||||
* 提交制作菜品的 UI 状态流,UI 层通过 collect 监听
|
||||
*/
|
||||
private val _submitCookFoodState = MutableStateFlow<UiState<Any?>>(UiState.Idle)
|
||||
val submitCookFoodState: StateFlow<UiState<Any?>> = _submitCookFoodState.asStateFlow()
|
||||
|
||||
/**
|
||||
* 提交制作菜品
|
||||
*/
|
||||
fun submitCookFood(
|
||||
entity: CookFoodEntity,
|
||||
onSuccess: (Any?) -> Unit,
|
||||
onFailure: (String, String) -> Unit
|
||||
) {
|
||||
fun submitCookFood(entity: CookFoodEntity) {
|
||||
viewModelScope.launch {
|
||||
repository.submitCookFood(entity, onSuccess, onFailure)
|
||||
_submitCookFoodState.value = UiState.Loading
|
||||
_submitCookFoodState.value = repository.submitCookFood(entity)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询菜品详情的 UI 状态流,UI 层通过 collect 监听
|
||||
*/
|
||||
private val _foodDetailState = MutableStateFlow<UiState<CookFoodEntity?>>(UiState.Idle)
|
||||
val foodDetailState: StateFlow<UiState<CookFoodEntity?>> = _foodDetailState.asStateFlow()
|
||||
|
||||
/**
|
||||
* 查询菜品详情
|
||||
*/
|
||||
fun getFoodDetail(
|
||||
foodId: String,
|
||||
onSuccess: (CookFoodEntity?) -> Unit,
|
||||
onFailure: (String, String) -> Unit
|
||||
) {
|
||||
fun getFoodDetail(foodId: String) {
|
||||
viewModelScope.launch {
|
||||
repository.getFoodDetail(foodId, onSuccess, onFailure)
|
||||
_foodDetailState.value = UiState.Loading
|
||||
_foodDetailState.value = repository.getFoodDetail(foodId)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索菜品列表的 UI 状态流,UI 层通过 collect 监听
|
||||
*/
|
||||
private val _searchFoodState = MutableStateFlow<UiState<MutableList<FoodRecord>?>>(UiState.Idle)
|
||||
val searchFoodState: StateFlow<UiState<MutableList<FoodRecord>?>> = _searchFoodState.asStateFlow()
|
||||
|
||||
/**
|
||||
* 搜索菜品列表
|
||||
*/
|
||||
fun searchFoodList(
|
||||
param: MutableMap<String, Any>,
|
||||
onSuccess: (MutableList<FoodRecord>?) -> Unit,
|
||||
onFailure: (String, String) -> Unit
|
||||
) {
|
||||
fun searchFoodList(param: MutableMap<String, Any>) {
|
||||
viewModelScope.launch {
|
||||
repository.searchFoodList(param, onSuccess, onFailure)
|
||||
_searchFoodState.value = UiState.Loading
|
||||
_searchFoodState.value = repository.searchFoodList(param)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询采样数据列表的 UI 状态流,UI 层通过 collect 监听
|
||||
*/
|
||||
private val _samplingListState = MutableStateFlow<UiState<MutableList<FoodRecord>?>>(UiState.Idle)
|
||||
val samplingListState: StateFlow<UiState<MutableList<FoodRecord>?>> = _samplingListState.asStateFlow()
|
||||
fun resetSamplingListState() {
|
||||
_samplingListState.value = UiState.Idle
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询采样数据列表
|
||||
*/
|
||||
fun getSamplingList(
|
||||
param: MutableMap<String, Any>,
|
||||
onSuccess: (MutableList<FoodRecord>?) -> Unit,
|
||||
onFailure: (String, String) -> Unit
|
||||
) {
|
||||
fun getSamplingList(param: MutableMap<String, Any>) {
|
||||
viewModelScope.launch {
|
||||
repository.getSamplingList(param, onSuccess, onFailure)
|
||||
_samplingListState.value = UiState.Loading
|
||||
_samplingListState.value = repository.getSamplingList(param)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询物品信息列表的 UI 状态流,UI 层通过 collect 监听
|
||||
*/
|
||||
private val _goodsListState = MutableStateFlow<UiState<MutableList<CookFoodGoodsEntity>?>>(UiState.Idle)
|
||||
val goodsListState: StateFlow<UiState<MutableList<CookFoodGoodsEntity>?>> = _goodsListState.asStateFlow()
|
||||
|
||||
/**
|
||||
* 查询物品信息列表
|
||||
*/
|
||||
fun queryGoodsList(
|
||||
param: MutableMap<String, Any>,
|
||||
onSuccess: (MutableList<CookFoodGoodsEntity>?) -> Unit,
|
||||
onFailure: (String, String) -> Unit
|
||||
) {
|
||||
fun queryGoodsList(param: MutableMap<String, Any>) {
|
||||
viewModelScope.launch {
|
||||
repository.queryGoodsList(param, onSuccess, onFailure)
|
||||
_goodsListState.value = UiState.Loading
|
||||
_goodsListState.value = repository.queryGoodsList(param)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询调料信息列表的 UI 状态流,UI 层通过 collect 监听
|
||||
*/
|
||||
private val _seasoningListState = MutableStateFlow<UiState<MutableList<SeasoningEntity>?>>(UiState.Idle)
|
||||
val seasoningListState: StateFlow<UiState<MutableList<SeasoningEntity>?>> = _seasoningListState.asStateFlow()
|
||||
|
||||
/**
|
||||
* 查询调料信息列表
|
||||
*/
|
||||
fun querySeasoningList(
|
||||
param: MutableMap<String, Any>,
|
||||
onSuccess: (MutableList<SeasoningEntity>?) -> Unit,
|
||||
onFailure: (String, String) -> Unit
|
||||
) {
|
||||
fun querySeasoningList(param: MutableMap<String, Any>) {
|
||||
viewModelScope.launch {
|
||||
repository.querySeasoningList(param, onSuccess, onFailure)
|
||||
_seasoningListState.value = UiState.Loading
|
||||
_seasoningListState.value = repository.querySeasoningList(param)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,96 +14,98 @@ class RemoteRepository {
|
||||
/**
|
||||
* 提交制作菜品
|
||||
* @param entity 菜品实体
|
||||
* @param onSuccess 成功回调
|
||||
* @param onFailure 失败回调,参数为 (errorCode, errorMsg)
|
||||
* @return UiState 包装的结果,Success 表示提交成功,Error 携带错误信息
|
||||
*/
|
||||
suspend fun submitCookFood(
|
||||
entity: CookFoodEntity,
|
||||
onSuccess: (Any?) -> Unit,
|
||||
onFailure: (String, String) -> Unit
|
||||
) = request(
|
||||
onRequest = { apiService.submitCookFood(param = entity) },
|
||||
onSuccess = onSuccess,
|
||||
onFailure = onFailure
|
||||
)
|
||||
suspend fun submitCookFood(entity: CookFoodEntity): UiState<Any?> {
|
||||
return try {
|
||||
val resp = apiService.submitCookFood(param = entity)
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询菜品详情
|
||||
* @param foodId 菜品 ID
|
||||
* @param onSuccess 成功回调
|
||||
* @param onFailure 失败回调,参数为 (errorCode, errorMsg)
|
||||
* @return UiState 包装的结果,Success 携带详情数据,Error 携带错误信息
|
||||
*/
|
||||
suspend fun getFoodDetail(
|
||||
foodId: String,
|
||||
onSuccess: (CookFoodEntity?) -> Unit,
|
||||
onFailure: (String, String) -> Unit
|
||||
) = request(
|
||||
onRequest = { apiService.getFoodDetail(foodId = foodId) },
|
||||
onSuccess = onSuccess,
|
||||
onFailure = onFailure
|
||||
)
|
||||
suspend fun getFoodDetail(foodId: String): UiState<CookFoodEntity?> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索菜品列表
|
||||
* @param param 查询参数
|
||||
* @param onSuccess 成功回调
|
||||
* @param onFailure 失败回调,参数为 (errorCode, errorMsg)
|
||||
* @return UiState 包装的结果,Success 携带列表数据,Error 携带错误信息
|
||||
*/
|
||||
suspend fun searchFoodList(
|
||||
param: MutableMap<String, Any>,
|
||||
onSuccess: (MutableList<FoodRecord>?) -> Unit,
|
||||
onFailure: (String, String) -> Unit
|
||||
) = request(
|
||||
onRequest = { apiService.searchFoodList(param = param) },
|
||||
onSuccess = onSuccess,
|
||||
onFailure = onFailure
|
||||
)
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询采样数据列表
|
||||
* @param param 查询参数
|
||||
* @param onSuccess 成功回调
|
||||
* @param onFailure 失败回调,参数为 (errorCode, errorMsg)
|
||||
* @return UiState 包装的结果,Success 携带列表数据,Error 携带错误信息
|
||||
*/
|
||||
suspend fun getSamplingList(
|
||||
param: MutableMap<String, Any>,
|
||||
onSuccess: (MutableList<FoodRecord>?) -> Unit,
|
||||
onFailure: (String, String) -> Unit
|
||||
) = request(
|
||||
onRequest = { apiService.getSamplingList(param = param) },
|
||||
onSuccess = onSuccess,
|
||||
onFailure = onFailure
|
||||
)
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询物品信息列表
|
||||
* @param param 查询参数
|
||||
* @param onSuccess 成功回调
|
||||
* @param onFailure 失败回调,参数为 (errorCode, errorMsg)
|
||||
* @return UiState 包装的结果,Success 携带列表数据,Error 携带错误信息
|
||||
*/
|
||||
suspend fun queryGoodsList(
|
||||
param: MutableMap<String, Any>,
|
||||
onSuccess: (MutableList<CookFoodGoodsEntity>?) -> Unit,
|
||||
onFailure: (String, String) -> Unit
|
||||
) = request(
|
||||
onRequest = { apiService.queryGoodsList(param = param) },
|
||||
onSuccess = onSuccess,
|
||||
onFailure = onFailure
|
||||
)
|
||||
suspend fun queryGoodsList(param: MutableMap<String, Any>): UiState<MutableList<CookFoodGoodsEntity>?> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询调料信息列表
|
||||
* @param param 查询参数
|
||||
* @param onSuccess 成功回调
|
||||
* @param onFailure 失败回调,参数为 (errorCode, errorMsg)
|
||||
* @return UiState 包装的结果,Success 携带列表数据,Error 携带错误信息
|
||||
*/
|
||||
suspend fun querySeasoningList(
|
||||
param: MutableMap<String, Any>,
|
||||
onSuccess: (MutableList<SeasoningEntity>?) -> Unit,
|
||||
onFailure: (String, String) -> Unit
|
||||
) = request(
|
||||
onRequest = { apiService.querySeasoningList(param = param) },
|
||||
onSuccess = onSuccess,
|
||||
onFailure = onFailure
|
||||
)
|
||||
suspend fun querySeasoningList(param: MutableMap<String, Any>): UiState<MutableList<SeasoningEntity>?> {
|
||||
return try {
|
||||
val resp = apiService.querySeasoningList(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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.shuwei.dish.match.net
|
||||
|
||||
/**
|
||||
* 统一 UI 状态模型,用于 ViewModel 向 UI 层传递请求状态
|
||||
* Idle — 初始状态,未发起请求
|
||||
* Loading — 请求进行中
|
||||
* Success — 请求成功,携带数据
|
||||
* Error — 请求失败,携带错误码和错误信息
|
||||
*/
|
||||
sealed class UiState<out T> {
|
||||
object Idle : UiState<Nothing>()
|
||||
object Loading : UiState<Nothing>()
|
||||
data class Success<T>(val data: T) : UiState<T>()
|
||||
data class Error(val code: String, val msg: String) : UiState<Nothing>()
|
||||
}
|
||||
@@ -213,6 +213,31 @@ object ObjectBox {
|
||||
getBox<Food>()?.query(Food_.name.equal(name))?.build()?.remove()
|
||||
}
|
||||
|
||||
/**
|
||||
* 按名称分组统计采集数量
|
||||
* 使用属性查询只加载 name 字段,不加载 foodVector,节省大量内存
|
||||
* @param nameFilter 名称过滤关键词,为空时查询全部
|
||||
* @return 按名称分组后的 (名称, 数量) 列表,按名称排序
|
||||
*/
|
||||
suspend fun queryFoodNameCounts(nameFilter: String? = null) = safeDbOp {
|
||||
val box = getBox<Food>() ?: return@safeDbOp emptyList<Pair<String, Int>>()
|
||||
val query = if (!nameFilter.isNullOrBlank()) {
|
||||
box.query(Food_.name.contains(nameFilter)).build()
|
||||
} else {
|
||||
box.query().build()
|
||||
}
|
||||
try {
|
||||
// 只查 name 字段,完全不加载 foodVector
|
||||
query.property(Food_.name).findStrings()
|
||||
.groupingBy { it }
|
||||
.eachCount()
|
||||
.map { (name, count) -> Pair(name, count) }
|
||||
.sortedBy { it.first }
|
||||
} finally {
|
||||
query.close()
|
||||
}
|
||||
} ?: emptyList()
|
||||
|
||||
private val dbMutex = Mutex() // 协程并发锁,保证写入操作原子性
|
||||
private const val DB_DIR_NAME = "objectbox" // ObjectBox 默认数据库目录
|
||||
private const val BACKUP_DIR_NAME = "objectbox_backup" // 备份目录
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
package com.shuwei.dish.match.ui
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.graphics.Color
|
||||
import android.graphics.Typeface
|
||||
import android.os.Bundle
|
||||
import android.text.style.ForegroundColorSpan
|
||||
import android.text.style.StyleSpan
|
||||
import android.view.LayoutInflater
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import androidx.core.widget.addTextChangedListener
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.shuwei.dish.match.R
|
||||
import com.shuwei.dish.match.adapter.CollectedFoodAdapter
|
||||
import com.shuwei.dish.match.base.BaseActivity
|
||||
import com.shuwei.dish.match.databinding.ActivityCollectedFoodBinding
|
||||
import com.shuwei.dish.match.databinding.LayoutEmptyViewBinding
|
||||
import com.shuwei.dish.match.dialog.CommonDialog
|
||||
import com.shuwei.dish.match.entity.CollectedFoodItem
|
||||
import com.shuwei.dish.match.utils.KeyboardUtil
|
||||
import com.shuwei.dish.match.utils.ext.appendText
|
||||
import com.shuwei.dish.match.utils.ext.buildSpannableString
|
||||
import com.shuwei.dish.match.utils.ext.gone
|
||||
import com.shuwei.dish.match.utils.ext.toast
|
||||
import com.shuwei.dish.match.utils.ext.visible
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* 已采集食材列表页面
|
||||
* 展示所有已采集的食材及其采集数量,支持搜索和删除
|
||||
*/
|
||||
class CollectedFoodActivity : BaseActivity() {
|
||||
|
||||
private lateinit var binding: ActivityCollectedFoodBinding
|
||||
|
||||
private val foodList = mutableListOf<CollectedFoodItem>()
|
||||
|
||||
private var emptyViewBinding: LayoutEmptyViewBinding? = null
|
||||
|
||||
private val adapter by lazy {
|
||||
CollectedFoodAdapter(foodList).apply {
|
||||
isStateViewEnable = true
|
||||
// 点击删除按钮,移除对应食材
|
||||
addOnItemChildClickListener(R.id.ivDelete) { _, _, position ->
|
||||
showDeleteDialog(foodList[position].foodName)
|
||||
}
|
||||
setOnItemClickListener { _, view, _ ->
|
||||
KeyboardUtil.hideKeyboard(view)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除弹窗
|
||||
*/
|
||||
private fun showDeleteDialog(foodName: String) {
|
||||
val showFoodName = foodName.split("WP").first()
|
||||
val separator = if (showFoodName.length <= 10) "\n" else ""
|
||||
val content = buildSpannableString {
|
||||
appendText("食材:")
|
||||
appendText(showFoodName, StyleSpan(Typeface.BOLD), ForegroundColorSpan(Color.BLACK))
|
||||
appendText(" 删除后无法恢复,${separator}确认要删除吗?")
|
||||
}
|
||||
CommonDialog(this)
|
||||
.setTitle("温馨提示")
|
||||
.setContent(content)
|
||||
.setNegativeButton("取消")
|
||||
.setPositiveButton("确认") {
|
||||
appViewModel.removeCollectedFood(
|
||||
foodName = foodName,
|
||||
nameFilter = binding.editSearch.text.toString()
|
||||
)
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
statusBarDarkFont(enable = true)
|
||||
binding = ActivityCollectedFoodBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
setHeaderBackground()
|
||||
binding.root.setOnClickListener { v ->
|
||||
KeyboardUtil.hideKeyboard(v)
|
||||
}
|
||||
setTitleBar(titleBarAction = {
|
||||
it.visible()
|
||||
it.setOnClickListener { v ->
|
||||
KeyboardUtil.hideKeyboard(v)
|
||||
}
|
||||
}, titleAction = {
|
||||
it.text = "已采集食材"
|
||||
}, rightIconActon = {
|
||||
it.gone()
|
||||
}, backAction = {
|
||||
it.visible()
|
||||
it.setOnClickListener {
|
||||
finish()
|
||||
}
|
||||
})
|
||||
initRecyclerView()
|
||||
initSearch()
|
||||
initObserver()
|
||||
loadCollectedFoodList()
|
||||
}
|
||||
|
||||
private fun loadCollectedFoodList(name: String = "") {
|
||||
appViewModel.loadCollectedFoodList(nameFilter = name)
|
||||
}
|
||||
|
||||
/**
|
||||
* 收集 searchFoodState,统一处理 Loading / Success / Error 状态
|
||||
*/
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private fun initObserver() {
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
appViewModel.collectedFoodListState.collect { items ->
|
||||
foodList.clear()
|
||||
foodList.addAll(items)
|
||||
adapter.notifyDataSetChanged()
|
||||
if (items.isEmpty()) {
|
||||
loadEmptyView()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 展示空视图 */
|
||||
private fun loadEmptyView() {
|
||||
if (emptyViewBinding == null) {
|
||||
emptyViewBinding = LayoutEmptyViewBinding.inflate(
|
||||
LayoutInflater.from(this), binding.rvCollectedFood, false
|
||||
)
|
||||
}
|
||||
emptyViewBinding!!.tvContent.text = "暂无数据"
|
||||
emptyViewBinding!!.tvSubContent.text = "未查询到食材信息"
|
||||
adapter.stateView = emptyViewBinding!!.root
|
||||
}
|
||||
|
||||
/** 初始化列表 */
|
||||
private fun initRecyclerView() {
|
||||
binding.rvCollectedFood.run {
|
||||
layoutManager = LinearLayoutManager(this@CollectedFoodActivity)
|
||||
adapter = this@CollectedFoodActivity.adapter
|
||||
}
|
||||
}
|
||||
|
||||
/** 初始化搜索栏交互 */
|
||||
private fun initSearch() {
|
||||
binding.btnSearch.setOnClickListener { v ->
|
||||
performSearch {
|
||||
toast(binding.editSearch.hint.toString())
|
||||
}
|
||||
KeyboardUtil.hideKeyboard(v)
|
||||
}
|
||||
binding.editSearch.run {
|
||||
addTextChangedListener {
|
||||
performSearch {
|
||||
loadCollectedFoodList()
|
||||
}
|
||||
}
|
||||
setOnEditorActionListener { v, actionId, _ ->
|
||||
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
|
||||
performSearch {
|
||||
toast(binding.editSearch.hint.toString())
|
||||
}
|
||||
KeyboardUtil.hideKeyboard(v)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 根据关键词过滤食材列表 */
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private fun performSearch(action: () -> Unit) {
|
||||
val keyword = binding.editSearch.text.toString().trim()
|
||||
if (keyword.isEmpty()) {
|
||||
action()
|
||||
return
|
||||
}
|
||||
// 根据关键词从数据库查询并刷新列表
|
||||
loadCollectedFoodList(keyword)
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
//import androidx.lifecycle.ViewModelProvider
|
||||
//import com.shuwei.dish.match.base.BaseActivity
|
||||
//import com.shuwei.dish.match.base.BaseApp
|
||||
//import com.shuwei.dish.match.db.AppRepository
|
||||
//import com.shuwei.dish.match.db.DbRepository
|
||||
//import com.shuwei.dish.match.dialog.CommonDialog
|
||||
//import com.shuwei.dish.match.entity.SeasoningEntity
|
||||
//import com.shuwei.dish.match.entity.ResetReasoningRecord
|
||||
@@ -29,8 +29,6 @@
|
||||
//import com.shuwei.dish.match.utils.ext.startActivity
|
||||
//import com.shuwei.dish.match.utils.ext.toast
|
||||
//import com.shuwei.dish.match.utils.ext.visible
|
||||
//import com.shuwei.dish.match.viewmodel.AppViewModel
|
||||
//import com.shuwei.dish.match.viewmodel.factory.AppFactory
|
||||
//import com.shuwei.dish.match.adapter.TextCellAdapter
|
||||
//import com.shuwei.dish.match.databinding.ActivityDeviceConfigBinding
|
||||
//import com.shuwei.dish.match.dialog.SeasoningSearchDialog
|
||||
@@ -61,7 +59,7 @@
|
||||
//
|
||||
// private lateinit var binding: ActivityDeviceConfigBinding
|
||||
//
|
||||
// private lateinit var appViewModel: AppViewModel
|
||||
// private lateinit var appViewModel: DbViewModel
|
||||
//
|
||||
// private var cookMode: Int = 0
|
||||
//// private val weightArray = SparseIntArray()
|
||||
@@ -200,9 +198,9 @@
|
||||
// private fun initViewModel() {
|
||||
// val db = BaseApp.instance!!.database
|
||||
// val factory =
|
||||
// AppFactory(AppRepository(db.appDao()))
|
||||
// AppFactory(DbRepository(db.appDao()))
|
||||
// appViewModel =
|
||||
// ViewModelProvider(this, factory)[AppViewModel::class.java]
|
||||
// ViewModelProvider(this, factory)[DbViewModel::class.java]
|
||||
// }
|
||||
//
|
||||
// private fun loadSeasoning() {
|
||||
|
||||
@@ -7,7 +7,6 @@ import android.util.Log
|
||||
import android.view.View
|
||||
import androidx.activity.addCallback
|
||||
import androidx.activity.viewModels
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.shuwei.dish.match.R
|
||||
@@ -15,7 +14,6 @@ import com.shuwei.dish.match.adapter.DishPartAdapter
|
||||
import com.shuwei.dish.match.base.BaseActivity
|
||||
import com.shuwei.dish.match.base.BaseApp
|
||||
import com.shuwei.dish.match.databinding.ActivityDishSamplingBinding
|
||||
import com.shuwei.dish.match.db.AppRepository
|
||||
import com.shuwei.dish.match.dialog.FoodSearchDialog
|
||||
import com.shuwei.dish.match.dialog.CommonDialog
|
||||
import com.shuwei.dish.match.entity.CookFoodEntity
|
||||
@@ -33,8 +31,6 @@ 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.shuwei.dish.match.viewmodel.AppViewModel
|
||||
import com.shuwei.dish.match.viewmodel.factory.AppFactory
|
||||
import java.io.Serializable
|
||||
|
||||
class DishSamplingActivity : BaseActivity() {
|
||||
@@ -62,7 +58,6 @@ class DishSamplingActivity : BaseActivity() {
|
||||
setTitleBar()
|
||||
setHeaderBackground()
|
||||
addViewClickListener()
|
||||
initViewModel()
|
||||
foodName = intent.getStringExtra(FOOD_NAME)
|
||||
binding.etInputDish.setText(foodName)
|
||||
|
||||
@@ -97,18 +92,10 @@ class DishSamplingActivity : BaseActivity() {
|
||||
})
|
||||
}
|
||||
|
||||
private lateinit var appViewModel: AppViewModel
|
||||
|
||||
private fun initViewModel() {
|
||||
val db = BaseApp.instance!!.database
|
||||
val factory =
|
||||
AppFactory(AppRepository(db.appDao(), db.seasoningSlotDao()))
|
||||
appViewModel =
|
||||
ViewModelProvider(this, factory)[AppViewModel::class.java]
|
||||
}
|
||||
|
||||
fun getCookFoodList(action: (MutableList<CookFoodEntity>?) -> Unit) {
|
||||
appViewModel.getCookFoodList(cookMode = 1) { action(it) }
|
||||
fun getCookFoodList() {
|
||||
appViewModel.getCookFoodList(cookMode = 1)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -269,7 +256,7 @@ class DishSamplingActivity : BaseActivity() {
|
||||
setSelection(text.length)
|
||||
}
|
||||
}
|
||||
KeyboardUtil.hideKeyboard(v.context, v)
|
||||
KeyboardUtil.hideKeyboard(v)
|
||||
}
|
||||
|
||||
private fun searchDishType() {
|
||||
|
||||
@@ -4,6 +4,9 @@ import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.shuwei.dish.match.R
|
||||
import com.shuwei.dish.match.adapter.FoodRecordAdapter
|
||||
@@ -12,6 +15,7 @@ import com.shuwei.dish.match.base.BaseApp
|
||||
import com.shuwei.dish.match.databinding.ActivityFoodSearchBinding
|
||||
import com.shuwei.dish.match.databinding.LayoutEmptyViewBinding
|
||||
import com.shuwei.dish.match.entity.FoodRecord
|
||||
import com.shuwei.dish.match.net.UiState
|
||||
import com.shuwei.dish.match.utils.KeyboardUtil
|
||||
import com.shuwei.dish.match.utils.ext.addOnActionSearchListener
|
||||
import com.shuwei.dish.match.utils.ext.gone
|
||||
@@ -19,6 +23,7 @@ import com.shuwei.dish.match.utils.ext.startActivity
|
||||
import com.shuwei.dish.match.utils.ext.toast
|
||||
import com.shuwei.dish.match.utils.ext.visible
|
||||
import java.io.Serializable
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class FoodSearchActivity : BaseActivity() {
|
||||
|
||||
@@ -83,13 +88,38 @@ class FoodSearchActivity : BaseActivity() {
|
||||
adapter = recordAdapter
|
||||
}
|
||||
addViewListener()
|
||||
initObserver()
|
||||
}
|
||||
|
||||
/**
|
||||
* 收集 searchFoodState,统一处理 Loading / Success / Error 状态
|
||||
*/
|
||||
private fun initObserver() {
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
netViewModel.searchFoodState.collect { state ->
|
||||
when (state) {
|
||||
is UiState.Loading -> showLoading()
|
||||
is UiState.Success -> handleSearchResult(state.data)
|
||||
is UiState.Error -> {
|
||||
delayDismissLoading()
|
||||
finishRefresh()
|
||||
binding.refreshLayout.setEnableRefresh(true)
|
||||
toast(state.msg)
|
||||
if (pageNo == 1) loadEmptyView()
|
||||
}
|
||||
is UiState.Idle -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun addViewListener() {
|
||||
binding.ivDishSearch.setOnClickListener { v ->
|
||||
pageNo = 1
|
||||
getInputAndSearch()
|
||||
KeyboardUtil.hideKeyboard(v.context, v)
|
||||
KeyboardUtil.hideKeyboard(v)
|
||||
}
|
||||
binding.refreshLayout.setEnableRefresh(true)
|
||||
binding.refreshLayout.setEnableLoadMore(false)
|
||||
@@ -106,13 +136,13 @@ class FoodSearchActivity : BaseActivity() {
|
||||
queryListInfo(foodName!!)
|
||||
}
|
||||
binding.root.setOnClickListener { v ->
|
||||
KeyboardUtil.hideKeyboard(v.context, v)
|
||||
KeyboardUtil.hideKeyboard(v)
|
||||
}
|
||||
binding.etInputDish.let { v ->
|
||||
v.addOnActionSearchListener {
|
||||
pageNo = 1
|
||||
getInputAndSearch()
|
||||
KeyboardUtil.hideKeyboard(v.context, v)
|
||||
KeyboardUtil.hideKeyboard( v)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -140,61 +170,6 @@ class FoodSearchActivity : BaseActivity() {
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private fun queryListInfo(input: String) {
|
||||
showLoading()
|
||||
// val map = mutableMapOf(
|
||||
// "foodName" to input.trim(),
|
||||
// "pageNo" to "$pageNo",
|
||||
// "pageSize" to "$pageSize",
|
||||
// "canteenId" to BaseApp.canteenId
|
||||
// "dinnerType" to getDinnerTypeText()
|
||||
// )
|
||||
// val sb = StringBuilder(UrlConfig.QUERY_FOOD_LIST).apply {
|
||||
// append("?")
|
||||
// map.forEach { (key, value) -> append("$key=$value&") }
|
||||
// }
|
||||
// sb.deleteCharAt(sb.length - 1)
|
||||
// HttpUtil.get(
|
||||
// url = sb.toString(),
|
||||
// doSuccess = {
|
||||
// delayDismissLoading()
|
||||
// finishRefresh()
|
||||
// binding.refreshLayout.run {
|
||||
// setEnableRefresh(true)
|
||||
// }
|
||||
// val json = it.toJsonString()
|
||||
// val recordBean: FoodRecordBean? = json.toObject<FoodRecordBean>()
|
||||
// if (recordBean == null || recordBean.records.isNullOrEmpty()) {
|
||||
//// toast("暂未搜索到相关菜品信息")
|
||||
// if (pageNo == 1) {
|
||||
// loadEmptyView()
|
||||
// }
|
||||
// return@get
|
||||
// }
|
||||
// val records = recordBean.records
|
||||
// if (pageNo == 1) {
|
||||
// list.clear()
|
||||
// }
|
||||
// list.addAll(records!!)
|
||||
// recordAdapter.notifyDataSetChanged()
|
||||
// val isLoadMoreEnable = records.size >= pageSize
|
||||
// binding.refreshLayout.setEnableLoadMore(isLoadMoreEnable)
|
||||
// if (isLoadMoreEnable) {
|
||||
// pageNo++
|
||||
// }
|
||||
// },
|
||||
// doFailure = { code, msg ->
|
||||
// binding.refreshLayout.run {
|
||||
// setEnableRefresh(true)
|
||||
// }
|
||||
// toast(msg)
|
||||
// delayDismissLoading()
|
||||
// finishRefresh()
|
||||
// if (pageNo == 1) {
|
||||
// loadEmptyView()
|
||||
// }
|
||||
// }
|
||||
// )
|
||||
|
||||
val map = mutableMapOf<String, Any>(
|
||||
"foodName" to input.trim(),
|
||||
"pageNum" to pageNo,
|
||||
@@ -202,40 +177,27 @@ class FoodSearchActivity : BaseActivity() {
|
||||
"placeId" to BaseApp.canteenId,
|
||||
"dinnerType" to getDinnerTypeText()
|
||||
)
|
||||
netViewModel.searchFoodList(
|
||||
param = map,
|
||||
onSuccess = {
|
||||
netViewModel.searchFoodList(param = map)
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理搜索结果,填充列表或展示空视图
|
||||
*/
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private fun handleSearchResult(records: MutableList<FoodRecord>?) {
|
||||
delayDismissLoading()
|
||||
finishRefresh()
|
||||
binding.refreshLayout.setEnableRefresh(true)
|
||||
if (it.isNullOrEmpty()) {
|
||||
// toast("暂未搜索到相关菜品信息")
|
||||
if (pageNo == 1) {
|
||||
loadEmptyView()
|
||||
if (records.isNullOrEmpty()) {
|
||||
if (pageNo == 1) loadEmptyView()
|
||||
return
|
||||
}
|
||||
return@searchFoodList
|
||||
}
|
||||
if (pageNo == 1) {
|
||||
list.clear()
|
||||
}
|
||||
list.addAll(it)
|
||||
if (pageNo == 1) list.clear()
|
||||
list.addAll(records)
|
||||
recordAdapter.notifyDataSetChanged()
|
||||
val isLoadMoreEnable = it.size >= pageSize
|
||||
val isLoadMoreEnable = records.size >= pageSize
|
||||
binding.refreshLayout.setEnableLoadMore(isLoadMoreEnable)
|
||||
if (isLoadMoreEnable) {
|
||||
pageNo++
|
||||
}
|
||||
}, onFailure = { code, msg ->
|
||||
binding.refreshLayout.run {
|
||||
setEnableRefresh(true)
|
||||
}
|
||||
toast(msg)
|
||||
delayDismissLoading()
|
||||
finishRefresh()
|
||||
if (pageNo == 1) {
|
||||
loadEmptyView()
|
||||
}
|
||||
})
|
||||
if (isLoadMoreEnable) pageNo++
|
||||
}
|
||||
|
||||
private fun finishRefresh() {
|
||||
|
||||
@@ -3,20 +3,18 @@ package com.shuwei.dish.match.ui
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
import androidx.activity.addCallback
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.shuwei.dish.match.R
|
||||
import com.shuwei.dish.match.adapter.HomeModeAdapter
|
||||
import com.shuwei.dish.match.base.BaseActivity
|
||||
import com.shuwei.dish.match.base.BaseApp
|
||||
import com.shuwei.dish.match.databinding.ActivityHomeBinding
|
||||
import com.shuwei.dish.match.db.AppRepository
|
||||
import com.shuwei.dish.match.entity.HomeModeBean
|
||||
import com.shuwei.dish.match.utils.SpTool
|
||||
import com.shuwei.dish.match.utils.ext.startActivity
|
||||
import com.shuwei.dish.match.utils.ext.toast
|
||||
import com.shuwei.dish.match.viewmodel.AppViewModel
|
||||
import com.shuwei.dish.match.viewmodel.factory.AppFactory
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class HomeActivity : BaseActivity() {
|
||||
|
||||
@@ -32,7 +30,6 @@ class HomeActivity : BaseActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
statusBarDarkFont(enable = true)
|
||||
initViewModel()
|
||||
// // 获取 ANDROID_ID
|
||||
// val deviceId =
|
||||
// Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID)
|
||||
@@ -134,36 +131,30 @@ class HomeActivity : BaseActivity() {
|
||||
)
|
||||
}
|
||||
|
||||
private lateinit var appViewModel: AppViewModel
|
||||
|
||||
private fun initViewModel() {
|
||||
val db = BaseApp.instance!!.database
|
||||
val factory = AppFactory(AppRepository(db.appDao(), db.seasoningSlotDao()))
|
||||
appViewModel = ViewModelProvider(this, factory)[AppViewModel::class.java]
|
||||
}
|
||||
|
||||
private fun goSampling() {
|
||||
appViewModel.loadSeasoning {
|
||||
if (it.isEmpty()) {
|
||||
//无调料信息打开采样历史列表页面,点击设置配置调料信息
|
||||
lifecycleScope.launch {
|
||||
val slots = appViewModel.loadSeasoningSlot()
|
||||
if (slots.isEmpty()) {
|
||||
// 无调料信息,打开采样历史列表页面,点击设置配置调料信息
|
||||
startActivity<SamplingListActivity>()
|
||||
finish()
|
||||
return@loadSeasoning
|
||||
return@launch
|
||||
}
|
||||
appViewModel.countCookFood(cookMode = 1) { count ->
|
||||
val count = appViewModel.countCookFood(cookMode = 1)
|
||||
if (count > 0) {
|
||||
//有烹饪中数据打开采样历史列表页面
|
||||
// 有烹饪中数据,打开采样历史列表页面
|
||||
startActivity<SamplingListActivity>()
|
||||
finish()
|
||||
return@countCookFood
|
||||
return@launch
|
||||
}
|
||||
//无烹饪数据打开新增采样页面
|
||||
// 无烹饪数据,打开新增采样页面
|
||||
startActivity<PrepareCookActivity> {
|
||||
putExtra(PrepareCookActivity.PAGE_FROM, PrepareCookActivity.HOME)
|
||||
}
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,14 +9,12 @@ import android.view.KeyEvent
|
||||
import android.view.animation.RotateAnimation
|
||||
import androidx.activity.addCallback
|
||||
import androidx.core.graphics.toColorInt
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.shuwei.dish.match.base.BaseActivity
|
||||
import com.shuwei.dish.match.base.BaseApp
|
||||
import com.shuwei.dish.match.base.DeviceRole
|
||||
import com.shuwei.dish.match.base.GlobalData
|
||||
import com.shuwei.dish.match.databinding.ActivityInitBinding
|
||||
import com.shuwei.dish.match.db.AppRepository
|
||||
import com.shuwei.dish.match.objbox.FoodModule
|
||||
import com.shuwei.dish.match.scale.ScaleServiceManager
|
||||
import com.shuwei.dish.match.utils.AppUtil
|
||||
@@ -27,8 +25,6 @@ import com.shuwei.dish.match.utils.WeightUtil
|
||||
import com.shuwei.dish.match.utils.ext.gone
|
||||
import com.shuwei.dish.match.utils.ext.startActivity
|
||||
import com.shuwei.dish.match.utils.ext.visible
|
||||
import com.shuwei.dish.match.viewmodel.AppViewModel
|
||||
import com.shuwei.dish.match.viewmodel.factory.AppFactory
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@@ -38,7 +34,6 @@ class InitActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
private lateinit var binding: ActivityInitBinding
|
||||
private lateinit var appViewModel: AppViewModel
|
||||
private var startTime = 0L // 倒计时开始时间
|
||||
private var lastNetworkCheckTime = 0L // 上次检测网络的时间
|
||||
|
||||
@@ -59,8 +54,6 @@ class InitActivity : BaseActivity() {
|
||||
|
||||
BaseApp.canteenId = "0"
|
||||
|
||||
initViewModel()
|
||||
|
||||
WeightUtil.init()
|
||||
WeightUtil.getWeight()
|
||||
WeightUtil.startContinuousRead()
|
||||
@@ -68,11 +61,6 @@ class InitActivity : BaseActivity() {
|
||||
initViews()
|
||||
}
|
||||
|
||||
private fun initViewModel() {
|
||||
val db = BaseApp.instance!!.database
|
||||
val factory = AppFactory(AppRepository(db.appDao(), db.seasoningSlotDao()))
|
||||
appViewModel = ViewModelProvider(this, factory)[AppViewModel::class.java]
|
||||
}
|
||||
|
||||
private fun startNextPage(withDelay: Boolean = false) {
|
||||
lifecycleScope.launch {
|
||||
@@ -100,25 +88,25 @@ class InitActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
private fun goSampling() {
|
||||
appViewModel.loadSeasoning {
|
||||
if (it.isEmpty()) {
|
||||
//无调料信息打开采样历史列表页面,点击设置配置调料信息
|
||||
lifecycleScope.launch {
|
||||
val slots = appViewModel.loadSeasoningSlot()
|
||||
if (slots.isEmpty()) {
|
||||
// 无调料信息,打开采样历史列表页面,点击设置配置调料信息
|
||||
startActivity<SamplingListActivity>()
|
||||
return@loadSeasoning
|
||||
return@launch
|
||||
}
|
||||
appViewModel.countCookFood(cookMode = 1) { count ->
|
||||
val count = appViewModel.countCookFood(cookMode = 1)
|
||||
if (count > 0) {
|
||||
//有烹饪中数据打开采样历史列表页面
|
||||
// 有烹饪中数据,打开采样历史列表页面
|
||||
startActivity<SamplingListActivity>()
|
||||
return@countCookFood
|
||||
return@launch
|
||||
}
|
||||
//无烹饪数据打开新增采样页面
|
||||
// 无烹饪数据,打开新增采样页面
|
||||
startActivity<PrepareCookActivity> {
|
||||
putExtra(PrepareCookActivity.PAGE_FROM, PrepareCookActivity.HOME)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
WeightUtil.stopContinuousRead()
|
||||
|
||||
@@ -30,8 +30,6 @@ import com.shuwei.dish.match.databinding.ListItemScale22RowBinding
|
||||
import com.shuwei.dish.match.scale.ScaleData
|
||||
import com.shuwei.dish.match.scale.ScaleDeviceConfig
|
||||
import com.shuwei.dish.match.scale.ScaleServiceManager
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import com.shuwei.dish.match.utils.NetworkUtil
|
||||
import com.shuwei.dish.match.utils.SizeTool
|
||||
import com.shuwei.dish.match.utils.WeightUtil
|
||||
@@ -53,6 +51,7 @@ class MasterScaleActivity : BaseActivity() {
|
||||
|
||||
private lateinit var binding: ActivityMasterScaleBinding
|
||||
private val size by lazy { SizeTool.getFlexLayoutSize(10.dp) }
|
||||
|
||||
private data class DeviceGroup(
|
||||
val deviceId: String,
|
||||
val ip: String,
|
||||
@@ -81,16 +80,14 @@ class MasterScaleActivity : BaseActivity() {
|
||||
|
||||
/** 从 Room 加载槽位配置到 slotNameMap,加载完成后启动数据观测 */
|
||||
private fun loadSlotNames() {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val slots = BaseApp.instance!!.database.seasoningSlotDao().queryAll()
|
||||
withContext(Dispatchers.Main) {
|
||||
lifecycleScope.launch {
|
||||
val slots = appViewModel.loadSeasoningSlot()
|
||||
slots.forEach { slot ->
|
||||
slotNameMap["${slot.deviceId}#${slot.address}"] = slot.goodsName
|
||||
}
|
||||
observeScaleData()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 用 slotNameMap 为 ScaleData 注入名称 */
|
||||
private fun ScaleData.withSlotName(): ScaleData {
|
||||
|
||||
@@ -8,7 +8,9 @@ import android.util.Log
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.activity.addCallback
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.shuwei.dish.match.R
|
||||
@@ -20,6 +22,7 @@ import com.shuwei.dish.match.dialog.CommonDialog
|
||||
import com.shuwei.dish.match.entity.CookFoodEntity
|
||||
import com.shuwei.dish.match.entity.CookFoodGoodsEntity
|
||||
import com.shuwei.dish.match.entity.FoodRecord
|
||||
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
|
||||
@@ -36,6 +39,7 @@ 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 kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.Serializable
|
||||
@@ -110,6 +114,7 @@ class PrepareCookActivity : BaseActivity() {
|
||||
addBackKeyListener()
|
||||
initCamera(binding.flCameraContainer)
|
||||
initRecyclerView()
|
||||
initObserver()
|
||||
|
||||
if (!isSamplingMode) {
|
||||
getDishDetail()
|
||||
@@ -267,6 +272,28 @@ class PrepareCookActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
|
||||
private fun initObserver() {
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
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 -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDishDetail() {
|
||||
// //649
|
||||
// val url = "${UrlConfig.DISH_DETAIL}?foodId=${food?.foodId}"
|
||||
@@ -285,17 +312,7 @@ class PrepareCookActivity : BaseActivity() {
|
||||
// toast(msg)
|
||||
// }
|
||||
|
||||
netViewModel.getFoodDetail(
|
||||
food?.foodId ?: "",
|
||||
onSuccess = { detail ->
|
||||
if (detail == null) {
|
||||
toast("查询菜品信息为空")
|
||||
return@getFoodDetail
|
||||
}
|
||||
loadDishDetail(detail)
|
||||
}, onFailure = { code, msg ->
|
||||
toast(msg)
|
||||
})
|
||||
netViewModel.getFoodDetail(food?.foodId ?: "")
|
||||
}
|
||||
|
||||
|
||||
@@ -534,7 +551,7 @@ class PrepareCookActivity : BaseActivity() {
|
||||
setSelection(text.length)
|
||||
}
|
||||
}
|
||||
KeyboardUtil.hideKeyboard(v.context, v)
|
||||
KeyboardUtil.hideKeyboard(v)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,7 +5,9 @@ import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import androidx.activity.addCallback
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.shuwei.dish.match.R
|
||||
@@ -14,7 +16,6 @@ import com.shuwei.dish.match.base.BaseActivity
|
||||
import com.shuwei.dish.match.base.BaseApp
|
||||
import com.shuwei.dish.match.databinding.ActivitySamplingBinding
|
||||
import com.shuwei.dish.match.databinding.LayoutEmptyViewBinding
|
||||
import com.shuwei.dish.match.db.AppRepository
|
||||
import com.shuwei.dish.match.dialog.CommonDialog
|
||||
import com.shuwei.dish.match.entity.CookFoodEntity
|
||||
import com.shuwei.dish.match.entity.FoodRecord
|
||||
@@ -24,9 +25,9 @@ import com.shuwei.dish.match.utils.ext.gone
|
||||
import com.shuwei.dish.match.utils.ext.startActivity
|
||||
import com.shuwei.dish.match.utils.ext.toast
|
||||
import com.shuwei.dish.match.utils.ext.visible
|
||||
import com.shuwei.dish.match.viewmodel.AppViewModel
|
||||
import com.shuwei.dish.match.viewmodel.factory.AppFactory
|
||||
import java.io.Serializable
|
||||
import kotlinx.coroutines.launch
|
||||
import com.shuwei.dish.match.net.UiState
|
||||
|
||||
class SamplingListActivity : BaseActivity() {
|
||||
|
||||
@@ -44,13 +45,65 @@ class SamplingListActivity : BaseActivity() {
|
||||
setContentView(binding.root)
|
||||
setTitleBar()
|
||||
setHeaderBackground()
|
||||
initViewModel()
|
||||
initRecyclerView()
|
||||
addViewListener()
|
||||
initObserver()
|
||||
requestData(true)
|
||||
onBackPressedDispatcher.addCallback(this) { }
|
||||
}
|
||||
|
||||
/**
|
||||
* 收集 cookFoodListState,将本地烹饪中数据渲染到列表
|
||||
*/
|
||||
private fun initObserver() {
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
appViewModel.cookFoodListState.collect { cookFoodEntities ->
|
||||
delayDismissLoading()
|
||||
if (cookFoodEntities.isNullOrEmpty()) {
|
||||
loadEmptyView()
|
||||
return@collect
|
||||
}
|
||||
val tempList = mutableListOf<FoodRecord>()
|
||||
cookFoodEntities.sortedByDescending { DateTimeUtil.convert(dateStr = it.createTime) }
|
||||
.forEach { entity ->
|
||||
tempList.add(FoodRecord().apply {
|
||||
foodId = entity.foodId
|
||||
foodName = entity.foodName
|
||||
cookMode = 1
|
||||
isCooking = true
|
||||
})
|
||||
}
|
||||
list.clear()
|
||||
list.addAll(tempList)
|
||||
dishAdapter.notifyDataSetChanged()
|
||||
binding.refreshLayout.run {
|
||||
setEnableRefresh(false)
|
||||
setEnableLoadMore(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
netViewModel.samplingListState.collect { state ->
|
||||
when (state) {
|
||||
is UiState.Loading -> showLoading()
|
||||
is UiState.Success -> loadDishList(state.data)
|
||||
is UiState.Error -> {
|
||||
binding.refreshLayout.setEnableRefresh(true)
|
||||
toast(state.msg)
|
||||
finishRefresh()
|
||||
delayDismissLoading()
|
||||
if (pageNo == 1) loadEmptyView()
|
||||
}
|
||||
is UiState.Idle -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun setTitleBar() {
|
||||
setTitleBar(titleBarAction = {
|
||||
@@ -70,20 +123,17 @@ class SamplingListActivity : BaseActivity() {
|
||||
|
||||
}
|
||||
|
||||
private lateinit var appViewModel: AppViewModel
|
||||
|
||||
private fun initViewModel() {
|
||||
val db = BaseApp.instance!!.database
|
||||
val factory = AppFactory(AppRepository(db.appDao(), db.seasoningSlotDao()))
|
||||
appViewModel = ViewModelProvider(this, factory)[AppViewModel::class.java]
|
||||
}
|
||||
|
||||
fun getCookFoodList(action: (MutableList<CookFoodEntity>?) -> Unit) {
|
||||
appViewModel.getCookFoodList(cookMode = 1) { action(it) }
|
||||
fun getCookFoodList() {
|
||||
appViewModel.getCookFoodList(cookMode = 1)
|
||||
}
|
||||
|
||||
fun deleteCookFoodAndGoods(foodId: String, action: () -> Unit) {
|
||||
appViewModel.deleteCookFoodAndGoods(cookMode = 1, foodId = foodId, onFinish = action)
|
||||
lifecycleScope.launch {
|
||||
appViewModel.deleteCookFoodAndGoods(cookMode = 1, foodId = foodId)
|
||||
action()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNewIntent(intent: Intent) {
|
||||
@@ -190,53 +240,12 @@ class SamplingListActivity : BaseActivity() {
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
fun getSamplingList() {
|
||||
showLoading()
|
||||
// val map = mapOf(
|
||||
//// "foodName" to input,
|
||||
// "pageNo" to "$pageNo",
|
||||
// "pageSize" to "$pageSize",
|
||||
// "canteenId" to BaseApp.canteenId
|
||||
// )
|
||||
// val sb = StringBuilder(UrlConfig.SAMPLING_LIST).apply {
|
||||
// append("?")
|
||||
// map.forEach { (key, value) -> append("$key=$value&") }
|
||||
// }
|
||||
// sb.deleteCharAt(sb.length - 1)
|
||||
// HttpUtil.get(
|
||||
// url = sb.toString(),
|
||||
// doSuccess = {
|
||||
// loadDishList(it)
|
||||
// }, doFailure = { code, msg ->
|
||||
// binding.refreshLayout.run {
|
||||
// setEnableRefresh(true)
|
||||
// }
|
||||
// toast(msg)
|
||||
// finishRefresh()
|
||||
// binding.refreshLayout.setEnableRefresh(true)
|
||||
// delayDismissLoading()
|
||||
// if (pageNo == 1) {
|
||||
// loadEmptyView()
|
||||
// }
|
||||
// })
|
||||
|
||||
netViewModel.getSamplingList(
|
||||
param = mutableMapOf(
|
||||
"pageNum" to pageNo,
|
||||
"pageSize" to pageSize,
|
||||
"placeId" to BaseApp.canteenId
|
||||
),
|
||||
onSuccess = {
|
||||
loadDishList(it)
|
||||
},
|
||||
onFailure = { code, msg ->
|
||||
binding.refreshLayout.setEnableRefresh(true)
|
||||
toast(msg)
|
||||
finishRefresh()
|
||||
delayDismissLoading()
|
||||
if (pageNo == 1) {
|
||||
loadEmptyView()
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -298,38 +307,18 @@ class SamplingListActivity : BaseActivity() {
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
fun refreshLocalData() {
|
||||
showLoading()
|
||||
//查询本地数据
|
||||
getCookFoodList { cookFoodEntities ->
|
||||
delayDismissLoading()
|
||||
if (cookFoodEntities.isNullOrEmpty()) {
|
||||
loadEmptyView()
|
||||
return@getCookFoodList
|
||||
}
|
||||
val tempList = mutableListOf<FoodRecord>()
|
||||
|
||||
cookFoodEntities.sortedByDescending { DateTimeUtil.convert(dateStr = it.createTime) }
|
||||
.forEach { entity ->
|
||||
tempList.add(FoodRecord().apply {
|
||||
foodId = entity.foodId
|
||||
foodName = entity.foodName
|
||||
cookMode = 1
|
||||
isCooking = true
|
||||
})
|
||||
}
|
||||
list.clear()
|
||||
list.addAll(tempList)
|
||||
dishAdapter.notifyDataSetChanged()
|
||||
binding.refreshLayout.run {
|
||||
setEnableRefresh(false)
|
||||
setEnableLoadMore(false)
|
||||
}
|
||||
}
|
||||
appViewModel.resetCookFoodList()
|
||||
getCookFoodList()
|
||||
}
|
||||
|
||||
private fun requestData(isCooking: Boolean) {
|
||||
if (isCooking) {
|
||||
// 清除上次网络请求的残留状态
|
||||
netViewModel.resetSamplingListState()
|
||||
refreshLocalData()
|
||||
} else {
|
||||
// 同理,清除本地数据残留状态
|
||||
appViewModel.resetCookFoodList()
|
||||
pageNo = 1
|
||||
getSamplingList()
|
||||
}
|
||||
@@ -367,10 +356,11 @@ class SamplingListActivity : BaseActivity() {
|
||||
block()
|
||||
return
|
||||
}
|
||||
appViewModel.loadSeasoning {
|
||||
if (it.isEmpty()) {
|
||||
lifecycleScope.launch {
|
||||
val slots = appViewModel.loadSeasoningSlot()
|
||||
if (slots.isEmpty()) {
|
||||
showDeviceConfigDialog()
|
||||
return@loadSeasoning
|
||||
return@launch
|
||||
}
|
||||
configFinished = true
|
||||
block()
|
||||
|
||||
@@ -3,15 +3,13 @@ package com.shuwei.dish.match.ui
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.activity.addCallback
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import kotlinx.coroutines.launch
|
||||
import com.shuwei.dish.match.R
|
||||
import com.shuwei.dish.match.base.BaseActivity
|
||||
import com.shuwei.dish.match.base.BaseApp
|
||||
import com.shuwei.dish.match.databinding.ActivitySelectDishBinding
|
||||
import com.shuwei.dish.match.db.AppRepository
|
||||
import com.shuwei.dish.match.dialog.CommonDialog
|
||||
import com.shuwei.dish.match.entity.CookFoodEntity
|
||||
import com.shuwei.dish.match.entity.FoodRecord
|
||||
import com.shuwei.dish.match.ui.fragment.DishListFragment
|
||||
import com.shuwei.dish.match.utils.KeyboardUtil
|
||||
import com.shuwei.dish.match.utils.ext.addOnActionSearchListener
|
||||
@@ -19,8 +17,6 @@ import com.shuwei.dish.match.utils.ext.gone
|
||||
import com.shuwei.dish.match.utils.ext.startActivity
|
||||
import com.shuwei.dish.match.utils.ext.toast
|
||||
import com.shuwei.dish.match.utils.ext.visible
|
||||
import com.shuwei.dish.match.viewmodel.AppViewModel
|
||||
import com.shuwei.dish.match.viewmodel.factory.AppFactory
|
||||
|
||||
class SelectDishActivity : BaseActivity() {
|
||||
|
||||
@@ -32,8 +28,6 @@ class SelectDishActivity : BaseActivity() {
|
||||
|
||||
private lateinit var binding: ActivitySelectDishBinding
|
||||
|
||||
private lateinit var appViewModel: AppViewModel
|
||||
|
||||
private var dinnerType: String = "1"
|
||||
|
||||
private val fragmentList = mutableListOf<DishListFragment>().apply {
|
||||
@@ -60,20 +54,14 @@ class SelectDishActivity : BaseActivity() {
|
||||
}, backAction = {
|
||||
it.gone()
|
||||
})
|
||||
initViewModel()
|
||||
addViewListener()
|
||||
loadFragment()
|
||||
onBackPressedDispatcher.addCallback(this) {}
|
||||
}
|
||||
|
||||
private fun initViewModel() {
|
||||
val db = BaseApp.instance!!.database
|
||||
val factory = AppFactory(AppRepository(db.appDao(), db.seasoningSlotDao()))
|
||||
appViewModel = ViewModelProvider(this, factory)[AppViewModel::class.java]
|
||||
}
|
||||
|
||||
fun getCookFoodList(action: (MutableList<CookFoodEntity>?) -> Unit) {
|
||||
appViewModel.getCookFoodList(cookMode = 0, dinnerType = dinnerType) { action(it) }
|
||||
fun getCookFoodList() {
|
||||
appViewModel.getCookFoodList(cookMode = 0, dinnerType = dinnerType)
|
||||
}
|
||||
|
||||
private var configFinished = false
|
||||
@@ -132,7 +120,7 @@ class SelectDishActivity : BaseActivity() {
|
||||
putExtra(FoodSearchActivity.DINNER_TYPE, dinnerType)
|
||||
putExtra(FoodSearchActivity.FOOD_NAME, searchText)
|
||||
}
|
||||
KeyboardUtil.hideKeyboard(this, binding.etInputDish)
|
||||
KeyboardUtil.hideKeyboard(binding.etInputDish)
|
||||
}
|
||||
|
||||
private fun loadFragment() {
|
||||
@@ -153,7 +141,10 @@ class SelectDishActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
fun deleteCookFoodAndGoods(foodId: String, action: () -> Unit) {
|
||||
appViewModel.deleteCookFoodAndGoods(cookMode = 0, foodId = foodId, onFinish = action)
|
||||
lifecycleScope.launch {
|
||||
appViewModel.deleteCookFoodAndGoods(cookMode = 0, foodId = foodId)
|
||||
action()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNewIntent(intent: Intent) {
|
||||
@@ -189,16 +180,8 @@ class SelectDishActivity : BaseActivity() {
|
||||
isVisible = false
|
||||
}
|
||||
|
||||
public fun getFoodList(
|
||||
param: MutableMap<String, Any>,
|
||||
onSuccess: (MutableList<FoodRecord>?) -> Unit,
|
||||
onFailure: (String, String) -> Unit
|
||||
) {
|
||||
netViewModel.searchFoodList(
|
||||
param = param,
|
||||
onSuccess = onSuccess,
|
||||
onFailure = onFailure
|
||||
)
|
||||
public fun getFoodList(param: MutableMap<String, Any>) {
|
||||
netViewModel.searchFoodList(param = param)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.shuwei.dish.match.base.BaseActivity
|
||||
import com.shuwei.dish.match.base.BaseApp
|
||||
import com.shuwei.dish.match.ui.fragment.CollectFragment
|
||||
import com.shuwei.dish.match.ui.fragment.DeviceConfigFragment
|
||||
import com.shuwei.dish.match.ui.fragment.SeasoningConfigFragment
|
||||
@@ -60,6 +61,7 @@ class SingleFragmentActivity : BaseActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
setHeaderBackground()
|
||||
|
||||
// 解析页面类型,非法值直接关闭
|
||||
|
||||
@@ -30,9 +30,7 @@ import com.shuwei.dish.match.utils.NetworkUtil
|
||||
import com.shuwei.dish.match.utils.SizeTool
|
||||
import com.shuwei.dish.match.utils.WeightUtil
|
||||
import com.shuwei.dish.match.utils.ext.dp
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
/**
|
||||
* 子设备专属页面(小屏幕设备使用)
|
||||
@@ -152,10 +150,9 @@ class SlaveActivity : BaseActivity() {
|
||||
* 主设备未开机时也能正常展示上次配置
|
||||
*/
|
||||
private fun loadSlotsFromDb() {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val dao = BaseApp.instance!!.database.seasoningSlotDao()
|
||||
val slots = dao.queryByDeviceId(GlobalData.deviceId)
|
||||
withContext(Dispatchers.Main) { applySlots(slots) }
|
||||
lifecycleScope.launch {
|
||||
val slots = appViewModel.getSeasoningSlotsByDeviceId(GlobalData.deviceId)
|
||||
applySlots(slots)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,9 +166,9 @@ class SlaveActivity : BaseActivity() {
|
||||
?.filter { it.deviceId == GlobalData.deviceId }
|
||||
?.map { SeasoningSlotEntity(it.deviceId, it.address, it.goodsId, it.goodsName) }
|
||||
?: return@onSeasoningConfig
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
BaseApp.instance!!.database.seasoningSlotDao().upsertAll(mySlots)
|
||||
withContext(Dispatchers.Main) { applySlots(mySlots) }
|
||||
lifecycleScope.launch {
|
||||
appViewModel.upsertAllSeasoningSlots(mySlots)
|
||||
applySlots(mySlots)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
package com.shuwei.dish.match.ui
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.graphics.Color
|
||||
import android.graphics.Typeface
|
||||
import android.os.Bundle
|
||||
import android.text.style.ForegroundColorSpan
|
||||
import android.text.style.StyleSpan
|
||||
import android.util.Log
|
||||
import androidx.activity.addCallback
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.shuwei.dish.match.R
|
||||
@@ -13,16 +18,18 @@ import com.shuwei.dish.match.adapter.SeasoningWeightAdapter
|
||||
import com.shuwei.dish.match.base.BaseActivity
|
||||
import com.shuwei.dish.match.base.BaseApp
|
||||
import com.shuwei.dish.match.databinding.ActivitySubmitFoodBinding
|
||||
import com.shuwei.dish.match.db.AppRepository
|
||||
import com.shuwei.dish.match.dialog.CommonDialog
|
||||
import com.shuwei.dish.match.entity.CookFoodEntity
|
||||
import com.shuwei.dish.match.entity.CookFoodGoodsEntity
|
||||
import com.shuwei.dish.match.entity.FoodRecord
|
||||
import com.shuwei.dish.match.net.NetViewModel
|
||||
import com.shuwei.dish.match.net.UiState
|
||||
import com.shuwei.dish.match.scale.ScaleDeviceConfig
|
||||
import com.shuwei.dish.match.scale.ScaleServiceManager
|
||||
import com.shuwei.dish.match.utils.AddressUtil
|
||||
import com.shuwei.dish.match.utils.WeightUtil
|
||||
import com.shuwei.dish.match.utils.ext.appendText
|
||||
import com.shuwei.dish.match.utils.ext.buildSpannableString
|
||||
import com.shuwei.dish.match.utils.ext.clickWithDebounce
|
||||
import com.shuwei.dish.match.utils.ext.gone
|
||||
import com.shuwei.dish.match.utils.ext.roundedDecimalPlace
|
||||
@@ -32,8 +39,6 @@ import com.shuwei.dish.match.utils.ext.toJsonString
|
||||
import com.shuwei.dish.match.utils.ext.toType
|
||||
import com.shuwei.dish.match.utils.ext.toast
|
||||
import com.shuwei.dish.match.utils.ext.visible
|
||||
import com.shuwei.dish.match.viewmodel.AppViewModel
|
||||
import com.shuwei.dish.match.viewmodel.factory.AppFactory
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -97,7 +102,6 @@ class SubmitFoodActivity : BaseActivity() {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivitySubmitFoodBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
initViewModel()
|
||||
setHeaderBackground()
|
||||
intent.extras?.apply {
|
||||
food = getSerializable(FOOD_ITEM) as FoodRecord?
|
||||
@@ -121,12 +125,34 @@ class SubmitFoodActivity : BaseActivity() {
|
||||
})
|
||||
setupRecyclerView()
|
||||
addViewListener()
|
||||
initObserver()
|
||||
loadSlotsThenObserveScales()
|
||||
onBackPressedDispatcher.addCallback(this) {
|
||||
remindSaveDataDialog()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 收集 submitCookFoodState,处理提交成功/失败
|
||||
*/
|
||||
private fun initObserver() {
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
netViewModel.submitCookFoodState.collect { state ->
|
||||
when (state) {
|
||||
is UiState.Success -> submitSuccess(food?.cookMode == 1)
|
||||
is UiState.Error -> {
|
||||
toast(state.msg)
|
||||
dismissLoading()
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 初始化 RecyclerView,2列 GridLayoutManager */
|
||||
private fun setupRecyclerView() {
|
||||
binding.rvSeasoning.itemAnimator = null
|
||||
@@ -139,17 +165,16 @@ class SubmitFoodActivity : BaseActivity() {
|
||||
* isCooking=true 时先从数据库查询 goodsList,筛选调料预填充 adapter,再开始观测
|
||||
*/
|
||||
private fun loadSlotsThenObserveScales() {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val slots = BaseApp.instance!!.database.seasoningSlotDao().queryAll()
|
||||
withContext(Dispatchers.Main) {
|
||||
lifecycleScope.launch {
|
||||
val slots = appViewModel.loadSeasoningSlot()
|
||||
slots.forEach { slot ->
|
||||
slotMap["${slot.deviceId}#${slot.address}"] = slot.goodsId to slot.goodsName
|
||||
}
|
||||
if (food?.isCooking == true) {
|
||||
// 制作中:从数据库查询 goodsList,筛选调料数据预填充 adapter
|
||||
val foodId = food?.foodId ?: return@withContext
|
||||
val cookMode = food?.cookMode ?: return@withContext
|
||||
appViewModel.getCookFoodGoodsList(foodId, cookMode) { list ->
|
||||
val foodId = food?.foodId ?: return@launch
|
||||
val cookMode = food?.cookMode ?: return@launch
|
||||
val list = appViewModel.getCookFoodGoodsList(foodId, cookMode)
|
||||
goodsList = list
|
||||
list.filter { it.materialType == 3 }.forEach { item ->
|
||||
val name = item.goodsName ?: ""
|
||||
@@ -164,13 +189,11 @@ class SubmitFoodActivity : BaseActivity() {
|
||||
)
|
||||
}
|
||||
observeScaleData()
|
||||
}
|
||||
} else {
|
||||
observeScaleData()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 订阅 ScaleServiceManager.allScales,过滤子设备数据并更新 adapter
|
||||
@@ -240,14 +263,18 @@ class SubmitFoodActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
private fun addViewListener() {
|
||||
binding.btnCook.clickWithDebounce { cook() }
|
||||
binding.btnCook.clickWithDebounce {
|
||||
val content = getRemindSpannable("开始制作")
|
||||
showRemindDialog(content) { cook() }
|
||||
}
|
||||
binding.btnWeightClear.clickWithDebounce { WeightUtil.tareTwo(2) }
|
||||
binding.btnSubmit.clickWithDebounce {
|
||||
if (cookFoodEntity.foodWeight <= 0.toDouble()) {
|
||||
toast("未识别到菜品熟重")
|
||||
return@clickWithDebounce
|
||||
}
|
||||
submit()
|
||||
val content = getRemindSpannable("制作完成")
|
||||
showRemindDialog(content) { submit() }
|
||||
}
|
||||
|
||||
// 监听主设备 2格秤的熟重
|
||||
@@ -271,10 +298,10 @@ class SubmitFoodActivity : BaseActivity() {
|
||||
return
|
||||
}
|
||||
val seasoningData = seasoningAdapter.items
|
||||
if (seasoningData.isEmpty()) {
|
||||
toast("未获取到调料信息")
|
||||
return
|
||||
}
|
||||
// if (seasoningData.isEmpty()) {
|
||||
// toast("未获取到调料信息")
|
||||
// return
|
||||
// }
|
||||
showLoading()
|
||||
|
||||
// 将调料数据转为 CookFoodGoodsEntity 追加到 goodsList
|
||||
@@ -305,16 +332,15 @@ class SubmitFoodActivity : BaseActivity() {
|
||||
}
|
||||
goodsList?.forEach { it.foodId = cookFoodEntity.foodId }
|
||||
|
||||
lifecycleScope.launch {
|
||||
appViewModel.saveCookFoodAndGoods(
|
||||
cookMode = food!!.cookMode,
|
||||
entity = cookFoodEntity,
|
||||
list = goodsList,
|
||||
onFinish = {
|
||||
runOnUiThread {
|
||||
list = goodsList
|
||||
)
|
||||
dismissLoading()
|
||||
jumpPage(isSamplingData, true)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun submit() {
|
||||
@@ -354,13 +380,7 @@ class SubmitFoodActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
Log.d(TAG, "submit: json=${cookFoodEntity.toJsonString()}")
|
||||
netViewModel.submitCookFood(
|
||||
entity = cookFoodEntity,
|
||||
onSuccess = { submitSuccess(isSamplingData) },
|
||||
onFailure = { _, msg ->
|
||||
toast(msg)
|
||||
dismissLoading()
|
||||
})
|
||||
netViewModel.submitCookFood(entity = cookFoodEntity)
|
||||
}
|
||||
|
||||
private fun submitSuccess(isSamplingData: Boolean) {
|
||||
@@ -369,10 +389,11 @@ class SubmitFoodActivity : BaseActivity() {
|
||||
jumpPage(isSamplingData, false)
|
||||
return
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
appViewModel.deleteCookFoodAndGoods(
|
||||
cookMode = food!!.cookMode,
|
||||
foodId = food!!.foodId!!
|
||||
) {
|
||||
)
|
||||
dismissLoading()
|
||||
jumpPage(isSamplingData, false)
|
||||
}
|
||||
@@ -391,13 +412,6 @@ class SubmitFoodActivity : BaseActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private lateinit var appViewModel: AppViewModel
|
||||
|
||||
private fun initViewModel() {
|
||||
val db = BaseApp.instance!!.database
|
||||
val factory = AppFactory(AppRepository(db.appDao(), db.seasoningSlotDao()))
|
||||
appViewModel = ViewModelProvider(this, factory)[AppViewModel::class.java]
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
WeightUtil.removeWeightListener(TAG)
|
||||
@@ -417,4 +431,22 @@ class SubmitFoodActivity : BaseActivity() {
|
||||
.show()
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击制作和提交按钮确认dialog
|
||||
*/
|
||||
private fun showRemindDialog(content: CharSequence, action: () -> Unit) {
|
||||
CommonDialog(this)
|
||||
.setTitle("温馨提示")
|
||||
.setContent(content)
|
||||
.setNegativeButton("取消")
|
||||
.setPositiveButton("确认") { action() }
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun getRemindSpannable(cookStateText: String) = buildSpannableString {
|
||||
appendText("请确认是否 ")
|
||||
appendText(cookStateText, StyleSpan(Typeface.BOLD), ForegroundColorSpan(Color.BLACK))
|
||||
appendText(" ?")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.shuwei.dish.match.ui.fragment
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.net.Uri
|
||||
@@ -22,6 +23,7 @@ import com.shuwei.dish.match.databinding.LayoutCameraPreviewBinding
|
||||
import com.shuwei.dish.match.dialog.Loading
|
||||
import com.shuwei.dish.match.objbox.FoodCollectionBean
|
||||
import com.shuwei.dish.match.objbox.FoodModule
|
||||
import com.shuwei.dish.match.ui.CollectedFoodActivity
|
||||
import com.shuwei.dish.match.ui.SingleFragmentActivity
|
||||
import com.shuwei.dish.match.utils.BitmapSaver
|
||||
import com.shuwei.dish.match.utils.CameraUtils
|
||||
@@ -243,7 +245,7 @@ class CollectFragment : BaseFragment<FragmentCollectBinding>(){
|
||||
}
|
||||
|
||||
binding.btnCollectedFood.setOnClickListener {
|
||||
// startActivity(Intent(requireActivity(), CollectedFoodActivity::class.java))
|
||||
startActivity(Intent(requireActivity(), CollectedFoodActivity::class.java))
|
||||
}
|
||||
binding.btnTakePhoto.clickWithDebounce {
|
||||
val count = foodCollectionList.count { it.bitmap != null }
|
||||
|
||||
@@ -39,7 +39,7 @@ class DeviceConfigFragment : BaseFragment<FragmentDeviceConfigBinding>() {
|
||||
var modeDesc: String
|
||||
)
|
||||
|
||||
// private lateinit var appViewModel: AppViewModel
|
||||
// private lateinit var appViewModel: DbViewModel
|
||||
|
||||
// private val weightArray = SparseArray<Double>()
|
||||
// private val addressArray = AddressUtil.getWeighAddressArray()
|
||||
@@ -54,22 +54,12 @@ class DeviceConfigFragment : BaseFragment<FragmentDeviceConfigBinding>() {
|
||||
}
|
||||
|
||||
override fun initialize() {
|
||||
initViewModel()
|
||||
initUI()
|
||||
// addWeighListener()
|
||||
// addGridItemListener()
|
||||
// loadSeasoning()
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化ViewModel
|
||||
*/
|
||||
private fun initViewModel() {
|
||||
// val db = BaseApp.instance!!.database
|
||||
// val factory = AppFactory(AppRepository(db.appDao()))
|
||||
// appViewModel = ViewModelProvider(this, factory)[AppViewModel::class.java]
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化UI
|
||||
*/
|
||||
|
||||
@@ -5,6 +5,9 @@ import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.chad.library.adapter4.util.setOnDebouncedItemClick
|
||||
@@ -13,7 +16,9 @@ import com.shuwei.dish.match.base.BaseApp
|
||||
import com.shuwei.dish.match.base.BaseFragment
|
||||
import com.shuwei.dish.match.databinding.FragmentDishListBinding
|
||||
import com.shuwei.dish.match.databinding.LayoutEmptyViewBinding
|
||||
import com.shuwei.dish.match.entity.CookFoodEntity
|
||||
import com.shuwei.dish.match.entity.FoodRecord
|
||||
import com.shuwei.dish.match.net.UiState
|
||||
import com.shuwei.dish.match.ui.PrepareCookActivity
|
||||
import com.shuwei.dish.match.ui.SelectDishActivity
|
||||
import com.shuwei.dish.match.ui.SubmitFoodActivity
|
||||
@@ -21,6 +26,8 @@ import com.shuwei.dish.match.utils.SwipeCallback
|
||||
import com.shuwei.dish.match.utils.ext.startActivity
|
||||
import com.shuwei.dish.match.utils.ext.toast
|
||||
import java.io.Serializable
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class DishListFragment : BaseFragment<FragmentDishListBinding>() {
|
||||
|
||||
@@ -108,6 +115,7 @@ class DishListFragment : BaseFragment<FragmentDishListBinding>() {
|
||||
itemTouchHelper.attachToRecyclerView(this)
|
||||
}
|
||||
addViewListener()
|
||||
initObserver()
|
||||
|
||||
pageNo = 1
|
||||
activity.showLoading()
|
||||
@@ -115,6 +123,39 @@ class DishListFragment : BaseFragment<FragmentDishListBinding>() {
|
||||
binding.refreshLayout.setEnableRefresh(true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 用 combine 同时监听网络结果与本地数据,网络成功时统一合并渲染
|
||||
* pageNo > 1(加载更多)时 cookFoodListState 不参与合并,直接追加网络数据
|
||||
*/
|
||||
private fun initObserver() {
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
combine(
|
||||
activity.netViewModel.searchFoodState,
|
||||
activity.appViewModel.cookFoodListState
|
||||
) { networkState, localList -> Pair(networkState, localList) }
|
||||
.collect { (networkState, localList) ->
|
||||
when (networkState) {
|
||||
is UiState.Loading -> activity.showLoading()
|
||||
is UiState.Success -> {
|
||||
activity.delayDismissLoading()
|
||||
finishRefresh()
|
||||
loadAndMergeDishList(networkState.data, localList)
|
||||
}
|
||||
is UiState.Error -> {
|
||||
if (isAdded.not()) return@collect
|
||||
toast(networkState.msg)
|
||||
finishRefresh()
|
||||
if (pageNo == 1) loadEmptyView()
|
||||
activity.delayDismissLoading()
|
||||
}
|
||||
is UiState.Idle -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun addViewListener() {
|
||||
binding.refreshLayout.run {
|
||||
setEnableRefresh(true)
|
||||
@@ -147,72 +188,15 @@ class DishListFragment : BaseFragment<FragmentDishListBinding>() {
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
@Suppress("unchecked_cast")
|
||||
fun getDishList() {
|
||||
activity.showLoading()
|
||||
activity.getFoodList(
|
||||
param = mutableMapOf(
|
||||
val param = mutableMapOf<String, Any>(
|
||||
"pageNum" to pageNo,
|
||||
"pageSize" to pageSize,
|
||||
"placeId" to BaseApp.canteenId,
|
||||
"dinnerType" to getDinnerTypeText()
|
||||
),
|
||||
onSuccess = { records ->
|
||||
activity.delayDismissLoading()
|
||||
finishRefresh()
|
||||
loadDishList(records)
|
||||
},
|
||||
onFailure = { code, msg ->
|
||||
if (isAdded.not()) {
|
||||
return@getFoodList
|
||||
}
|
||||
toast(msg)
|
||||
finishRefresh()
|
||||
if (pageNo == 1) {
|
||||
loadEmptyView()
|
||||
}
|
||||
activity.delayDismissLoading()
|
||||
}
|
||||
)
|
||||
// val map = mapOf(
|
||||
//// "foodName" to input,
|
||||
// "dinnerType" to getDinnerTypeText(),
|
||||
// "pageNo" to "$pageNo",
|
||||
// "pageSize" to "$pageSize",
|
||||
// "canteenId" to BaseApp.canteenId
|
||||
// )
|
||||
// val sb = StringBuilder(UrlConfig.QUERY_FOOD_LIST).apply {
|
||||
// append("?")
|
||||
// map.forEach { (key, value) -> append("$key=$value&") }
|
||||
// }
|
||||
// sb.deleteCharAt(sb.length - 1)
|
||||
// HttpUtil.get(
|
||||
// url = sb.toString(),
|
||||
// doSuccess = { data ->
|
||||
// binding.refreshLayout.run {
|
||||
// setEnableRefresh(true)
|
||||
// }
|
||||
// activity.delayDismissLoading()
|
||||
// finishRefresh()
|
||||
// val json = data.toJsonString()
|
||||
// val recordBean: FoodRecordBean? = json.toObject<FoodRecordBean>()
|
||||
// loadDishList(recordBean)
|
||||
// }, doFailure = { code, msg ->
|
||||
// try {
|
||||
// if (isAdded.not()) {
|
||||
// return@get
|
||||
// }
|
||||
// binding.refreshLayout.run {
|
||||
// setEnableRefresh(true)
|
||||
// }
|
||||
// toast(msg)
|
||||
// finishRefresh()
|
||||
// if (pageNo == 1) {
|
||||
// loadEmptyView()
|
||||
// }
|
||||
// activity.delayDismissLoading()
|
||||
// } catch (e: Exception) {
|
||||
// e.printStackTrace()
|
||||
// }
|
||||
// })
|
||||
// 网络与本地并行触发,pageNo > 1 时不重复查询本地数据
|
||||
activity.getFoodList(param = param)
|
||||
if (pageNo == 1) activity.getCookFoodList()
|
||||
}
|
||||
|
||||
private var emptyViewBinding: LayoutEmptyViewBinding? = null
|
||||
@@ -248,24 +232,41 @@ class DishListFragment : BaseFragment<FragmentDishListBinding>() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将网络数据与本地烹饪中数据合并后渲染列表
|
||||
* pageNo > 1 时忽略本地数据,直接追加网络数据,避免 combine 带入旧的本地状态
|
||||
*/
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private fun refreshLocalData(list: MutableList<FoodRecord>) {
|
||||
activity.getCookFoodList { cookFoodEntities ->
|
||||
if (cookFoodEntities.isNullOrEmpty()) {
|
||||
return@getCookFoodList
|
||||
private fun loadAndMergeDishList(
|
||||
records: MutableList<FoodRecord>?,
|
||||
localList: MutableList<CookFoodEntity>?
|
||||
) {
|
||||
try {
|
||||
if (isAdded.not()) return
|
||||
// pageNo > 1 时不参与本地合并,避免 combine 带入旧的本地状态
|
||||
val effectiveLocalList = if (pageNo == 1) localList else null
|
||||
if (records.isNullOrEmpty() && effectiveLocalList.isNullOrEmpty()) {
|
||||
if (pageNo == 1) loadEmptyView()
|
||||
return
|
||||
}
|
||||
val tempList = mutableListOf<FoodRecord>()
|
||||
if (pageNo == 1) list.clear()
|
||||
|
||||
cookFoodEntities.forEachIndexed { index, entity ->
|
||||
val food = list.firstOrNull { it.foodId == entity.foodId }
|
||||
val mergedList = records?.toMutableList() ?: mutableListOf()
|
||||
|
||||
// 仅 pageNo == 1 时才有本地数据参与合并
|
||||
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"
|
||||
tempList.add(food)
|
||||
cookingItems.add(food)
|
||||
} else {
|
||||
//当前查询到的list不包括本地数据id,可能数据在很多页以后了,暂时只能直接构造数据
|
||||
tempList.add(
|
||||
// 当前网络数据不包含该本地记录,直接构造
|
||||
cookingItems.add(
|
||||
FoodRecord(
|
||||
foodId = entity.foodId,
|
||||
foodName = entity.foodName,
|
||||
@@ -276,36 +277,20 @@ class DishListFragment : BaseFragment<FragmentDishListBinding>() {
|
||||
)
|
||||
}
|
||||
}
|
||||
list.removeAll(tempList)
|
||||
list.addAll(0, tempList)
|
||||
dishAdapter.notifyDataSetChanged()
|
||||
}
|
||||
mergedList.addAll(0, cookingItems)
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private fun loadDishList(records: MutableList<FoodRecord>?) {
|
||||
try {
|
||||
if (isAdded.not()) {
|
||||
return
|
||||
if (pageNo >= 2 && !localList.isNullOrEmpty()) {
|
||||
//第2页起,从mergedList中移除localList中的同foodId数据
|
||||
val localIds = localList.map { it.foodId }.toHashSet()
|
||||
mergedList.removeAll { it.foodId in localIds }
|
||||
}
|
||||
if (records.isNullOrEmpty()) {
|
||||
//toast("暂未搜索到相关菜品信息")
|
||||
if (pageNo == 1) {
|
||||
loadEmptyView()
|
||||
}
|
||||
return
|
||||
}
|
||||
if (pageNo == 1) {
|
||||
list.clear()
|
||||
}
|
||||
list.addAll(records)
|
||||
|
||||
list.addAll(mergedList)
|
||||
dishAdapter.notifyDataSetChanged()
|
||||
val isLoadMoreEnable = records.size >= pageSize
|
||||
val isLoadMoreEnable = (records?.size ?: 0) >= pageSize
|
||||
binding.refreshLayout.setEnableLoadMore(isLoadMoreEnable)
|
||||
if (isLoadMoreEnable) {
|
||||
pageNo++
|
||||
}
|
||||
refreshLocalData(list)
|
||||
if (isLoadMoreEnable) pageNo++
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ import com.google.android.flexbox.FlexWrap
|
||||
import com.google.android.flexbox.FlexboxLayoutManager
|
||||
import com.shuwei.dish.match.adapter.Seasoning18GridAdapter
|
||||
import com.shuwei.dish.match.adapter.Seasoning22GridAdapter
|
||||
import com.shuwei.dish.match.base.BaseApp
|
||||
import com.shuwei.dish.match.base.BaseFragment
|
||||
import com.shuwei.dish.match.base.DeviceRole
|
||||
import com.shuwei.dish.match.base.GlobalData
|
||||
@@ -29,9 +28,7 @@ import com.shuwei.dish.match.ui.SingleFragmentActivity
|
||||
import com.shuwei.dish.match.utils.SizeTool
|
||||
import com.shuwei.dish.match.utils.WeightUtil
|
||||
import com.shuwei.dish.match.utils.ext.dp
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class SeasoningConfigFragment : BaseFragment<FragmentSeasoningConfigBinding>() {
|
||||
|
||||
@@ -51,7 +48,7 @@ class SeasoningConfigFragment : BaseFragment<FragmentSeasoningConfigBinding>() {
|
||||
) = FragmentSeasoningConfigBinding.inflate(inflater, container, false)
|
||||
|
||||
private lateinit var currentActivity: SingleFragmentActivity
|
||||
// private lateinit var appViewModel: AppViewModel
|
||||
// private lateinit var appViewModel: DbViewModel
|
||||
|
||||
private val adapter22 by lazy { buildAdapter22() }
|
||||
private val adapter18 by lazy {
|
||||
@@ -149,11 +146,10 @@ class SeasoningConfigFragment : BaseFragment<FragmentSeasoningConfigBinding>() {
|
||||
* 仅主设备执行广播,子设备不调用此方法
|
||||
*/
|
||||
private fun saveSlotAndBroadcast(slot: SeasoningSlotEntity) {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val dao = BaseApp.instance!!.database.seasoningSlotDao()
|
||||
dao.upsert(slot)
|
||||
lifecycleScope.launch {
|
||||
currentActivity.appViewModel.upsertSeasoningSlot(slot)
|
||||
// 读取全量配置,通过 wsClient 推送给所有已连接子设备
|
||||
val allSlots = dao.queryAll().map {
|
||||
val allSlots = currentActivity.appViewModel.loadSeasoningSlot().map {
|
||||
SlotConfig(it.deviceId, it.address, it.goodsId, it.goodsName)
|
||||
}
|
||||
ScaleServiceManager.sendSeasoningConfig(allSlots)
|
||||
@@ -162,8 +158,8 @@ class SeasoningConfigFragment : BaseFragment<FragmentSeasoningConfigBinding>() {
|
||||
|
||||
// /** 初始化 ViewModel */
|
||||
// private fun initViewModel() {
|
||||
// val factory = AppFactory(AppRepository(BaseApp.instance!!.database.appDao()))
|
||||
// appViewModel = ViewModelProvider(this, factory)[AppViewModel::class.java]
|
||||
// val factory = AppFactory(DbRepository(BaseApp.instance!!.database.appDao()))
|
||||
// appViewModel = ViewModelProvider(this, factory)[DbViewModel::class.java]
|
||||
// }
|
||||
|
||||
|
||||
@@ -205,12 +201,10 @@ class SeasoningConfigFragment : BaseFragment<FragmentSeasoningConfigBinding>() {
|
||||
private fun loadData() {
|
||||
adapter22.update(emptyList())
|
||||
adapter18.update(emptyList())
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val dao = BaseApp.instance!!.database.seasoningSlotDao()
|
||||
val slots22 = dao.queryByDeviceId(ScaleDeviceConfig.DEVICE_ID_22)
|
||||
val slots18 = dao.queryByDeviceId(ScaleDeviceConfig.DEVICE_ID_18)
|
||||
val slotsOil = dao.queryByDeviceId(ScaleDeviceConfig.DEVICE_ID_1)
|
||||
withContext(Dispatchers.Main) {
|
||||
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)
|
||||
slots22.forEach { slot ->
|
||||
val pos = ScaleDeviceConfig.SCALE_ORDER_22.indexOf(slot.address)
|
||||
if (pos >= 0) adapter22.updateItemName(pos, slot.goodsName)
|
||||
@@ -225,7 +219,6 @@ class SeasoningConfigFragment : BaseFragment<FragmentSeasoningConfigBinding>() {
|
||||
if (oilSlot != null && oilSlot.goodsName.isNotEmpty()) oilSlot.goodsName else "-"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册重量监听,检测重量增加超过阈值的秤,高亮对应格子并通知主设备
|
||||
|
||||
@@ -7,7 +7,8 @@ import android.view.inputmethod.InputMethodManager
|
||||
|
||||
object KeyboardUtil {
|
||||
|
||||
fun hideKeyboard(context: Context, view: View) {
|
||||
fun hideKeyboard(view: View) {
|
||||
val context = view.context
|
||||
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
imm.hideSoftInputFromWindow(view.windowToken, 0)
|
||||
view.clearFocus() // 清除焦点避免键盘再次弹出
|
||||
|
||||
@@ -1,217 +0,0 @@
|
||||
package com.shuwei.dish.match.viewmodel
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.shuwei.dish.match.db.AppRepository
|
||||
import com.shuwei.dish.match.entity.CookFoodEntity
|
||||
import com.shuwei.dish.match.entity.CookFoodGoodsEntity
|
||||
import com.shuwei.dish.match.entity.SeasoningEntity
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.collections.forEach
|
||||
|
||||
class AppViewModel(private val rep: AppRepository) : ViewModel() {
|
||||
|
||||
fun updateCookFood(entity: CookFoodEntity) {
|
||||
viewModelScope.launch {
|
||||
rep.updateCookFood(entity)
|
||||
}
|
||||
}
|
||||
|
||||
fun getCookFoodById(foodId: String, cookMode: Int, action: (CookFoodEntity?) -> Unit) {
|
||||
viewModelScope.launch {
|
||||
val data = rep.getCookFoodById(foodId, cookMode)
|
||||
action(data)
|
||||
}
|
||||
}
|
||||
|
||||
fun getCookFoodList(
|
||||
cookMode: Int,
|
||||
dinnerType: String = "0",
|
||||
action: (MutableList<CookFoodEntity>?) -> Unit
|
||||
) {
|
||||
viewModelScope.launch {
|
||||
val data = rep.getCookFoodList(cookMode, dinnerType)
|
||||
action(data)
|
||||
}
|
||||
}
|
||||
|
||||
fun countCookFood(cookMode: Int, action: (Int) -> Unit) {
|
||||
viewModelScope.launch {
|
||||
val count = rep.countCookFood(cookMode)
|
||||
action(count)
|
||||
}
|
||||
}
|
||||
|
||||
// fun saveCookFood(cookMode: Int, entity: CookFoodEntity) {
|
||||
// viewModelScope.launch {
|
||||
// val data = rep.getCookFoodById(entity.foodId, cookMode)
|
||||
// if (data == null) {
|
||||
// rep.insertCookFood(entity)
|
||||
// return@launch
|
||||
// }
|
||||
// rep.updateCookFood(entity)
|
||||
// }
|
||||
// }
|
||||
|
||||
fun saveCookFoodAndGoods(
|
||||
cookMode: Int,
|
||||
entity: CookFoodEntity,
|
||||
list: MutableList<CookFoodGoodsEntity>?,
|
||||
onFinish: () -> Unit
|
||||
) {
|
||||
viewModelScope.launch {
|
||||
val data = rep.getCookFoodById(entity.foodId, cookMode)
|
||||
if (data != null) {
|
||||
//存在数据删除
|
||||
rep.deleteCookFood(entity.foodId, cookMode)
|
||||
rep.deleteCookFoodGoodsList(data.id, entity.foodId)
|
||||
}
|
||||
//重新保存数据
|
||||
rep.insertCookFood(entity)
|
||||
val newData = rep.getCookFoodById(entity.foodId, cookMode)
|
||||
list?.let { it ->
|
||||
it.forEach { goods ->
|
||||
goods.id = 0
|
||||
goods.pid = newData?.id?:0
|
||||
}
|
||||
rep.insertGoodsList(it)
|
||||
}
|
||||
onFinish()
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteCookFoodAndGoods(
|
||||
cookMode: Int,
|
||||
foodId: String,
|
||||
onFinish: () -> Unit
|
||||
) {
|
||||
viewModelScope.launch {
|
||||
val data = rep.getCookFoodById(foodId, cookMode)
|
||||
if (data != null) {
|
||||
rep.deleteCookFood(foodId = foodId, cookMode = cookMode)
|
||||
rep.deleteCookFoodGoodsList(pid = data.id, foodId = foodId)
|
||||
}
|
||||
onFinish()
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
fun getCookFoodGoodsList(
|
||||
foodId: String,
|
||||
cookMode: Int,
|
||||
action: (list: MutableList<CookFoodGoodsEntity>) -> Unit
|
||||
) {
|
||||
viewModelScope.launch {
|
||||
val cookFood = rep.getCookFoodById(foodId, cookMode)
|
||||
cookFood?.let {
|
||||
val list = rep.getCookFoodGoodsList(pid = it.id, foodId = it.foodId)
|
||||
action(list)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fun updateGoods(entity: CookFoodGoodsEntity) {
|
||||
// viewModelScope.launch {
|
||||
// rep.updateGoods(entity)
|
||||
// }
|
||||
// }
|
||||
|
||||
// fun saveCookFoodGoods(list: MutableList<CookFoodGoodsEntity>) {
|
||||
// viewModelScope.launch {
|
||||
// val foodId = list[0].foodId
|
||||
// val data: MutableList<CookFoodGoodsEntity>? =
|
||||
// rep.getCookFoodGoodsList(foodId!!)
|
||||
// if (data.isNullOrEmpty()) {
|
||||
// rep.insertGoodsList(list)
|
||||
// return@launch
|
||||
// }
|
||||
// val localDbSeasoningList = rep.getCookFoodGoodsListByType(foodId, 3)
|
||||
// localDbSeasoningList.forEach {
|
||||
// it.isDel = 1
|
||||
// //更新本地调料数据为已删除的状态
|
||||
// rep.updateGoods(it)
|
||||
// }
|
||||
// //筛选出调料数据保存,主辅材不会变更不需要再次处理
|
||||
// val saveSeasoningList = list.filter { it.materialType == 3 }
|
||||
// rep.insertGoodsList(saveSeasoningList.toMutableList())
|
||||
// }
|
||||
// }
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
// fun addSeasoning(list: MutableList<SeasoningEntity>, callback: () -> Unit) {
|
||||
// viewModelScope.launch {
|
||||
// rep.deleteBatch()
|
||||
// rep.insertSeasoningList(items = list)
|
||||
// callback()
|
||||
// }
|
||||
// }
|
||||
|
||||
private var isProcessing = false
|
||||
fun loadSeasoning(action: (MutableList<SeasoningEntity>) -> Unit) {
|
||||
viewModelScope.launch {
|
||||
if (isProcessing) return@launch
|
||||
isProcessing = true
|
||||
val list = rep.getAllStream()
|
||||
action(list)
|
||||
isProcessing = false
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteSeasoningBySort(sort: Int) {
|
||||
viewModelScope.launch {
|
||||
rep.deleteSeasoningBySort(sort)
|
||||
}
|
||||
}
|
||||
|
||||
fun clearAllSeasoning(action:()->Unit) {
|
||||
viewModelScope.launch {
|
||||
rep.clearAllSeasoning()
|
||||
action()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询指定设备是否已配置调料槽位
|
||||
* @param deviceId 目标设备 ID
|
||||
* @param action 回调,true 表示已配置,false 表示未配置
|
||||
*/
|
||||
fun hasSeasoningSlotConfig(deviceId: String, action: (Boolean) -> Unit) {
|
||||
viewModelScope.launch {
|
||||
action(rep.hasSeasoningSlotConfig(deviceId))
|
||||
}
|
||||
}
|
||||
|
||||
// fun updateAll(list: MutableList<SeasoningEntity>) {
|
||||
// viewModelScope.launch {
|
||||
// list.forEach {
|
||||
// rep.updateSeasoning(it)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
fun saveSeasoning(entity: SeasoningEntity, block: () -> Unit) {
|
||||
viewModelScope.launch {
|
||||
val list = rep.getSeasoningBySort(entity.sort)
|
||||
val size = list?.size?:0
|
||||
if (size == 1) {
|
||||
rep.updateSeasoning(entity.also { it.id = list!![0].id })
|
||||
block()
|
||||
return@launch
|
||||
}
|
||||
if (size > 1) {
|
||||
list?.forEach {
|
||||
rep.deleteSeasoningBySort(it.sort)
|
||||
}
|
||||
}
|
||||
entity.id = 0
|
||||
val id = rep.insertSeasoning(entity)
|
||||
entity.id = id
|
||||
block()
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
//package com.shuwei.dish.match.viewmodel
|
||||
//
|
||||
//import androidx.lifecycle.ViewModel
|
||||
//import androidx.lifecycle.viewModelScope
|
||||
//import com.shuwei.dish.match.db.CookFoodGoodsRepository
|
||||
//import com.shuwei.dish.match.entity.CookFoodGoodsEntity
|
||||
//import kotlinx.coroutines.launch
|
||||
//
|
||||
//class CookFoodGoodsViewModel(private val rep: CookFoodGoodsRepository) : ViewModel() {
|
||||
//
|
||||
// fun getCookFoodGoodsList(
|
||||
// foodId: String,
|
||||
// action: (list: MutableList<CookFoodGoodsEntity>) -> Unit
|
||||
// ) {
|
||||
// viewModelScope.launch {
|
||||
// val list = rep.cookFoodGoodsDao.getCookFoodGoodsList(foodId)
|
||||
// action(list)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fun saveCookFoodGoods(list: MutableList<CookFoodGoodsEntity>) {
|
||||
// viewModelScope.launch {
|
||||
// val foodId = list[0].foodId
|
||||
// val data: MutableList<CookFoodGoodsEntity>? =
|
||||
// rep.cookFoodGoodsDao.getCookFoodGoodsList(foodId!!)
|
||||
// if (data.isNullOrEmpty()) {
|
||||
// rep.cookFoodGoodsDao.insertAll(list)
|
||||
// return@launch
|
||||
// }
|
||||
// val localDbSeasoningList = rep.cookFoodGoodsDao.getCookFoodGoodsListByType(foodId, 3)
|
||||
// localDbSeasoningList.forEach {
|
||||
// it.isDel = 1
|
||||
// //更新本地调料数据为已删除的状态
|
||||
// rep.cookFoodGoodsDao.update(it)
|
||||
// }
|
||||
// //筛选出调料数据保存,主辅材不会变更不需要再次处理
|
||||
// val saveSeasoningList = list.filter { it.materialType == 3 }
|
||||
// rep.cookFoodGoodsDao.insertAll(saveSeasoningList.toMutableList())
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//}
|
||||
@@ -1,44 +0,0 @@
|
||||
//package com.shuwei.dish.match.viewmodel
|
||||
//
|
||||
//import androidx.lifecycle.ViewModel
|
||||
//import androidx.lifecycle.viewModelScope
|
||||
//import com.shuwei.dish.match.db.CookFoodRepository
|
||||
//import com.shuwei.dish.match.entity.CookFoodEntity
|
||||
//import kotlinx.coroutines.launch
|
||||
//
|
||||
//class CookFoodViewModel(private val rep: CookFoodRepository) : ViewModel() {
|
||||
//
|
||||
// fun getCookFoodById(foodId: String, cookMode: Int, action: (CookFoodEntity?) -> Unit) {
|
||||
// viewModelScope.launch {
|
||||
// val data = rep.cookFoodDao.getCookFoodById(foodId, cookMode)
|
||||
// action(data)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fun getCookFoodList(cookMode: Int, action: (MutableList<CookFoodEntity>?) -> Unit) {
|
||||
// viewModelScope.launch {
|
||||
// val data = rep.cookFoodDao.getCookFoodList(cookMode)
|
||||
// action(data)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fun countCookFood(cookMode: Int, action: (Int) -> Unit) {
|
||||
// viewModelScope.launch {
|
||||
// val count = rep.cookFoodDao.countCookFood(cookMode)
|
||||
// action(count)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fun saveCookFood(cookMode: Int, entity: CookFoodEntity) {
|
||||
// viewModelScope.launch {
|
||||
// val data = rep.cookFoodDao.getCookFoodById(entity.foodId, cookMode)
|
||||
// if (data == null) {
|
||||
// rep.cookFoodDao.insert(entity)
|
||||
// return@launch
|
||||
// }
|
||||
// rep.cookFoodDao.update(entity)
|
||||
//
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//}
|
||||
@@ -1,47 +0,0 @@
|
||||
//package com.shuwei.dish.match.viewmodel
|
||||
//
|
||||
//import androidx.lifecycle.ViewModel
|
||||
//import androidx.lifecycle.viewModelScope
|
||||
//import com.shuwei.dish.match.db.SeasoningRepository
|
||||
//import com.shuwei.dish.match.entity.SeasoningEntity
|
||||
//import kotlinx.coroutines.delay
|
||||
//import kotlinx.coroutines.launch
|
||||
//
|
||||
//class DeviceSettingViewModel(private val rep: SeasoningRepository) : ViewModel() {
|
||||
// fun addSeasoning(list: MutableList<SeasoningEntity>, callback:()-> Unit) {
|
||||
// viewModelScope.launch {
|
||||
// rep.seasoningDao.deleteBatch()
|
||||
// delay(500)
|
||||
// val rows: Array<Long>? = rep.seasoningDao.insertAll(items = list)
|
||||
// if (rows.isNullOrEmpty().not()) {
|
||||
// callback()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private var isProcessing = false
|
||||
// fun loadSeasoning(action: (list: MutableList<SeasoningEntity>) -> Unit) {
|
||||
// viewModelScope.launch {
|
||||
// if (isProcessing) return@launch
|
||||
// isProcessing = true
|
||||
// rep.seasoningDao.getAllStream().collect { list ->
|
||||
// action(list)
|
||||
// isProcessing = false
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fun deleteAll() {
|
||||
// viewModelScope.launch {
|
||||
// rep.seasoningDao.deleteBatch()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fun updateAll(list: MutableList<SeasoningEntity>) {
|
||||
// viewModelScope.launch {
|
||||
// list.forEach {
|
||||
// rep.seasoningDao.update(it)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@@ -1,24 +0,0 @@
|
||||
//package com.shuwei.dish.match.viewmodel
|
||||
//
|
||||
//import androidx.lifecycle.ViewModel
|
||||
//import androidx.lifecycle.viewModelScope
|
||||
//import com.shuwei.dish.match.db.SeasoningRepository
|
||||
//import com.shuwei.dish.match.entity.CookFoodEntity
|
||||
//import com.shuwei.dish.match.entity.SeasoningEntity
|
||||
//import kotlinx.coroutines.launch
|
||||
//
|
||||
//class SubmitDishViewModel(private val rep: SeasoningRepository) : ViewModel() {
|
||||
//
|
||||
// private var isProcessing = false
|
||||
// fun loadSeasoning(action: (list: MutableList<SeasoningEntity>) -> Unit) {
|
||||
// viewModelScope.launch {
|
||||
// if (isProcessing) return@launch
|
||||
// isProcessing = true
|
||||
// rep.seasoningDao.getAllStream().collect { list ->
|
||||
// action(list)
|
||||
// isProcessing = false
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//}
|
||||
@@ -1,44 +0,0 @@
|
||||
package com.shuwei.dish.match.viewmodel.factory
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.shuwei.dish.match.db.AppRepository
|
||||
import com.shuwei.dish.match.db.dao.SeasoningSlotDao
|
||||
import com.shuwei.dish.match.viewmodel.AppViewModel
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
class AppFactory(private val repo: AppRepository) : ViewModelProvider.Factory {
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return AppViewModel(repo) as T
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//@Suppress("UNCHECKED_CAST")
|
||||
//class DeviceSettingFactory(private val repo: SeasoningRepository) : ViewModelProvider.Factory {
|
||||
// override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
// return DeviceSettingViewModel(repo) as T
|
||||
// }
|
||||
//}
|
||||
//
|
||||
////@Suppress("UNCHECKED_CAST")
|
||||
////class SubmitDishFactory(private val repo: SeasoningRepository) : ViewModelProvider.Factory {
|
||||
//// override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
//// return SubmitDishViewModel(repo) as T
|
||||
//// }
|
||||
////}
|
||||
//
|
||||
//@Suppress("UNCHECKED_CAST")
|
||||
//class CookFoodFactory(private val repo: CookFoodRepository) : ViewModelProvider.Factory {
|
||||
// override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
// return CookFoodViewModel(repo) as T
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//@Suppress("UNCHECKED_CAST")
|
||||
//class CookFoodGoodsFactory(private val repo: CookFoodGoodsRepository) : ViewModelProvider.Factory {
|
||||
// override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
// return CookFoodGoodsViewModel(repo) as T
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -1,6 +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"/>
|
||||
<!-- <solid android:color="#FFFF3232"/>-->
|
||||
<solid android:color="@color/dish_green"/>
|
||||
<corners android:radius="12dp"/>
|
||||
</shape>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 拍照按钮背景:圆角矩形,填充色 #00BC71 -->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="#00BC71" />
|
||||
<corners android:radius="12dp" />
|
||||
</shape>
|
||||
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 白色相机图标:外圆环 evenOdd 镂空,机身实心,镜头白色小圆 -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="56dp"
|
||||
android:height="56dp"
|
||||
android:viewportWidth="56"
|
||||
android:viewportHeight="56">
|
||||
|
||||
<!-- 外圆环:大圆 + 小圆 evenOdd,中间透明 -->
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="
|
||||
M28,4
|
||||
A24,24 0 1,1 27.9999,4 Z
|
||||
M28,10
|
||||
A18,18 0 1,0 28.0001,10 Z" />
|
||||
|
||||
<!-- 相机机身:evenOdd 在镜头位置挖透明圆孔 -->
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="
|
||||
M20,22 L22.5,18 L33.5,18 L36,22 L38,22
|
||||
A2,2 0 0,1 40,24 L40,36
|
||||
A2,2 0 0,1 38,38 L18,38
|
||||
A2,2 0 0,1 16,36 L16,24
|
||||
A2,2 0 0,1 18,22 Z
|
||||
M28,23
|
||||
A6,6 0 1,0 28.0001,23 Z" />
|
||||
|
||||
<!-- 镜头中心:白色小圆点 -->
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M28,25.5 A3.5,3.5 0 1,0 28.0001,25.5 Z" />
|
||||
|
||||
</vector>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 红色圆形背景 + 白色 X 图标,用于列表项删除按钮 -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="48dp"
|
||||
android:height="48dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
|
||||
<!-- 红色圆形背景 #FFEE4444 -->
|
||||
<path
|
||||
android:fillColor="#00BC71"
|
||||
android:pathData="M24,2C11.85,2 2,11.85 2,24C2,36.15 11.85,46 24,46C36.15,46 46,36.15 46,24C46,11.85 36.15,2 24,2Z" />
|
||||
|
||||
<!-- 白色 X 图标 -->
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M33,16.41L31.59,15L24,22.59L16.41,15L15,16.41L22.59,24L15,31.59L16.41,33L24,25.41L31.59,33L33,31.59L25.41,24L33,16.41Z" />
|
||||
|
||||
</vector>
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 绿色圆角背景 + 白色垃圾桶图标,替代红色的 ic_delete_red.png -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<!-- 绿色圆角背景 -->
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="#00BC71" />
|
||||
<corners android:radius="10dp" />
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
<!-- 白色垃圾桶图标,居中显示 -->
|
||||
<item
|
||||
android:drawable="@drawable/ic_trash_white"
|
||||
android:gravity="center" />
|
||||
|
||||
</layer-list>
|
||||
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 白色垃圾桶图标:使用 evenOdd 填充规则实现条纹镂空,无硬编码背景色依赖 -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="40dp"
|
||||
android:height="40dp"
|
||||
android:viewportWidth="40"
|
||||
android:viewportHeight="40">
|
||||
|
||||
<!-- 桶盖 -->
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="
|
||||
M10,13 A1,1 0 0,1 10,11 L14,11 L14,9
|
||||
A2,2 0 0,1 16,7 L24,7
|
||||
A2,2 0 0,1 26,9 L26,11 L30,11
|
||||
A1,1 0 0,1 30,13 Z
|
||||
M16,9 L16,11 L24,11 L24,9 Z" />
|
||||
|
||||
<!-- 桶身:外轮廓 + 三条竖槽镂空,evenOdd 使竖槽透明 -->
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="
|
||||
M12,15 L13.5,33
|
||||
A2,2 0 0,0 15.5,35 L24.5,35
|
||||
A2,2 0 0,0 26.5,33 L28,15 Z
|
||||
M17,18 L17,32 L19,32 L19,18 Z
|
||||
M19.5,18 L19.5,32 L21.5,32 L21.5,18 Z
|
||||
M22,18 L22,32 L24,32 L24,18 Z" />
|
||||
|
||||
</vector>
|
||||
@@ -1,7 +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"/>
|
||||
<solid android:color="@color/dish_green"/>
|
||||
<size android:width="10dp" android:height="40dp"/>
|
||||
<corners android:radius="5dp"/>
|
||||
</shape>
|
||||
@@ -0,0 +1,54 @@
|
||||
<?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"
|
||||
tools:background="@color/white"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- 搜索栏 -->
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="100dp"
|
||||
android:layout_marginHorizontal="32dp"
|
||||
android:layout_marginTop="32dp"
|
||||
android:layout_marginBottom="16dp">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/editSearch"
|
||||
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:inputType="text"
|
||||
android:maxLines="1"
|
||||
android:paddingStart="47dp"
|
||||
android:paddingEnd="80dp"
|
||||
android:textColor="@color/black"
|
||||
android:textColorHint="#FFC4CFDA"
|
||||
android:textSize="36sp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/btnSearch"
|
||||
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"
|
||||
tools:ignore="ContentDescription" />
|
||||
</FrameLayout>
|
||||
|
||||
<!-- 已采集食材列表 -->
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rvCollectedFood"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:overScrollMode="never"
|
||||
tools:itemCount="5"
|
||||
tools:listitem="@layout/list_item_collected_food" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -15,7 +15,7 @@
|
||||
android:layout_marginTop="55dp"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:gravity="center"
|
||||
android:textColor="@color/black"
|
||||
android:textColor="@color/black333"
|
||||
android:textSize="36sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginTop="30dp"
|
||||
android:drawablePadding="17dp"
|
||||
android:text="餐品采集"
|
||||
android:text="食材采集"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="36sp"
|
||||
android:textStyle="bold"
|
||||
@@ -35,7 +35,7 @@
|
||||
android:layout_marginEnd="32dp"
|
||||
android:gravity="center_vertical"
|
||||
android:includeFontPadding="false"
|
||||
android:text="已采集餐品"
|
||||
android:text="已采集食材"
|
||||
android:textColor="#ff5e7585"
|
||||
android:textSize="30sp"
|
||||
android:textStyle="bold"
|
||||
@@ -98,15 +98,33 @@
|
||||
android:foreground="@drawable/ripple_effect"/>
|
||||
<!-- android:background="?android:attr/selectableItemBackgroundBorderless"-->
|
||||
|
||||
<ImageView
|
||||
<!-- 拍照按钮:绿色圆角背景 + 相机图标 + 文字 -->
|
||||
<LinearLayout
|
||||
android:id="@+id/btnTakePhoto"
|
||||
android:layout_width="212dp"
|
||||
android:layout_height="155dp"
|
||||
android:src="@drawable/ic_take_photo"
|
||||
android:background="@drawable/bg_take_photo"
|
||||
android:foreground="@drawable/ripple_effect"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintBottom_toBottomOf="@id/flPreview"
|
||||
app:layout_constraintEnd_toEndOf="@id/btnCollectedFood"
|
||||
tools:ignore="ContentDescription"
|
||||
android:foreground="@drawable/ripple_effect"/>
|
||||
app:layout_constraintEnd_toEndOf="@id/btnCollectedFood">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="72dp"
|
||||
android:layout_height="72dp"
|
||||
android:src="@drawable/ic_camera_white"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp"
|
||||
android:text="拍照"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="30sp"
|
||||
android:textStyle="bold" />
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rvFoodList"
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
<?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="wrap_content"
|
||||
tools:background="@color/white"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="32dp"
|
||||
android:paddingVertical="24dp">
|
||||
|
||||
<!-- 食材名称和采集数量 -->
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvFoodName"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="32sp"
|
||||
android:textStyle="bold"
|
||||
tools:text="三河小炒" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvCollectCount"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:textColor="#ff5e7585"
|
||||
android:textSize="26sp"
|
||||
tools:text="已采集153" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 删除按钮 -->
|
||||
<ImageView
|
||||
android:id="@+id/ivDelete"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:padding="25dp"
|
||||
android:src="@drawable/ic_close_red"
|
||||
tools:ignore="ContentDescription" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 分割线 -->
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginHorizontal="32dp"
|
||||
android:background="#FFE8EDF2" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -19,7 +19,7 @@
|
||||
android:layout_height="52dp"
|
||||
android:layout_gravity="end|top"
|
||||
android:padding="6dp"
|
||||
android:src="@drawable/ic_delete_red" />
|
||||
android:src="@drawable/ic_delete_green" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ivFinish"
|
||||
|
||||
Reference in New Issue
Block a user