Add desktop mute toggle button in draft board

Add a setMute WebSocket action and a mute IconButton in the draft
board title bar. The button optimistically flips local state and
rolls back with a toast when the desktop is unreachable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Misaka
2026-06-17 22:12:29 +08:00
parent 2798b5a66a
commit 491513fc5e
3 changed files with 66 additions and 0 deletions

View File

@@ -291,6 +291,34 @@ class ConnectionService : Service() {
return sendAction(socket, "enter", null)
}
fun sendMute(muted: Boolean): Boolean {
Log.d("WTS", "ConnectionService.sendMute muted=$muted connected=${state.connected}")
val socket = currentSocket ?: return false
if (!state.connected) {
return false
}
return sendMuteAction(socket, muted)
}
private fun sendMuteAction(socket: WebSocket, muted: Boolean): Boolean {
val payload = JSONObject()
.put("action", "setMute")
.put("muted", muted)
.toString()
val sent = socket.send(payload)
if (!sent && currentSocket == socket) {
currentSocket = null
updateState(
connected = false,
connecting = false,
lastError = "连接已断开"
)
}
return sent
}
private fun sendAction(socket: WebSocket, action: String, text: String?): Boolean {
val payload = JSONObject()
.put("action", action)

View File

@@ -44,6 +44,11 @@ class MainActivity : FlutterActivity() {
Log.d(tag, "MethodChannel sendEnter")
result.success(ConnectionService.sendEnter())
}
"sendMute" -> {
val muted = call.argument<Boolean>("muted") ?: false
Log.d(tag, "MethodChannel sendMute muted=$muted")
result.success(ConnectionService.sendMute(muted))
}
"getState" -> {
Log.d(tag, "MethodChannel getState")
result.success(ConnectionService.stateMap())

View File

@@ -134,6 +134,13 @@ class NativeConnectionApi {
return result ?? false;
}
Future<bool> sendMute(bool muted) async {
final result = await _methodChannel.invokeMethod<bool>('sendMute', {
'muted': muted,
});
return result ?? false;
}
Future<List<DiscoveredDevice>> startDiscovery() async {
try {
final result = await _methodChannel.invokeListMethod<dynamic>(
@@ -184,6 +191,7 @@ class _InputSyncPageState extends State<InputSyncPage>
bool headerExpanded = true;
bool inputFocused = false;
bool scanning = false;
bool desktopMuted = false;
@override
void initState() {
@@ -265,6 +273,7 @@ class _InputSyncPageState extends State<InputSyncPage>
}
if (!nextState.connected) {
sendButtonState = SendButtonState.idle;
desktopMuted = false;
}
});
@@ -423,6 +432,23 @@ class _InputSyncPageState extends State<InputSyncPage>
}
}
Future<void> _toggleMute() async {
if (!connection.connected) {
return;
}
final nextMuted = !desktopMuted;
setState(() {
desktopMuted = nextMuted;
});
final sent = await api.sendMute(nextMuted);
if (!sent && mounted) {
setState(() {
desktopMuted = !nextMuted;
});
_showToast('发送失败,连接已断开');
}
}
Future<void> _saveHistory(String text) async {
final trimmed = text.trim();
if (trimmed.isEmpty) {
@@ -904,6 +930,13 @@ class _InputSyncPageState extends State<InputSyncPage>
icon: const Icon(Icons.delete_outline),
),
),
IconButton(
tooltip: desktopMuted ? '取消静音' : '静音桌面',
onPressed: connection.connected ? _toggleMute : null,
icon: Icon(
desktopMuted ? Icons.volume_off : Icons.volume_up,
),
),
],
),
),