Skip to content

Commit f78570b

Browse files
committed
Improvement for login. Automatic host detection
1 parent 8b511ed commit f78570b

5 files changed

Lines changed: 266 additions & 21 deletions

File tree

modules/BlueskyGephi/src/main/java/fr/totetmatt/blueskygephi/BlueskyGephi.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package fr.totetmatt.blueskygephi;
22

33
import fr.totetmatt.blueskygephi.atproto.AtClient;
4+
import fr.totetmatt.blueskygephi.atproto.AtIdentity;
45
import fr.totetmatt.blueskygephi.atproto.AtProtoException;
56
import fr.totetmatt.blueskygephi.atproto.response.common.Identity;
67
import java.awt.Color;
@@ -96,6 +97,18 @@ public boolean connect(String host,String handle, String password) {
9697
public String getHost(){
9798
return nbPref.get(NBPREF_ATPROTO_HOST,"bsky.social");
9899
}
100+
101+
/**
102+
* Determines the account's PDS host from its handle (unauthenticated), so
103+
* the user can auto-fill the host field. This is a network call and must be
104+
* run off the EDT.
105+
*
106+
* @return the resolved PDS host, e.g. {@code shaggymane.us-west.host.bsky.network}.
107+
* @throws AtProtoException if the handle can't be resolved to a PDS.
108+
*/
109+
public String resolveHostFromHandle(String handle) {
110+
return AtIdentity.resolveHost(handle);
111+
}
99112
public String getHandle() {
100113
return nbPref.get(NBPREF_BSKY_HANDLE, "");
101114
}

modules/BlueskyGephi/src/main/java/fr/totetmatt/blueskygephi/BlueskyGephiMainPanel.form

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -101,20 +101,21 @@
101101
<Component id="credentialsConnectButton" max="32767" attributes="0"/>
102102
<Group type="102" attributes="0">
103103
<Group type="103" groupAlignment="0" attributes="0">
104-
<Component id="credentialsPasswordLabel" alignment="0" min="-2" max="-2" attributes="0"/>
105104
<Component id="credentialsHandleLabel" alignment="0" min="-2" max="-2" attributes="0"/>
105+
<Component id="credentialsHostLabel" alignment="0" min="-2" max="-2" attributes="0"/>
106+
<Component id="credentialsPasswordLabel" alignment="0" min="-2" max="-2" attributes="0"/>
106107
</Group>
107108
<EmptySpace type="separate" max="-2" attributes="0"/>
108109
<Group type="103" groupAlignment="0" attributes="0">
109110
<Component id="credentialsHandleField" pref="263" max="32767" attributes="0"/>
110111
<Component id="credentialsPasswordField" max="32767" attributes="0"/>
112+
<Group type="102" alignment="0" attributes="0">
113+
<Component id="credentialsHostField" pref="263" max="32767" attributes="0"/>
114+
<EmptySpace max="-2" attributes="0"/>
115+
<Component id="credentialsCheckButton" min="-2" max="-2" attributes="0"/>
116+
</Group>
111117
</Group>
112118
</Group>
113-
<Group type="102" alignment="0" attributes="0">
114-
<Component id="credentialsHostLabel" min="-2" max="-2" attributes="0"/>
115-
<EmptySpace min="-2" pref="43" max="-2" attributes="0"/>
116-
<Component id="credentialsHostField" pref="263" max="32767" attributes="0"/>
117-
</Group>
118119
</Group>
119120
<EmptySpace max="-2" attributes="0"/>
120121
</Group>
@@ -125,13 +126,14 @@
125126
<Group type="102" alignment="1" attributes="0">
126127
<EmptySpace min="0" pref="9" max="32767" attributes="0"/>
127128
<Group type="103" groupAlignment="3" attributes="0">
128-
<Component id="credentialsHostLabel" alignment="3" min="-2" max="-2" attributes="0"/>
129-
<Component id="credentialsHostField" alignment="3" min="-2" max="-2" attributes="0"/>
129+
<Component id="credentialsHandleLabel" alignment="3" min="-2" max="-2" attributes="0"/>
130+
<Component id="credentialsHandleField" alignment="3" min="-2" max="-2" attributes="0"/>
130131
</Group>
131132
<EmptySpace type="unrelated" max="-2" attributes="0"/>
132133
<Group type="103" groupAlignment="3" attributes="0">
133-
<Component id="credentialsHandleLabel" alignment="3" min="-2" max="-2" attributes="0"/>
134-
<Component id="credentialsHandleField" alignment="3" min="-2" max="-2" attributes="0"/>
134+
<Component id="credentialsHostLabel" alignment="3" min="-2" max="-2" attributes="0"/>
135+
<Component id="credentialsHostField" alignment="3" min="-2" max="-2" attributes="0"/>
136+
<Component id="credentialsCheckButton" alignment="3" min="-2" max="-2" attributes="0"/>
135137
</Group>
136138
<EmptySpace type="unrelated" max="-2" attributes="0"/>
137139
<Group type="103" groupAlignment="3" attributes="0">
@@ -209,6 +211,19 @@
209211
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="credentialsConnectButtonActionPerformed"/>
210212
</Events>
211213
</Component>
214+
<Component class="javax.swing.JButton" name="credentialsCheckButton">
215+
<Properties>
216+
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
217+
<ResourceString bundle="fr/totetmatt/blueskygephi/Bundle.properties" key="BlueskyGephiMainPanel.credentialsCheckButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
218+
</Property>
219+
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
220+
<ResourceString bundle="fr/totetmatt/blueskygephi/Bundle.properties" key="BlueskyGephiMainPanel.credentialsCheckButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
221+
</Property>
222+
</Properties>
223+
<Events>
224+
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="credentialsCheckButtonActionPerformed"/>
225+
</Events>
226+
</Component>
212227
</SubComponents>
213228
</Container>
214229
<Container class="javax.swing.JScrollPane" name="jScrollPane1">

modules/BlueskyGephi/src/main/java/fr/totetmatt/blueskygephi/BlueskyGephiMainPanel.java

Lines changed: 72 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,21 @@
44
*/
55
package fr.totetmatt.blueskygephi;
66

7+
import fr.totetmatt.blueskygephi.atproto.AtProtoException;
78
import java.awt.Color;
89
import java.awt.Desktop;
910
import java.io.IOException;
1011
import java.net.URI;
1112
import java.util.Arrays;
1213
import java.util.List;
14+
import java.util.concurrent.ExecutionException;
1315
import java.util.logging.Logger;
1416
import java.util.stream.Collectors;
17+
import javax.swing.Icon;
18+
import javax.swing.UIManager;
1519
import org.openide.awt.ActionID;
1620
import org.openide.awt.ActionReference;
21+
import org.openide.awt.NotificationDisplayer;
1722
import org.openide.util.Exceptions;
1823
import org.openide.util.Lookup;
1924
import org.openide.util.NbBundle;
@@ -75,6 +80,7 @@ private void initComponents() {
7580
credentialsPasswordLabel = new javax.swing.JLabel();
7681
credentialsPasswordField = new javax.swing.JPasswordField();
7782
credentialsConnectButton = new javax.swing.JButton();
83+
credentialsCheckButton = new javax.swing.JButton();
7884
jScrollPane1 = new javax.swing.JScrollPane();
7985
handleSearchTextArea = new javax.swing.JTextArea();
8086
fetchLabel = new javax.swing.JLabel();
@@ -123,6 +129,14 @@ public void actionPerformed(java.awt.event.ActionEvent evt) {
123129
}
124130
});
125131

