Manage identities on Android, pick one per bookmark, and give identities their own nicknames
Settings -> Identities lists them and creates, imports (an identity file or a TeamSpeak 3 settings.db), exports, renames and removes them, picks the default and improves an identity's security level; the search runs on until reached or stopped, whichever page is on screen. The Connect screen and each bookmark choose the identity to connect with. An identity keeps a nickname and phonetic nickname, in TeamSpeak's own INI keys, on both clients. A connect goes by the bookmark's nickname, else the identity's, else the global one; the phonetic one is sent in clientinit. Imported bookmarks no longer copy their identity's nickname. IdentityStore is now safe to share with the thread a connect resolves its identity on, and imports and exports through streams for Android's document picker. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -31,6 +31,8 @@ import java.awt.Frame;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.Insets;
|
||||
import java.awt.event.FocusAdapter;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.io.File;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Consumer;
|
||||
@@ -53,6 +55,10 @@ public final class IdentitiesDialog extends JDialog {
|
||||
private final JTextField nameField = new JTextField();
|
||||
private final JTextField uidField = new JTextField();
|
||||
private final JTextField levelField = new JTextField();
|
||||
private final JTextField nicknameField = new JTextField();
|
||||
private final JTextField phoneticField = new JTextField();
|
||||
/** The identity the nickname fields belong to, which the list may already have moved off. */
|
||||
private IdentityEntry shown;
|
||||
|
||||
public IdentitiesDialog(Frame owner, IdentityStore identities, Settings settings,
|
||||
Bookmarks bookmarks, Runnable onChanged) {
|
||||
@@ -124,6 +130,19 @@ public final class IdentitiesDialog extends JDialog {
|
||||
addRow(form, c, row++, "Name:", nameField);
|
||||
addRow(form, c, row++, "Unique ID:", uidField);
|
||||
addRow(form, c, row++, "Security level:", levelField);
|
||||
addRow(form, c, row++, "Nickname:", nicknameField);
|
||||
addRow(form, c, row++, "Phonetic nickname:", phoneticField);
|
||||
|
||||
nicknameField.setToolTipText("Empty: the global nickname");
|
||||
for (JTextField field : new JTextField[]{nicknameField, phoneticField}) {
|
||||
field.addActionListener(e -> applyNicknames());
|
||||
field.addFocusListener(new FocusAdapter() {
|
||||
@Override
|
||||
public void focusLost(FocusEvent e) {
|
||||
applyNicknames();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
c.gridx = 0;
|
||||
c.gridy = row;
|
||||
@@ -172,13 +191,39 @@ public final class IdentitiesDialog extends JDialog {
|
||||
}
|
||||
|
||||
private void showDetails(IdentityEntry e) {
|
||||
applyNicknames();
|
||||
shown = e;
|
||||
nicknameField.setEnabled(e != null);
|
||||
phoneticField.setEnabled(e != null);
|
||||
nicknameField.setText(e == null ? "" : e.getNickname());
|
||||
phoneticField.setText(e == null ? "" : e.getPhoneticNickname());
|
||||
nameField.setText(e == null ? "" : e.getName());
|
||||
uidField.setText(e == null ? "" : e.getUniqueId());
|
||||
levelField.setText(e == null ? "" : Integer.toString(e.getSecurityLevel()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
// Escape closes without the field losing focus first.
|
||||
applyNicknames();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
// ---- actions ----
|
||||
|
||||
private void applyNicknames() {
|
||||
IdentityEntry e = shown;
|
||||
if (e == null || identities.byId(e.getId()) == null) return;
|
||||
String nickname = nicknameField.getText().trim();
|
||||
String phonetic = phoneticField.getText().trim();
|
||||
if (nickname.equals(e.getNickname()) && phonetic.equals(e.getPhoneticNickname())) return;
|
||||
try {
|
||||
identities.setNicknames(e, nickname, phonetic);
|
||||
} catch (Exception ex) {
|
||||
error("Could not save the nicknames", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void newIdentity() {
|
||||
String name = JOptionPane.showInputDialog(this, "Name for the new identity:", "New identity");
|
||||
if (name == null || name.trim().isEmpty()) return;
|
||||
|
||||
@@ -640,7 +640,7 @@ public final class MainFrame extends JFrame implements ServerTabPane.Listener {
|
||||
private void startConnection(String address, int port, String nickname, String password, String identityId,
|
||||
String channel, String channelPassword, boolean replaceCurrent) {
|
||||
settings.lastAddress = address + ":" + port;
|
||||
settings.nickname = nickname;
|
||||
if (!nickname.isBlank()) settings.nickname = nickname;
|
||||
settings.serverPassword = password;
|
||||
settings.save();
|
||||
|
||||
@@ -653,8 +653,7 @@ public final class MainFrame extends JFrame implements ServerTabPane.Listener {
|
||||
|
||||
/** Connects on the current tab, leaving whatever server it is on. */
|
||||
private void connectToBookmark(Bookmark b) {
|
||||
String nick = (b.nickname != null && !b.nickname.isBlank()) ? b.nickname : settings.nickname;
|
||||
startConnection(b.address, b.port, nick, b.password, b.identityId, b.channel, b.channelPassword, true);
|
||||
startConnection(b.address, b.port, b.nickname == null ? "" : b.nickname, b.password, b.identityId, b.channel, b.channelPassword, true);
|
||||
}
|
||||
|
||||
private void addCurrentServerBookmark() {
|
||||
|
||||
Reference in New Issue
Block a user