Show and control channel subscriptions
Track the subscription state from the notifychannelsubscribed events, draw subscribed and unsubscribed channels apart with the pack's icons (and the built-in glyph as a hollow cone), and offer subscribe/unsubscribe entries — channel and family — in the channel context menu. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -17,6 +17,8 @@ public final class ChannelNode {
|
||||
public int maxClients = -1;
|
||||
/** Id of the channel's custom icon in the server's file repository, or 0 for none. */
|
||||
public long iconId;
|
||||
/** Whether the server sends us this channel's client list; set from the subscription events. */
|
||||
public boolean subscribed;
|
||||
|
||||
/** Populated when the tree is rebuilt. */
|
||||
public final List<ChannelNode> children = new ArrayList<>();
|
||||
@@ -26,4 +28,35 @@ public final class ChannelNode {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/** @return whether this channel or any channel below it is subscribed */
|
||||
public boolean anySubscribed() {
|
||||
if (subscribed) return true;
|
||||
for (ChannelNode child : children) {
|
||||
if (child.anySubscribed()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @return whether this channel and every channel below it is subscribed */
|
||||
public boolean allSubscribed() {
|
||||
if (!subscribed) return false;
|
||||
for (ChannelNode child : children) {
|
||||
if (!child.allSubscribed()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @return this channel's id, followed by those of the channels below it when {@code family} */
|
||||
public List<Integer> familyIds(boolean family) {
|
||||
List<Integer> ids = new ArrayList<>();
|
||||
collectIds(family, ids);
|
||||
return ids;
|
||||
}
|
||||
|
||||
private void collectIds(boolean family, List<Integer> into) {
|
||||
into.add(id);
|
||||
if (!family) return;
|
||||
for (ChannelNode child : children) child.collectIds(true, into);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.ts3client.net;
|
||||
|
||||
import com.github.manevolent.ts3j.api.Channel;
|
||||
import com.github.manevolent.ts3j.api.Client;
|
||||
import com.github.manevolent.ts3j.command.MultiCommand;
|
||||
import com.github.manevolent.ts3j.command.SingleCommand;
|
||||
import com.github.manevolent.ts3j.command.parameter.CommandSingleParameter;
|
||||
import com.github.manevolent.ts3j.event.*;
|
||||
@@ -24,6 +25,9 @@ import com.ts3client.sound.SoundNotifier;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Consumer;
|
||||
@@ -534,6 +538,28 @@ public final class TeamspeakConnection implements TS3Listener {
|
||||
}, "ts3j-move-channel").start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribes to (or unsubscribes from) a set of channels in one command. The model
|
||||
* is left alone: the server answers with the subscription events that update it.
|
||||
*/
|
||||
public void setChannelsSubscribed(Collection<Integer> channelIds, boolean subscribed) {
|
||||
if (channelIds.isEmpty()) return;
|
||||
List<Integer> ids = List.copyOf(channelIds);
|
||||
String name = subscribed ? "channelsubscribe" : "channelunsubscribe";
|
||||
new Thread(() -> {
|
||||
try {
|
||||
List<SingleCommand> parts = new ArrayList<>(ids.size());
|
||||
for (int id : ids) {
|
||||
parts.add(new SingleCommand(name, ProtocolRole.CLIENT,
|
||||
new CommandSingleParameter("cid", Integer.toString(id))));
|
||||
}
|
||||
client.executeCommand(new MultiCommand(name, ProtocolRole.CLIENT, parts)).complete();
|
||||
} catch (Exception e) {
|
||||
error((subscribed ? "Could not subscribe: " : "Could not unsubscribe: ") + rootMessage(e));
|
||||
}
|
||||
}, "ts3j-channel-subscribe").start();
|
||||
}
|
||||
|
||||
public void sendChannelMessage(String text) {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
@@ -926,6 +952,23 @@ public final class TeamspeakConnection implements TS3Listener {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChannelSubscribed(ChannelSubscribedEvent e) {
|
||||
setSubscribed(safeInt(e, "cid"), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChannelUnsubscribed(ChannelUnsubscribedEvent e) {
|
||||
setSubscribed(safeInt(e, "cid"), false);
|
||||
}
|
||||
|
||||
private void setSubscribed(int cid, boolean subscribed) {
|
||||
ChannelNode ch = model.getChannel(cid);
|
||||
if (ch == null || ch.subscribed == subscribed) return;
|
||||
ch.subscribed = subscribed;
|
||||
ui.onModelChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServerEdit(ServerEditedEvent e) {
|
||||
if (has(e, "virtualserver_name")) model.setServerName(e.get("virtualserver_name"));
|
||||
|
||||
Reference in New Issue
Block a user