132+
org.openide.awt.Mnemonics.setLocalizedText(credentialsCheckButton, org.openide.util.NbBundle.getMessage(BlueskyGephiMainPanel.class, "BlueskyGephiMainPanel.credentialsCheckButton.text")); // NOI18N
133+
credentialsCheckButton.setToolTipText(org.openide.util.NbBundle.getMessage(BlueskyGephiMainPanel.class, "BlueskyGephiMainPanel.credentialsCheckButton.toolTipText")); // NOI18N
134+
credentialsCheckButton.addActionListener(new java.awt.event.ActionListener() {
135+
public void actionPerformed(java.awt.event.ActionEvent evt) {
136+
credentialsCheckButtonActionPerformed(evt);
137+
}
138+
});
139+
126140
javax.swing.GroupLayout credentialsPanelLayout = new javax.swing.GroupLayout(credentialsPanel);
127141
credentialsPanel.setLayout(credentialsPanelLayout);
128142
credentialsPanelLayout.setHorizontalGroup(
@@ -133,30 +147,32 @@ public void actionPerformed(java.awt.event.ActionEvent evt) {
133147
.addComponent(credentialsConnectButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
134148
.addGroup(credentialsPanelLayout.createSequentialGroup()
135149
.addGroup(credentialsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
136-
.addComponent(credentialsPasswordLabel)
137-
.addComponent(credentialsHandleLabel))
150+
.addComponent(credentialsHandleLabel)
151+
.addComponent(credentialsHostLabel)
152+
.addComponent(credentialsPasswordLabel))
138153
.addGap(18, 18, 18)
139154
.addGroup(credentialsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
140155
.addComponent(credentialsHandleField, javax.swing.GroupLayout.DEFAULT_SIZE, 263, Short.MAX_VALUE)
141-
.addComponent(credentialsPasswordField)))
142-
.addGroup(credentialsPanelLayout.createSequentialGroup()
143-
.addComponent(credentialsHostLabel)
144-
.addGap(43, 43, 43)
145-
.addComponent(credentialsHostField, javax.swing.GroupLayout.DEFAULT_SIZE, 263, Short.MAX_VALUE)))
156+
.addComponent(credentialsPasswordField)
157+
.addGroup(credentialsPanelLayout.createSequentialGroup()
158+
.addComponent(credentialsHostField, javax.swing.GroupLayout.DEFAULT_SIZE, 263, Short.MAX_VALUE)
159+
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
160+
.addComponent(credentialsCheckButton)))))
146161
.addContainerGap())
147162
);
148163
credentialsPanelLayout.setVerticalGroup(
149164
credentialsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
150165
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, credentialsPanelLayout.createSequentialGroup()
151166
.addGap(0, 9, Short.MAX_VALUE)
152-
.addGroup(credentialsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
153-
.addComponent(credentialsHostLabel)
154-
.addComponent(credentialsHostField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
155-
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
156167
.addGroup(credentialsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
157168
.addComponent(credentialsHandleLabel)
158169
.addComponent(credentialsHandleField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
159170
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
171+
.addGroup(credentialsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
172+
.addComponent(credentialsHostLabel)
173+
.addComponent(credentialsHostField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
174+
.addComponent(credentialsCheckButton))
175+
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
160176
.addGroup(credentialsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
161177
.addComponent(credentialsPasswordLabel)
162178
.addComponent(credentialsPasswordField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
@@ -297,6 +313,50 @@ protected void done() {
297313
}.execute();
298314
}//GEN-LAST:event_credentialsConnectButtonActionPerformed
299315

316+
private void credentialsCheckButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_credentialsCheckButtonActionPerformed
317+
final String handle = credentialsHandleField.getText();
318+
// Resolve the account's PDS host off the EDT so a slow lookup never freezes the UI.
319+
credentialsCheckButton.setEnabled(false);
320+
credentialsCheckButton.setBackground(Color.ORANGE);
321+
new javax.swing.SwingWorker<String, Void>() {
322+
@Override
323+
protected String doInBackground() {
324+
return blueskyGephi.resolveHostFromHandle(handle);
325+
}
326+
327+
@Override
328+
protected void done() {
329+
try {
330+
String host = get();
331+
credentialsHostField.setText(host);
332+
credentialsCheckButton.setBackground(Color.GREEN);
333+
} catch (InterruptedException ex) {
334+
Thread.currentThread().interrupt();
335+
credentialsCheckButton.setBackground(Color.RED);
336+
} catch (ExecutionException ex) {
337+
credentialsCheckButton.setBackground(Color.RED);
338+
Throwable cause = (ex.getCause() != null) ? ex.getCause() : ex;
339+
String detail = (cause instanceof AtProtoException)
340+
? ((AtProtoException) cause).getUserMessageWithContent()
341+
: String.valueOf(cause.getMessage());
342+
consoleLogger.warning("Host check failed for \"" + handle + "\": " + detail);
343+
notifyError("Bluesky: could not determine host from handle", detail);
344+
} finally {
345+
credentialsCheckButton.setEnabled(true);
346+
}
347+
}
348+
}.execute();
349+
}//GEN-LAST:event_credentialsCheckButtonActionPerformed
350+
351+
private void notifyError(String title, String detail) {
352+
Icon icon = UIManager.getIcon("OptionPane.warningIcon");
353+
if (icon == null) {
354+
icon = new javax.swing.ImageIcon(
355+
new java.awt.image.BufferedImage(16, 16, java.awt.image.BufferedImage.TYPE_INT_ARGB));
356+
}
357+
NotificationDisplayer.getDefault().notify(title, icon, detail, null, NotificationDisplayer.Priority.HIGH);
358+
}
359+
300360
private void runFetchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_runFetchButtonActionPerformed
301361
blueskyGephi.setQuery(handleSearchTextArea.getText());
302362
List<String> actors = Arrays.asList(handleSearchTextArea.getText().split("\\n"))
@@ -339,6 +399,7 @@ private void credentialsHostFieldActionPerformed(java.awt.event.ActionEvent evt)
339399

340400

341401
// Variables declaration - do not modify//GEN-BEGIN:variables
402+
private javax.swing.JButton credentialsCheckButton;
342403
private javax.swing.JButton credentialsConnectButton;
343404
private javax.swing.JTextField credentialsHandleField;
344405
private javax.swing.JLabel credentialsHandleLabel;

0 commit comments

Comments
 (0)