Show all of a contact's options at once on desktop
The contacts window drops its tabs for one column of short groups beside the list: contact type, display and ignore, where whisper becomes a "Deny whisper" box, since allowing is the default. The names get their labels on a line of their own, and the window is never shorter than the options, leaving the list the only thing that scrolls. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,7 @@ import com.ts3client.contacts.NicknameDisplay;
|
||||
import com.ts3client.teamspeak.TeamSpeakSettingsDb;
|
||||
import com.ts3client.text.TsLink;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.ButtonGroup;
|
||||
@@ -24,7 +25,6 @@ import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.JRadioButton;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTabbedPane;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.JTree;
|
||||
import javax.swing.KeyStroke;
|
||||
@@ -59,10 +59,10 @@ import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* The contact list window, laid out like TeamSpeak's Contacts: the contacts grouped
|
||||
* as friends, blocked and neutral on the left, and on the right the selected one's
|
||||
* custom nickname and its General / Display / Ignore / Whisper pages. Every edit is
|
||||
* stored as it is made.
|
||||
* The contact list window: the contacts grouped as friends, blocked and neutral on
|
||||
* the left, and on the right all of the selected one's settings — TeamSpeak's
|
||||
* General / Display / Ignore / Whisper pages, in one column rather than as tabs
|
||||
* since each holds only a few options. Every edit is stored as it is made.
|
||||
*
|
||||
* <p>Clients can be dragged in from the server tree — the drag carries the
|
||||
* client's TS3 link, which names its unique id.
|
||||
@@ -98,8 +98,7 @@ final class ContactsDialog extends JDialog {
|
||||
private final JCheckBox ignorePokes = new JCheckBox("Ignore Pokes");
|
||||
private final JCheckBox ignoreAvatar = new JCheckBox("Hide avatar");
|
||||
private final JCheckBox ignoreAway = new JCheckBox("Hide away message");
|
||||
private final JRadioButton allowWhisper = new JRadioButton("Allow whisper");
|
||||
private final JRadioButton denyWhisper = new JRadioButton("Deny whisper");
|
||||
private final JCheckBox denyWhisper = new JCheckBox("Deny whisper");
|
||||
private final JPanel details = new JPanel(new BorderLayout(0, UIScale.scale(8)));
|
||||
|
||||
/** Set while the fields are being filled from a contact, so that does not count as an edit. */
|
||||
@@ -122,7 +121,7 @@ final class ContactsDialog extends JDialog {
|
||||
|
||||
details.setBorder(new ScaledEmptyBorder(8, 4, 8, 8));
|
||||
details.add(buildNicknameRow(), BorderLayout.NORTH);
|
||||
details.add(buildPages(), BorderLayout.CENTER);
|
||||
details.add(buildOptions(), BorderLayout.CENTER);
|
||||
|
||||
JPanel buttons = new JPanel(new BorderLayout());
|
||||
buttons.setBorder(new ScaledEmptyBorder(0, 8, 8, 8));
|
||||
@@ -161,7 +160,8 @@ final class ContactsDialog extends JDialog {
|
||||
Dialogs.closeOnEscape(this);
|
||||
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
|
||||
pack();
|
||||
setMinimumSize(UIScale.scale(new Dimension(620, 400)));
|
||||
// Only the list scrolls, so the window never gets shorter than the options column.
|
||||
setMinimumSize(new Dimension(UIScale.scale(620), getHeight()));
|
||||
setLocationRelativeTo(owner);
|
||||
}
|
||||
|
||||
@@ -299,35 +299,45 @@ final class ContactsDialog extends JDialog {
|
||||
|
||||
// ---- details ----
|
||||
|
||||
/** The names, each label on its own line above its field. */
|
||||
private JComponent buildNicknameRow() {
|
||||
JPanel row = new JPanel(new GridBagLayout());
|
||||
GridBagConstraints c = new GridBagConstraints();
|
||||
c.insets = UIScale.scale(new Insets(2, 2, 2, 2));
|
||||
c.anchor = GridBagConstraints.WEST;
|
||||
c.gridy = 0;
|
||||
c.gridx = 0;
|
||||
c.gridy = 0;
|
||||
c.gridwidth = 2;
|
||||
row.add(new JLabel("Custom Nickname:"), c);
|
||||
c.gridx = 1;
|
||||
|
||||
c.gridy = 1;
|
||||
c.gridwidth = 1;
|
||||
c.weightx = 1;
|
||||
c.fill = GridBagConstraints.HORIZONTAL;
|
||||
nicknameField.setToolTipText("Enter custom nickname");
|
||||
nicknameField.addActionListener(e -> applyNickname());
|
||||
row.add(nicknameField, c);
|
||||
c.gridx = 2;
|
||||
c.gridx = 1;
|
||||
c.weightx = 0;
|
||||
c.fill = GridBagConstraints.NONE;
|
||||
nicknameApply.setToolTipText("Apply nickname change");
|
||||
nicknameApply.addActionListener(e -> applyNickname());
|
||||
row.add(nicknameApply, c);
|
||||
|
||||
c.gridx = 0;
|
||||
c.gridy = 2;
|
||||
c.gridwidth = 2;
|
||||
row.add(new JLabel("Phonetic Nickname:"), c);
|
||||
c.gridy = 3;
|
||||
c.weightx = 1;
|
||||
c.fill = GridBagConstraints.HORIZONTAL;
|
||||
row.add(phoneticField, c);
|
||||
return row;
|
||||
}
|
||||
|
||||
private JComponent buildPages() {
|
||||
JTabbedPane pages = new JTabbedPane();
|
||||
pages.addTab("General", page(
|
||||
radioGroup(neutralRadio, blockedRadio, friendRadio),
|
||||
Box.createVerticalStrut(UIScale.scale(8)),
|
||||
labelled("Phonetic Nickname:", phoneticField)));
|
||||
/** Every option at once, one short group under the other. */
|
||||
private JComponent buildOptions() {
|
||||
JComponent contact = group("Contact", radioGroup(neutralRadio, blockedRadio, friendRadio));
|
||||
neutralRadio.setToolTipText("Mark as neutral");
|
||||
blockedRadio.setToolTipText("Mark as blocked");
|
||||
friendRadio.setToolTipText("Mark as friend");
|
||||
@@ -343,7 +353,7 @@ final class ContactsDialog extends JDialog {
|
||||
}
|
||||
});
|
||||
|
||||
pages.addTab("Display", page(radioGroup(bothRadio, onlyCustomRadio, onlyNicknameRadio)));
|
||||
JComponent display = group("Display", radioGroup(bothRadio, onlyCustomRadio, onlyNicknameRadio));
|
||||
bothRadio.setToolTipText("Show custom name and nickname");
|
||||
onlyCustomRadio.setToolTipText("Show only custom name");
|
||||
onlyNicknameRadio.setToolTipText("Show nickname only");
|
||||
@@ -351,7 +361,8 @@ final class ContactsDialog extends JDialog {
|
||||
onlyCustomRadio.addActionListener(e -> edit(c -> c.nicknameDisplay = NicknameDisplay.ONLY_CUSTOM));
|
||||
onlyNicknameRadio.addActionListener(e -> edit(c -> c.nicknameDisplay = NicknameDisplay.ONLY_NICKNAME));
|
||||
|
||||
pages.addTab("Ignore", page(automute, ignorePublic, ignorePrivate, ignorePokes, ignoreAvatar, ignoreAway));
|
||||
JComponent ignore = group("Ignore", automute, ignorePublic, ignorePrivate, ignorePokes, ignoreAvatar, ignoreAway,
|
||||
denyWhisper);
|
||||
automute.setToolTipText("Automatically mute this person");
|
||||
ignorePublic.setToolTipText("Ignore messages this person sends to the server or in channels");
|
||||
ignorePrivate.setToolTipText("Ignore private chat by this person");
|
||||
@@ -365,26 +376,35 @@ final class ContactsDialog extends JDialog {
|
||||
ignoreAvatar.addActionListener(e -> edit(c -> c.ignoreAvatar = ignoreAvatar.isSelected()));
|
||||
ignoreAway.addActionListener(e -> edit(c -> c.ignoreAwayMessage = ignoreAway.isSelected()));
|
||||
|
||||
pages.addTab("Whisper", page(radioGroup(allowWhisper, denyWhisper)));
|
||||
allowWhisper.setToolTipText("This contact is allowed to whisper to you");
|
||||
denyWhisper.setToolTipText("This contact is always denied to whisper to you.");
|
||||
allowWhisper.addActionListener(e -> edit(c -> c.whisperAllowed = true));
|
||||
denyWhisper.addActionListener(e -> edit(c -> c.whisperAllowed = false));
|
||||
return pages;
|
||||
denyWhisper.setToolTipText("This contact is always denied to whisper to you");
|
||||
denyWhisper.addActionListener(e -> edit(c -> c.whisperAllowed = !denyWhisper.isSelected()));
|
||||
return column(contact, display, ignore);
|
||||
}
|
||||
|
||||
private static JPanel page(Component... rows) {
|
||||
private static JPanel column(JComponent... groups) {
|
||||
JPanel p = new JPanel();
|
||||
p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
|
||||
p.setBorder(new ScaledEmptyBorder(10, 10, 10, 10));
|
||||
for (Component row : rows) {
|
||||
if (row instanceof JComponent) ((JComponent) row).setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||
p.add(row);
|
||||
for (JComponent g : groups) {
|
||||
g.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||
g.setMaximumSize(new Dimension(Integer.MAX_VALUE, g.getPreferredSize().height));
|
||||
p.add(g);
|
||||
p.add(Box.createVerticalStrut(UIScale.scale(6)));
|
||||
}
|
||||
p.add(Box.createVerticalGlue());
|
||||
return p;
|
||||
}
|
||||
|
||||
private static JPanel group(String title, JComponent... rows) {
|
||||
JPanel p = new JPanel();
|
||||
p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
|
||||
p.setBorder(BorderFactory.createTitledBorder(title));
|
||||
for (JComponent row : rows) {
|
||||
row.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||
p.add(row);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
private static JPanel radioGroup(JRadioButton... buttons) {
|
||||
ButtonGroup group = new ButtonGroup();
|
||||
JPanel p = new JPanel();
|
||||
@@ -397,14 +417,6 @@ final class ContactsDialog extends JDialog {
|
||||
return p;
|
||||
}
|
||||
|
||||
private static JPanel labelled(String label, JComponent field) {
|
||||
JPanel p = new JPanel(new BorderLayout(UIScale.scale(6), 0));
|
||||
p.add(new JLabel(label), BorderLayout.WEST);
|
||||
p.add(field, BorderLayout.CENTER);
|
||||
p.setMaximumSize(new Dimension(Integer.MAX_VALUE, field.getPreferredSize().height));
|
||||
return p;
|
||||
}
|
||||
|
||||
/** Fills the right-hand side from the selected contact, or greys it out. */
|
||||
private void showSelected() {
|
||||
Contact c = selectedContact();
|
||||
@@ -429,7 +441,7 @@ final class ContactsDialog extends JDialog {
|
||||
ignorePokes.setSelected(c.ignorePokes);
|
||||
ignoreAvatar.setSelected(c.ignoreAvatar);
|
||||
ignoreAway.setSelected(c.ignoreAwayMessage);
|
||||
(c.whisperAllowed ? allowWhisper : denyWhisper).setSelected(true);
|
||||
denyWhisper.setSelected(!c.whisperAllowed);
|
||||
} finally {
|
||||
filling = false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user