feat(fragment): 实现调料秤重量增加高亮提醒功能

主设备订阅 allScales StateFlow 检测所有子设备秤重量变化,
超过10g且秤稳定时高亮对应格子,15秒后自动恢复
This commit is contained in:
2026-04-17 16:56:36 +08:00
parent 768bde79a1
commit 87bf11454c
9 changed files with 295 additions and 4 deletions
@@ -0,0 +1,20 @@
package com.shuwei.dish.match.scale
/**
* 秤事件数据类,用于子设备向主设备发送非重量类通知
* @param type 事件类型,参见 companion object 中的常量
* @param deviceId 发送方设备 ID
* @param address 触发事件的秤地址
* @param delta 重量变化量(克),仅 TYPE_SEASONING_ADDED 时有意义
*/
data class ScaleEvent(
val type: String,
val deviceId: String,
val address: Int,
val delta: Double = 0.0
) {
companion object {
/** 调料添加事件:某秤重量增加超过阈值 */
const val TYPE_SEASONING_ADDED = "seasoning_added"
}
}
@@ -46,6 +46,26 @@ object ScaleServiceManager {
val allScales: StateFlow<Map<String, ScaleData>>?
get() = aggregator?.allScales
/**
* 收到子设备秤事件(如调料添加)时的回调,仅主设备有效
* 在子线程中调用,需自行切换到主线程更新 UI
*/
private var _onScaleEvent: ((ScaleEvent) -> Unit)? = null
var onScaleEvent: ((ScaleEvent) -> Unit)?
get() = _onScaleEvent
set(value) {
_onScaleEvent = value
wsClient?.onScaleEvent = value
}
/**
* 向主设备广播秤事件(子设备调用)
* @param event 要广播的事件
*/
fun broadcastEvent(event: ScaleEvent) {
wsServer?.broadcastEvent(event)
}
/**
* 主设备连接状态回调(仅子设备使用)
* 设置后会立即转发给 wsServer;需在 start() 之后设置才能生效
@@ -100,6 +120,7 @@ object ScaleServiceManager {
// WebSocket 客户端
val client = ScaleWebSocketClient().also {
it.onScaleData = { data -> aggregator?.onRemoteScaleData(data) }
it.onScaleEvent = { event -> _onScaleEvent?.invoke(event) }
it.onDeviceDisconnected = { remoteId -> aggregator?.removeDevice(remoteId) }
}
wsClient = client
@@ -49,6 +49,9 @@ class ScaleWebSocketClient {
/** 收到秤数据时的回调,在子线程调用 */
var onScaleData: ((data: ScaleData) -> Unit)? = null
/** 收到秤事件(如调料添加通知)时的回调,在子线程调用 */
var onScaleEvent: ((event: ScaleEvent) -> Unit)? = null
/** 设备断线时的回调(连接失败或关闭),在子线程调用 */
var onDeviceDisconnected: ((deviceId: String) -> Unit)? = null
@@ -80,10 +83,17 @@ class ScaleWebSocketClient {
override fun onMessage(webSocket: WebSocket, text: String) {
try {
val data = gson.fromJson(text, ScaleData::class.java)
onScaleData?.invoke(data)
// 通过 type 字段区分 ScaleEvent 与 ScaleData
val raw = gson.fromJson(text, Map::class.java)
if (raw.containsKey("type")) {
val event = gson.fromJson(text, ScaleEvent::class.java)
onScaleEvent?.invoke(event)
} else {
val data = gson.fromJson(text, ScaleData::class.java)
onScaleData?.invoke(data)
}
} catch (e: Exception) {
Log.w(TAG, "解析秤数据失败: ${e.message}")
Log.w(TAG, "解析消息失败: ${e.message}")
}
}
@@ -83,6 +83,14 @@ class ScaleWebSocketServer(private val deviceId: String, private val context: Co
Log.d(TAG, "WebSocket 服务端已停止")
}
/**
* 向所有已连接的主设备广播秤事件(如调料添加通知)
* @param event 要广播的事件
*/
fun broadcastEvent(event: ScaleEvent) {
broadcast(gson.toJson(event))
}
/**
* 向所有已连接客户端广播消息
*/