Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
import java.awt.datatransfer.StringSelection;
import java.net.BindException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import javax.swing.JMenu;
Expand All @@ -20,7 +18,6 @@

import forge.gamemodes.net.ChatMessage;
import forge.gamemodes.net.NetConnectUtil;
import forge.gamemodes.net.server.FServerManager;
import forge.gui.FNetOverlay;
import forge.gui.FThreads;
import forge.gui.SOverlayUtils;
Expand All @@ -29,10 +26,8 @@
import forge.gui.framework.ICDoc;
import forge.gui.util.SOptionPane;
import forge.localinstance.properties.ForgeConstants;
import forge.localinstance.properties.ForgeNetPreferences;
import forge.menus.IMenuProvider;
import forge.menus.MenuUtil;
import forge.model.FModel;
import forge.screens.home.CHomeUI;
import forge.screens.home.CLobby;
import forge.screens.home.VLobby;
Expand Down Expand Up @@ -96,37 +91,11 @@ private void host() {
}

static void showServerAddressesDialog() {
final ForgeNetPreferences netPrefs = FModel.getNetPreferences();
final int port = netPrefs.getPrefInt(ForgeNetPreferences.FNetPref.NET_PORT);
final LinkedHashMap<String, String> addresses = FServerManager.getAllLocalAddresses();
final String externalAddress = FServerManager.getExternalAddress();
final Localizer localizer = Localizer.getInstance();
final NetConnectUtil.ServerAddressList addresses = NetConnectUtil.collectHostedServerAddresses();

// 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<String> orderedLabels = new ArrayList<>();
final List<String> orderedUrls = new ArrayList<>();
if (externalAddress != null) {
orderedLabels.add("External (WAN)");
orderedUrls.add(externalAddress + ":" + port);
}
for (final Map.Entry<String, String> 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));
if (addresses.starIndex >= 0) {
copyToClipboard(addresses.urls.get(addresses.starIndex));
}

final JPanel panel = new JPanel(new MigLayout("insets 0, gap 4 6, wrap 3", "[pref]30[pref]30[pref]"));
Expand All @@ -142,25 +111,24 @@ static void showServerAddressesDialog() {
panel.add(new FLabel.Builder().text("").build());

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);
for (int i = 0; i < addresses.urls.size(); i++) {
final String url = addresses.urls.get(i);
final String label = (i == addresses.starIndex) ? addresses.labels.get(i) + " \u2605" : addresses.labels.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(url);
netPrefs.setPref(ForgeNetPreferences.FNetPref.NET_LAST_COPIED_URL, url);
netPrefs.save();
NetConnectUtil.rememberCopiedServerUrl(url);
holder[0].setVisible(false);
});
panel.add(btnCopy, "w 70!, h 24!");
}

