From f2a0414b59071d27d0fe813f38aed1286d792d9a Mon Sep 17 00:00:00 2001 From: MostCromulent <201167372+MostCromulent@users.noreply.github.com> Date: Tue, 21 Apr 2026 08:06:48 +0930 Subject: [PATCH] Server URL button: route to interface-picker dialog with memory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Point the lobby's "Server URL" button at the same per-interface address dialog added to host startup in PR #10445. Instruction moved inside the panel so dialog width fits the addresses; columns left-aligned with 30px gaps. Copy buttons dismiss the dialog. Remember the last-copied URL in a new NET_LAST_COPIED_URL pref. On open, auto-copy and star the remembered row (fallback: first row); an italic notice at the bottom confirms what was copied. Mobile continues to use NetConnectUtil.copyHostedServerUrl — the new dialog is desktop-only Swing. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../home/online/CSubmenuOnlineLobby.java | 86 +++++++++++++------ .../home/online/VSubmenuOnlineLobby.java | 3 +- forge-gui/res/languages/en-US.properties | 1 + .../properties/ForgeNetPreferences.java | 3 +- 4 files changed, 66 insertions(+), 27 deletions(-) diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/online/CSubmenuOnlineLobby.java b/forge-gui-desktop/src/main/java/forge/screens/home/online/CSubmenuOnlineLobby.java index 4c3366cb54e..549e529b31f 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/home/online/CSubmenuOnlineLobby.java +++ b/forge-gui-desktop/src/main/java/forge/screens/home/online/CSubmenuOnlineLobby.java @@ -12,6 +12,7 @@ import javax.swing.JMenu; import javax.swing.JPanel; +import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import com.google.common.collect.ImmutableList; @@ -94,50 +95,87 @@ private void host() { }); } - private void showServerAddressesDialog() { - final int port = FModel.getNetPreferences().getPrefInt(ForgeNetPreferences.FNetPref.NET_PORT); + static void showServerAddressesDialog() { + final ForgeNetPreferences netPrefs = FModel.getNetPreferences(); + final int port = netPrefs.getPrefInt(ForgeNetPreferences.FNetPref.NET_PORT); final LinkedHashMap addresses = FServerManager.getAllLocalAddresses(); final String externalAddress = FServerManager.getExternalAddress(); final Localizer localizer = Localizer.getInstance(); - final JPanel panel = new JPanel(new MigLayout("insets 0, gap 4 6, wrap 3", "[grow][grow][pref]")); + // Collect rows in display order; we auto-copy and star whichever row matches + // the last-copied URL, falling back to the first row. + final List orderedLabels = new ArrayList<>(); + final List orderedUrls = new ArrayList<>(); + if (externalAddress != null) { + orderedLabels.add("External (WAN)"); + orderedUrls.add(externalAddress + ":" + port); + } + for (final Map.Entry entry : addresses.entrySet()) { + orderedLabels.add(entry.getKey()); + orderedUrls.add(entry.getValue() + ":" + port); + } + + // If the remembered URL is present in the current list, auto-copy and star it. + // Otherwise fall back to the first entry (external if present, else first local + // interface) — matches the old copyHostedServerUrl default. Do NOT overwrite + // the remembered value on fallback, so a later reconnect to the original + // network restores the preference. + final String rememberedUrl = netPrefs.getPref(ForgeNetPreferences.FNetPref.NET_LAST_COPIED_URL); + int starIndex = orderedUrls.indexOf(rememberedUrl); + if (starIndex < 0) { + starIndex = orderedUrls.isEmpty() ? -1 : 0; + } + if (starIndex >= 0) { + copyToClipboard(orderedUrls.get(starIndex)); + } + + final JPanel panel = new JPanel(new MigLayout("insets 0, gap 4 6, wrap 3", "[pref]30[pref]30[pref]")); panel.setOpaque(false); - panel.add(new FLabel.Builder().text(localizer.getMessage("lblInterface")).fontStyle(Font.BOLD).fontSize(12).build(), "growx"); - panel.add(new FLabel.Builder().text(localizer.getMessage("lblAddress")).fontStyle(Font.BOLD).fontSize(12).build(), "growx"); + panel.add(new FLabel.Builder() + .text(localizer.getMessage("lblChooseAddressToCopy")) + .fontSize(12).fontAlign(SwingConstants.LEFT).build(), + "span 3, growx, gapbottom 10"); + + panel.add(new FLabel.Builder().text(localizer.getMessage("lblInterface")).fontStyle(Font.BOLD).fontSize(12).fontAlign(SwingConstants.LEFT).build(), "growx"); + panel.add(new FLabel.Builder().text(localizer.getMessage("lblAddress")).fontStyle(Font.BOLD).fontSize(12).fontAlign(SwingConstants.LEFT).build(), "growx"); panel.add(new FLabel.Builder().text("").build()); - if (externalAddress != null) { - final String externalUrl = externalAddress + ":" + port; - panel.add(new FLabel.Builder().text("External (WAN)").fontSize(12).build(), "growx"); - panel.add(new FLabel.Builder().text(externalUrl).fontSize(12).build(), "growx"); + final FOptionPane[] holder = new FOptionPane[1]; + for (int i = 0; i < orderedUrls.size(); i++) { + final String url = orderedUrls.get(i); + final String label = (i == starIndex) ? orderedLabels.get(i) + " \u2605" : orderedLabels.get(i); + panel.add(new FLabel.Builder().text(label).fontSize(12).fontAlign(SwingConstants.LEFT).build(), "growx"); + panel.add(new FLabel.Builder().text(url).fontSize(12).fontAlign(SwingConstants.LEFT).build(), "growx"); final FButton btnCopy = new FButton(localizer.getMessage("lblCopy")); btnCopy.setFont(FSkin.getFont(11)); - btnCopy.addActionListener(e -> copyToClipboard(externalUrl)); + btnCopy.addActionListener(e -> { + copyToClipboard(url); + netPrefs.setPref(ForgeNetPreferences.FNetPref.NET_LAST_COPIED_URL, url); + netPrefs.save(); + holder[0].setVisible(false); + }); panel.add(btnCopy, "w 70!, h 24!"); } - boolean first = true; - for (final Map.Entry entry : addresses.entrySet()) { - final String url = entry.getValue() + ":" + port; - final String label = first ? entry.getKey() + " \u2605" : entry.getKey(); - first = false; - - panel.add(new FLabel.Builder().text(label).fontSize(12).build(), "growx"); - panel.add(new FLabel.Builder().text(url).fontSize(12).build(), "growx"); - final FButton btnCopy = new FButton(localizer.getMessage("lblCopy")); - btnCopy.setFont(FSkin.getFont(11)); - btnCopy.addActionListener(e -> copyToClipboard(url)); - panel.add(btnCopy, "w 70!, h 24!"); + if (starIndex >= 0) { + panel.add(new FLabel.Builder() + .text(localizer.getMessage("lblServerUrlCopiedToClipboard", orderedUrls.get(starIndex))) + .fontSize(11).fontStyle(Font.ITALIC).fontAlign(SwingConstants.LEFT).build(), + "span 3, growx, gaptop 10"); } - FOptionPane.showOptionDialog( - localizer.getMessage("lblChooseAddressToCopy"), + // Pass null as the prompt message so dialog width is driven by the panel's + // actual content width rather than the much-wider localised instruction line. + holder[0] = new FOptionPane( + null, localizer.getMessage("lblServerURL"), FOptionPane.INFORMATION_ICON, panel, ImmutableList.of(localizer.getMessage("lblOK")), 0); + holder[0].setVisible(true); + holder[0].dispose(); } private static void copyToClipboard(final String text) { diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/online/VSubmenuOnlineLobby.java b/forge-gui-desktop/src/main/java/forge/screens/home/online/VSubmenuOnlineLobby.java index 75e97e1a397..cae05a496c8 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/home/online/VSubmenuOnlineLobby.java +++ b/forge-gui-desktop/src/main/java/forge/screens/home/online/VSubmenuOnlineLobby.java @@ -5,7 +5,6 @@ import forge.deckchooser.FDeckChooser; import forge.gamemodes.match.GameLobby; import forge.gamemodes.net.IOnlineLobby; -import forge.gamemodes.net.NetConnectUtil; import forge.gamemodes.net.client.FGameClient; import forge.gamemodes.net.server.FServerManager; import forge.gui.FNetOverlay; @@ -96,7 +95,7 @@ public void populate() { FButton btnServerUrl = new FButton(Localizer.getInstance().getMessage("lblServerURL")); btnServerUrl.setFont(FSkin.getRelativeFont(14)); pnlTitle.add(btnServerUrl, "w 150!, h 35!, gap 10 10 0 0, align right"); - btnServerUrl.addActionListener(e -> NetConnectUtil.copyHostedServerUrl()); + btnServerUrl.addActionListener(e -> CSubmenuOnlineLobby.showServerAddressesDialog()); } pnlTitle.add(btnStop, "gap 10 10 0 0, align right"); container.add(pnlTitle,"w 80%, gap 0 0 0 0, al right, pushx"); diff --git a/forge-gui/res/languages/en-US.properties b/forge-gui/res/languages/en-US.properties index c1bb6e3d7be..f04b2d7cbcc 100644 --- a/forge-gui/res/languages/en-US.properties +++ b/forge-gui/res/languages/en-US.properties @@ -3130,6 +3130,7 @@ lblServerURL=Server URL lblInterface=Interface lblAddress=Address lblChooseAddressToCopy=Click "Copy" next to the address you want to share with other players. +lblServerUrlCopiedToClipboard=Last used address automatically copied to clipboard: {0} lblCopyExternalURL=Copy External URL lblCopyLocalURL=Copy Local URL lblYourConnectionToHostWasInterrupted=Your connection to the host ({0}) was interrupted. diff --git a/forge-gui/src/main/java/forge/localinstance/properties/ForgeNetPreferences.java b/forge-gui/src/main/java/forge/localinstance/properties/ForgeNetPreferences.java index 3cf3c359e2f..a21fb5d1b50 100644 --- a/forge-gui/src/main/java/forge/localinstance/properties/ForgeNetPreferences.java +++ b/forge-gui/src/main/java/forge/localinstance/properties/ForgeNetPreferences.java @@ -30,7 +30,8 @@ public enum FNetPref implements PreferencesStore.IPref { NET_BANDWIDTH_LOGGING("false"), NET_MAX_LOG_FILES("10"), NET_LOG_CLEANUP_ENABLED("true"), - NET_AFK_TIMEOUT("5"); + NET_AFK_TIMEOUT("5"), + NET_LAST_COPIED_URL(""); private final String strDefaultVal;