Initial commit: TS3J TeamSpeak 3 Java client
Swing desktop client (core/desktop/swing Maven modules) built on the ts3j protocol library, included as a submodule. Native Opus voice with voice-activation detection, push-to-talk, and audio pre-processing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
100
ts3-client/swing/src/main/java/com/ts3client/ui/InfoPanel.java
Normal file
100
ts3-client/swing/src/main/java/com/ts3client/ui/InfoPanel.java
Normal file
@@ -0,0 +1,100 @@
|
||||
package com.ts3client.ui;
|
||||
|
||||
import com.ts3client.net.ChannelNode;
|
||||
import com.ts3client.net.ClientEntry;
|
||||
import com.ts3client.net.ServerModel;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JEditorPane;
|
||||
import javax.swing.JScrollPane;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Read-only detail view for the currently selected channel or client, mirroring
|
||||
* the TeamSpeak 3 info box: channel topic/description, or a client's server and
|
||||
* channel groups, platform and version.
|
||||
*/
|
||||
public final class InfoPanel extends JScrollPane {
|
||||
|
||||
private final JEditorPane pane = new JEditorPane();
|
||||
|
||||
public InfoPanel() {
|
||||
pane.setContentType("text/html");
|
||||
pane.setEditable(false);
|
||||
pane.setBackground(Theme.CHAT_BG);
|
||||
pane.setBorder(BorderFactory.createEmptyBorder(6, 8, 6, 8));
|
||||
setViewportView(pane);
|
||||
setBorder(BorderFactory.createLineBorder(new java.awt.Color(0xD0D0D0)));
|
||||
clear();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
setHtml("<i style='color:#8a8a8a'>Select a channel or client to see details.</i>");
|
||||
}
|
||||
|
||||
public void showChannel(ChannelNode ch) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(heading(esc(ch.name)));
|
||||
row(sb, "Type", ch.permanent ? "Permanent" : "Temporary");
|
||||
if (ch.maxClients >= 0) row(sb, "Max clients", Integer.toString(ch.maxClients));
|
||||
if (ch.hasPassword) row(sb, "Password", "protected");
|
||||
if (!ch.topic.isEmpty()) row(sb, "Topic", esc(ch.topic));
|
||||
sb.append("<hr>");
|
||||
if (ch.description != null && !ch.description.isEmpty()) {
|
||||
sb.append("<div>").append(multiline(ch.description)).append("</div>");
|
||||
} else if (ch.descriptionLoaded) {
|
||||
sb.append("<i style='color:#8a8a8a'>No description.</i>");
|
||||
} else {
|
||||
sb.append("<i style='color:#8a8a8a'>Loading description…</i>");
|
||||
}
|
||||
setHtml(sb.toString());
|
||||
}
|
||||
|
||||
public void showClient(ClientEntry cl, ServerModel model) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(heading(esc(cl.nickname) + (cl.self ? " <span style='color:#8a8a8a'>(you)</span>" : "")));
|
||||
|
||||
List<String> serverGroups = model.serverGroupNames(cl.serverGroupIds);
|
||||
row(sb, "Server groups", serverGroups.isEmpty() ? "—" : esc(String.join(", ", serverGroups)));
|
||||
|
||||
String channelGroup = model.channelGroupName(cl.channelGroupId);
|
||||
row(sb, "Channel group", channelGroup != null ? esc(channelGroup) : "#" + cl.channelGroupId);
|
||||
|
||||
if (cl.talkPower != 0) row(sb, "Talk power", Integer.toString(cl.talkPower));
|
||||
if (!cl.platform.isEmpty()) row(sb, "Platform", esc(cl.platform));
|
||||
if (!cl.version.isEmpty()) row(sb, "Version", esc(cl.version));
|
||||
if (cl.away) row(sb, "Status", "Away");
|
||||
if (cl.inputMuted) row(sb, "Microphone", "muted");
|
||||
if (cl.outputMuted) row(sb, "Speakers", "muted");
|
||||
if (!cl.uniqueId.isEmpty()) row(sb, "Unique ID", esc(cl.uniqueId));
|
||||
|
||||
if (cl.description != null && !cl.description.isEmpty()) {
|
||||
sb.append("<hr><div>").append(multiline(cl.description)).append("</div>");
|
||||
}
|
||||
setHtml(sb.toString());
|
||||
}
|
||||
|
||||
private void setHtml(String body) {
|
||||
pane.setText("<html><body style='font-family:sans-serif;font-size:11px;color:#202020'>"
|
||||
+ body + "</body></html>");
|
||||
pane.setCaretPosition(0);
|
||||
}
|
||||
|
||||
private static String heading(String text) {
|
||||
return "<div style='font-weight:bold;font-size:13px;margin-bottom:4px'>" + text + "</div>";
|
||||
}
|
||||
|
||||
private static void row(StringBuilder sb, String label, String value) {
|
||||
sb.append("<div style='margin:1px 0'><span style='color:#5a6b7b'>")
|
||||
.append(label).append(":</span> ").append(value).append("</div>");
|
||||
}
|
||||
|
||||
private static String multiline(String text) {
|
||||
return esc(text).replace("\n", "<br>");
|
||||
}
|
||||
|
||||
private static String esc(String s) {
|
||||
if (s == null) return "";
|
||||
return s.replace("&", "&").replace("<", "<").replace(">", ">");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user