if (starIndex >= 0) {
if (addresses.starIndex >= 0) {
panel.add(new FLabel.Builder()
.text(localizer.getMessage("lblServerUrlCopiedToClipboard", orderedUrls.get(starIndex)))
.text(localizer.getMessage("lblServerUrlCopiedToClipboard", addresses.urls.get(addresses.starIndex)))
.fontSize(11).fontStyle(Font.ITALIC).fontAlign(SwingConstants.LEFT).build(),
"span 3, growx, gaptop 10");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,10 @@ private void activateHost() {
FThreads.invokeInBackgroundThread(() -> {
result[0] = NetConnectUtil.host(OnlineLobbyScreen.this, chatInterface);
chatInterface.addMessage(result[0]);
NetConnectUtil.copyHostedServerUrl();
FThreads.invokeInEdtLater(() -> {
OnlineScreen.Lobby.update();
ServerAddressesDialog.show();
});
});
OnlineScreen.Lobby.update();
});
Expand Down
54 changes: 31 additions & 23 deletions forge-gui-mobile/src/forge/screens/online/OnlineMenu.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,36 +16,22 @@

public class OnlineMenu extends FPopupMenu {
public enum OnlineScreen {
Lobby("lblPlayOnline", FSkinImage.FAVICON, OnlineLobbyScreen.class),
Chat("lblChat", FSkinImage.QUEST_NOTES, OnlineChatScreen.class),
Disconnect("lblDisconnect", FSkinImage.DELETE, null);
Lobby("lblPlayOnline", FSkinImage.FAVICON, OnlineLobbyScreen.class, null),
Chat("lblChat", FSkinImage.QUEST_NOTES, OnlineChatScreen.class, null),
ServerUrl("lblServerURL", FSkinImage.INFORMATION, null, ServerAddressesDialog::show),
Disconnect("lblDisconnect", FSkinImage.DELETE, null, OnlineMenu::handleDisconnect);

private final FMenuItem item;
private final Class<? extends FScreen> screenClass;
private final Runnable customAction;
private FScreen screen;

OnlineScreen(final String caption0, final FImage icon0, final Class<? extends FScreen> screenClass0) {
OnlineScreen(final String caption0, final FImage icon0, final Class<? extends FScreen> screenClass0, final Runnable customAction0) {
screenClass = screenClass0;
customAction = customAction0;
item = new FMenuItem(Forge.getLocalizer().getMessage(caption0), icon0, e -> {
if(screenClass == null) {
FOptionPane.showConfirmDialog(
Forge.getLocalizer().getMessage("lblLeaveLobbyDescription"),
Forge.getLocalizer().getMessage("lblDisconnect"), result -> {
if (result) {
if (FServerManager.getInstance() != null)
if(FServerManager.getInstance().isHosting()) {
FServerManager.getInstance().unsetReady();
FServerManager.getInstance().stopServer();
}

if (OnlineLobbyScreen.getfGameClient() != null)
OnlineLobbyScreen.closeClient();

Forge.back();
screen = null;
OnlineLobbyScreen.clearGameLobby();
}
});
if (customAction != null) {
customAction.run();
return;
}
Forge.back(); //remove current screen from chain
Expand Down Expand Up @@ -85,6 +71,7 @@ public FScreen getScreen() {

public void update(){
Disconnect.item.setEnabled(getGameLobby() != null);
ServerUrl.item.setEnabled(FServerManager.getInstance() != null && FServerManager.getInstance().isHosting());
}
}

Expand Down Expand Up @@ -121,6 +108,27 @@ public static OnlineMenu getMenu() {
private OnlineMenu() {
}

private static void handleDisconnect() {
FOptionPane.showConfirmDialog(
Forge.getLocalizer().getMessage("lblLeaveLobbyDescription"),
Forge.getLocalizer().getMessage("lblDisconnect"), result -> {
if (result) {
if (FServerManager.getInstance() != null)
if (FServerManager.getInstance().isHosting()) {
FServerManager.getInstance().unsetReady();
FServerManager.getInstance().stopServer();
}

if (OnlineLobbyScreen.getfGameClient() != null)
OnlineLobbyScreen.closeClient();

Forge.back();
OnlineScreen.Disconnect.screen = null;
OnlineLobbyScreen.clearGameLobby();
}
});
}

@Override
protected void buildMenu() {
FScreen currentScreen = Forge.getCurrentScreen();
Expand Down
154 changes: 154 additions & 0 deletions forge-gui-mobile/src/forge/screens/online/ServerAddressesDialog.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package forge.screens.online;

import com.badlogic.gdx.utils.Align;
import com.google.common.collect.ImmutableList;

import forge.Forge;
import forge.assets.FSkinColor;
import forge.assets.FSkinFont;
import forge.assets.FSkinImage;
import forge.gamemodes.net.NetConnectUtil;
import forge.gui.GuiBase;
import forge.toolbox.FButton;
import forge.toolbox.FLabel;
import forge.toolbox.FOptionPane;
import forge.toolbox.FScrollPane;
import forge.toolbox.FTextArea;
import forge.util.Localizer;
import forge.util.Utils;

/**
* Mobile equivalent of the desktop "Server URL" dialog. Lists every reachable address
* (External + each local interface) with its own Copy button. Auto-copies and stars
* the previously remembered URL so repeat hosts on the same network don't need to
* pick the same row each time.
*/
public final class ServerAddressesDialog {
private ServerAddressesDialog() { }

private static final float SIDE_PADDING = Utils.scale(10);
private static final float ROW_GAP = Utils.scale(8);
private static final float ROW_PADDING = Utils.scale(10);
private static final float COPY_BTN_WIDTH = Utils.AVG_FINGER_WIDTH * 1.1f;
private static final float COPY_BTN_HEIGHT = Utils.AVG_FINGER_HEIGHT * 0.9f;

public static void show() {
final Localizer localizer = Localizer.getInstance();
final NetConnectUtil.ServerAddressList addresses = NetConnectUtil.collectHostedServerAddresses();
if (addresses.starIndex >= 0) {
GuiBase.getInterface().copyToClipboard(addresses.urls.get(addresses.starIndex));
}

final FOptionPane[] holder = new FOptionPane[1];
final AddressList list = new AddressList(addresses, holder, localizer);
holder[0] = new FOptionPane(
localizer.getMessage("lblChooseAddressToCopy"),
FSkinFont.get(12),
localizer.getMessage("lblServerURL"),
FOptionPane.INFORMATION_ICON,
list,
ImmutableList.of(localizer.getMessage("lblOK")),
0,
null);
holder[0].show();
}

private static final class AddressList extends FScrollPane {
private final FLabel[] labels;
private final FLabel[] urls;
private final FButton[] copyButtons;
private final FTextArea footer;
private final FSkinFont labelFont = FSkinFont.get(12);
private final FSkinFont urlFont = FSkinFont.get(14);

AddressList(final NetConnectUtil.ServerAddressList addresses, final FOptionPane[] holder, final Localizer localizer) {
final int n = addresses.urls.size();
labels = new FLabel[n];
urls = new FLabel[n];
copyButtons = new FButton[n];

for (int i = 0; i < n; i++) {
final String url = addresses.urls.get(i);
final FLabel.Builder labelBuilder = new FLabel.Builder()
.text(addresses.labels.get(i))
.font(labelFont)
.align(Align.left)
.textColor(FSkinColor.get(FSkinColor.Colors.CLR_TEXT));
if (i == addresses.starIndex) {
labelBuilder.icon(FSkinImage.STAR_FILLED).iconScaleFactor(1f);
}
labels[i] = add(labelBuilder.build());
urls[i] = add(new FLabel.Builder()
.text(url)
.font(urlFont)
.align(Align.left)
.textColor(FSkinColor.get(FSkinColor.Colors.CLR_TEXT))
.build());
final FButton btnCopy = new FButton(localizer.getMessage("lblCopy"));
btnCopy.setCommand(e -> {
GuiBase.getInterface().copyToClipboard(url);
NetConnectUtil.rememberCopiedServerUrl(url);
if (holder[0] != null) {
holder[0].hide();
}
});
copyButtons[i] = add(btnCopy);
}

if (addresses.starIndex >= 0) {
footer = new FTextArea(false,
localizer.getMessage("lblServerUrlCopiedToClipboard", addresses.urls.get(addresses.starIndex)));
footer.setFont(FSkinFont.get(11));
add(footer);
} else {
footer = null;
}

final float contentWidth = Forge.getScreenWidth() - 2 * FOptionPane.PADDING - 2 * SIDE_PADDING;
// Reserve some headroom for the icon + prompt + buttons that sit above and below the scroll viewport.
final float maxVisibleHeight = FOptionPane.getMaxDisplayObjHeight() * 0.85f;
setHeight(Math.min(computeFullHeight(contentWidth), maxVisibleHeight));
}

private float computeFullHeight(final float contentWidth) {
final float rowTextHeight = labelFont.getLineHeight() + urlFont.getLineHeight();
final float rowHeight = Math.max(rowTextHeight, COPY_BTN_HEIGHT) + 2 * ROW_PADDING;
float h = rowHeight * labels.length;
if (footer != null) {
h += ROW_GAP + footer.getPreferredHeight(contentWidth) + SIDE_PADDING;
}
return h;
}

@Override
protected ScrollBounds layoutAndGetScrollBounds(final float visibleWidth, final float visibleHeight) {
final float contentX = SIDE_PADDING;
final float contentWidth = visibleWidth - 2 * SIDE_PADDING;
float y = 0;

final float rowTextHeight = labelFont.getLineHeight() + urlFont.getLineHeight();
final float rowHeight = Math.max(rowTextHeight, COPY_BTN_HEIGHT) + 2 * ROW_PADDING;
final float btnWidth = Math.min(COPY_BTN_WIDTH, contentWidth * 0.25f);
final float textX = contentX + btnWidth + 2 * ROW_PADDING;
final float textWidth = contentWidth - btnWidth - 2 * ROW_PADDING;

for (int i = 0; i < labels.length; i++) {
final float rowTop = y + ROW_PADDING;
final float labelHeight = labelFont.getLineHeight();
final float urlHeight = urlFont.getLineHeight();
copyButtons[i].setBounds(contentX, y + (rowHeight - COPY_BTN_HEIGHT) / 2, btnWidth, COPY_BTN_HEIGHT);
labels[i].setBounds(textX, rowTop, textWidth, labelHeight);
urls[i].setBounds(textX, rowTop + labelHeight, textWidth, urlHeight);
y += rowHeight;
}

if (footer != null) {
y += ROW_GAP;
footer.setBounds(contentX, y, contentWidth, footer.getPreferredHeight(contentWidth));
y += footer.getHeight() + SIDE_PADDING;
}

return new ScrollBounds(visibleWidth, y);
}
}
}
Loading
Loading