Show an avatar, description or away message being cleared
Client and channel updates were only applied when the field had a value, since ts3j reads a missing field back as an empty string. A removed avatar, an emptied description or a cleared away message arrives as the field without a value, so they stayed as they were. Such fields are now applied whenever the update carries them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -314,12 +314,12 @@ final class ConnectionEventHandler implements TS3Listener {
|
||||
// Both fields travel together, so an absent message here means "no message"
|
||||
// — which `has` cannot tell from "not reported".
|
||||
c.awayMessage = c.away ? TeamspeakConnection.orEmpty(e.get("client_away_message")) : "";
|
||||
} else if (has(e, "client_away_message")) {
|
||||
c.awayMessage = e.get("client_away_message");
|
||||
} else if (reported(e, "client_away_message")) {
|
||||
c.awayMessage = TeamspeakConnection.orEmpty(e.get("client_away_message"));
|
||||
}
|
||||
if (has(e, "client_talk_power")) c.talkPower = e.getInt("client_talk_power");
|
||||
if (has(e, "client_description")) {
|
||||
c.description = e.get("client_description");
|
||||
if (reported(e, "client_description")) {
|
||||
c.description = TeamspeakConnection.orEmpty(e.get("client_description"));
|
||||
conn.ui.onInfoUpdated();
|
||||
}
|
||||
// The answer to clientgetvariables.
|
||||
@@ -330,7 +330,7 @@ final class ConnectionEventHandler implements TS3Listener {
|
||||
}
|
||||
if (has(e, "client_is_channel_commander"))
|
||||
c.channelCommander = e.getBoolean("client_is_channel_commander");
|
||||
if (has(e, "client_flag_avatar")) c.avatarFlag = TeamspeakConnection.orEmpty(e.get("client_flag_avatar"));
|
||||
if (reported(e, "client_flag_avatar")) c.avatarFlag = TeamspeakConnection.orEmpty(e.get("client_flag_avatar"));
|
||||
announceClientUpdate(e, c, renamed, oldName);
|
||||
conn.ui.onModelChanged();
|
||||
}
|
||||
@@ -398,7 +398,7 @@ final class ConnectionEventHandler implements TS3Listener {
|
||||
ChannelNode ch = conn.getModel().getChannel(safeInt(e, "cid"));
|
||||
if (ch == null) return;
|
||||
// The answer to channelgetdescription; an empty description comes as a bare key.
|
||||
if (e.getMap().containsKey("channel_description")) {
|
||||
if (reported(e, "channel_description")) {
|
||||
ch.description = TeamspeakConnection.orEmpty(e.get("channel_description"));
|
||||
ch.descriptionLoaded = true;
|
||||
conn.ui.onInfoUpdated();
|
||||
@@ -425,7 +425,7 @@ final class ConnectionEventHandler implements TS3Listener {
|
||||
private static void applyChannelProperties(ChannelNode ch, BaseEvent e) {
|
||||
if (has(e, "channel_name")) ch.name = e.get("channel_name");
|
||||
// An emptied topic arrives as a bare key, which has() would skip.
|
||||
if (e.getMap().containsKey("channel_topic")) ch.topic = TeamspeakConnection.orEmpty(e.get("channel_topic"));
|
||||
if (reported(e, "channel_topic")) ch.topic = TeamspeakConnection.orEmpty(e.get("channel_topic"));
|
||||
if (has(e, "channel_icon_id")) ch.iconId = TeamspeakConnection.safeLong(e, "channel_icon_id");
|
||||
if (has(e, "channel_flag_password")) ch.hasPassword = e.getBoolean("channel_flag_password");
|
||||
if (has(e, "channel_flag_permanent")) ch.permanent = e.getBoolean("channel_flag_permanent");
|
||||
@@ -681,6 +681,11 @@ final class ConnectionEventHandler implements TS3Listener {
|
||||
return value != null && !value.isEmpty();
|
||||
}
|
||||
|
||||
/** Whether the event carries a field at all, even empty: for text that can be cleared. */
|
||||
private static boolean reported(BaseEvent e, String key) {
|
||||
return e.getMap().containsKey(key);
|
||||
}
|
||||
|
||||
/** Parses a comma-separated id list (e.g. server groups "6,12,15"). */
|
||||
private static int[] parseIntList(String csv) {
|
||||
if (csv == null || csv.isEmpty()) return new int[0];
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
package com.ts3client.net;
|
||||
|
||||
import com.github.manevolent.ts3j.command.MultiCommand;
|
||||
import com.github.manevolent.ts3j.event.ClientUpdatedEvent;
|
||||
import com.github.manevolent.ts3j.protocol.ProtocolRole;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* Pins the ts3j behaviour {@code ConnectionEventHandler.has(...)} exists for: a field
|
||||
@@ -22,4 +26,15 @@ class EventFieldsTest {
|
||||
assertEquals("", e.get("client_is_recording"));
|
||||
assertEquals("", e.get("client_nickname"));
|
||||
}
|
||||
|
||||
/** What {@code reported(...)} relies on: a cleared field still arrives, just without a value. */
|
||||
@Test
|
||||
void clearedFieldsAreStillInTheMap() {
|
||||
Map<String, String> fields = MultiCommand.parse(ProtocolRole.SERVER,
|
||||
"notifyclientupdated clid=7 client_flag_avatar client_description=").simplifyOne().toMap();
|
||||
ClientUpdatedEvent e = new ClientUpdatedEvent(fields);
|
||||
assertTrue(e.getMap().containsKey("client_flag_avatar"));
|
||||
assertTrue(e.getMap().containsKey("client_description"));
|
||||
assertFalse(e.getMap().containsKey("client_away_message"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user