Feat: Accept ClientService and delegate to LobbyClient
Add constructor overload that accepts ClientService and constructs a LobbyClient. Avoids implicit host/port lookup in UI code; caller controls network config. Keeps rendering/status behavior unchanged (async updates, deterministic ordering).
This commit is contained in:
+35
-65
@@ -38,15 +38,9 @@ public class LobbyButtonGridManager {
|
|||||||
/** Manager for mapping ButtonID to LobbyID. */
|
/** Manager for mapping ButtonID to LobbyID. */
|
||||||
private final LobbyButtonTranslationManager translationManager;
|
private final LobbyButtonTranslationManager translationManager;
|
||||||
|
|
||||||
/** Number of rows in the grid. */
|
|
||||||
private static final int ROWS = 2;
|
|
||||||
|
|
||||||
/** Number of columns in the grid. */
|
/** Number of columns in the grid. */
|
||||||
private static final int COLS = 4;
|
private static final int COLS = 4;
|
||||||
|
|
||||||
/** Path to the button image. */
|
|
||||||
private static final String BUTTON_IMAGE_PATH = "/images/logo.png";
|
|
||||||
|
|
||||||
/** Image for a lobby in CREATED state. */
|
/** Image for a lobby in CREATED state. */
|
||||||
/** Default fallback image. */
|
/** Default fallback image. */
|
||||||
private static final String BUTTON_FALLBACK_IMAGE = "/images/lobbypictures/error.png";
|
private static final String BUTTON_FALLBACK_IMAGE = "/images/lobbypictures/error.png";
|
||||||
@@ -61,25 +55,17 @@ public class LobbyButtonGridManager {
|
|||||||
/** Cache for loaded Images keyed by resource path. */
|
/** Cache for loaded Images keyed by resource path. */
|
||||||
private final ConcurrentHashMap<String, Image> imageCache = new ConcurrentHashMap<>();
|
private final ConcurrentHashMap<String, Image> imageCache = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
/** Max random lobby id. */
|
|
||||||
private static final int MAX_RANDOM_LOBBY_ID = 10000;
|
|
||||||
|
|
||||||
private final LobbyClient lobbyClient;
|
private final LobbyClient lobbyClient;
|
||||||
|
|
||||||
|
/** Executor for background status/network tasks. */
|
||||||
|
private final ExecutorService executor = Executors.newCachedThreadPool();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for the GridManager.
|
* Constructor for the GridManager.
|
||||||
*
|
*
|
||||||
* @param gridPane the GridPane for rendering
|
* @param gridPane the GridPane for rendering
|
||||||
* @param translationManager the manager for mapping ButtonID to LobbyID
|
* @param translationManager the manager for mapping ButtonID to LobbyID
|
||||||
*/
|
*/
|
||||||
public LobbyButtonGridManager(
|
|
||||||
GridPane gridPane, LobbyButtonTranslationManager translationManager) {
|
|
||||||
this(gridPane, translationManager, createDefaultLobbyClient());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor that accepts a `LobbyClient` implementation.
|
|
||||||
*/
|
|
||||||
public LobbyButtonGridManager(
|
public LobbyButtonGridManager(
|
||||||
GridPane gridPane, LobbyButtonTranslationManager translationManager, LobbyClient lobbyClient) {
|
GridPane gridPane, LobbyButtonTranslationManager translationManager, LobbyClient lobbyClient) {
|
||||||
this.gridPane = gridPane;
|
this.gridPane = gridPane;
|
||||||
@@ -88,17 +74,20 @@ public class LobbyButtonGridManager {
|
|||||||
this.lobbyClient = lobbyClient;
|
this.lobbyClient = lobbyClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static LobbyClient createDefaultLobbyClient() {
|
/**
|
||||||
String host = System.getProperty("casono.server.host", "127.0.0.1");
|
* Convenience constructor: accept a {@link ClientService} and build a
|
||||||
int port = 1337;
|
* {@link LobbyClient} from it. This avoids any host/port System.getProperty
|
||||||
try {
|
* lookups elsewhere — caller controls the ClientService.
|
||||||
port = Integer.parseInt(System.getProperty("casono.server.port", "1337"));
|
*/
|
||||||
} catch (NumberFormatException e) {
|
public LobbyButtonGridManager(
|
||||||
// use default port if parsing fails
|
GridPane gridPane, LobbyButtonTranslationManager translationManager, ClientService clientService) {
|
||||||
}
|
this(gridPane, translationManager, new LobbyClient(clientService));
|
||||||
return new LobbyClient(new ClientService(host, port));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Default client creation removed to avoid implicit IP/port configuration.
|
||||||
|
// Applications must construct and provide a LobbyClient or ClientService
|
||||||
|
// explicitly.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders all lobby buttons in the grid. Creates a button for each mapping with
|
* Renders all lobby buttons in the grid. Creates a button for each mapping with
|
||||||
* image and event
|
* image and event
|
||||||
@@ -106,10 +95,8 @@ public class LobbyButtonGridManager {
|
|||||||
*/
|
*/
|
||||||
public void renderLobbyButtons() {
|
public void renderLobbyButtons() {
|
||||||
gridPane.getChildren().clear();
|
gridPane.getChildren().clear();
|
||||||
int index = 0;
|
|
||||||
Map<Integer, Integer> mapping = translationManager.getButtonIdToLobbyId();
|
Map<Integer, Integer> mapping = translationManager.getButtonIdToLobbyId();
|
||||||
if (mapping.isEmpty()) {
|
if (mapping.isEmpty()) {
|
||||||
// No buttons to render
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
List<Integer> buttonIds = new ArrayList<>(mapping.keySet());
|
List<Integer> buttonIds = new ArrayList<>(mapping.keySet());
|
||||||
@@ -122,39 +109,24 @@ public class LobbyButtonGridManager {
|
|||||||
// placeholder image so UI remains responsive
|
// placeholder image so UI remains responsive
|
||||||
Image placeholder = safeLoadImage(BUTTON_FALLBACK_IMAGE);
|
Image placeholder = safeLoadImage(BUTTON_FALLBACK_IMAGE);
|
||||||
ImageView imageView = new ImageView(placeholder);
|
ImageView imageView = new ImageView(placeholder);
|
||||||
imageView.setPreserveRatio(true);
|
imageView.setPreserveRatio(true);
|
||||||
imageView.fitWidthProperty().bind(gridPane.widthProperty().divide(COLS).subtract(BUTTON_WIDTH_MARGIN));
|
imageView.fitWidthProperty().bind(gridPane.widthProperty().divide(COLS).subtract(BUTTON_WIDTH_MARGIN));
|
||||||
imageView.setSmooth(true);
|
imageView.setSmooth(true);
|
||||||
btn.setGraphic(imageView);
|
btn.setGraphic(imageView);
|
||||||
btn.setMaxWidth(Double.MAX_VALUE);
|
btn.setMaxWidth(Double.MAX_VALUE);
|
||||||
btn.setMaxHeight(Double.MAX_VALUE);
|
btn.setMaxHeight(Double.MAX_VALUE);
|
||||||
btn.setMinWidth(BUTTON_MIN_SIZE);
|
btn.setMinWidth(BUTTON_MIN_SIZE);
|
||||||
btn.setMinHeight(BUTTON_MIN_SIZE);
|
btn.setMinHeight(BUTTON_MIN_SIZE);
|
||||||
GridPane.setHgrow(btn, javafx.scene.layout.Priority.ALWAYS);
|
GridPane.setHgrow(btn, javafx.scene.layout.Priority.ALWAYS);
|
||||||
GridPane.setVgrow(btn, javafx.scene.layout.Priority.ALWAYS);
|
GridPane.setVgrow(btn, javafx.scene.layout.Priority.ALWAYS);
|
||||||
final int bId = buttonId;
|
final int bId = buttonId;
|
||||||
btn.setOnAction(e -> {
|
btn.setOnAction(e -> {
|
||||||
Integer targetLobbyId = translationManager.getLobbyIdForButton(bId);
|
Integer targetLobbyId = translationManager.getLobbyIdForButton(bId);
|
||||||
if (targetLobbyId != null) {
|
if (targetLobbyId != null) {
|
||||||
joinLobby(targetLobbyId);
|
joinLobby(targetLobbyId);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
// async fetch status and update image
|
|
||||||
});
|
|
||||||
// async fetch status and update image
|
|
||||||
CompletableFuture.supplyAsync(() -> lobbyClient.fetchLobbyStatusString(lobbyId), executor)
|
|
||||||
.thenAccept(statusStr -> {
|
|
||||||
LobbyStatus status = parseLobbyStatus(statusStr);
|
|
||||||
String path = getImagePathForButton(buttonId, status == null ? LobbyStatus.CREATED : status);
|
|
||||||
Image img = safeLoadImage(path);
|
|
||||||
javafx.application.Platform.runLater(() -> {
|
|
||||||
ImageView iv = new ImageView(img);
|
|
||||||
iv.setPreserveRatio(true);
|
|
||||||
iv.fitWidthProperty()
|
|
||||||
.bind(gridPane.widthProperty().divide(COLS).subtract(BUTTON_WIDTH_MARGIN));
|
|
||||||
iv.setSmooth(true);
|
|
||||||
btn.setGraphic(iv);
|
|
||||||
});
|
});
|
||||||
|
// async fetch status and update image
|
||||||
CompletableFuture.supplyAsync(() -> lobbyClient.fetchLobbyStatusString(lobbyId), executor)
|
CompletableFuture.supplyAsync(() -> lobbyClient.fetchLobbyStatusString(lobbyId), executor)
|
||||||
.thenAccept(statusStr -> {
|
.thenAccept(statusStr -> {
|
||||||
LobbyStatus status = parseLobbyStatus(statusStr);
|
LobbyStatus status = parseLobbyStatus(statusStr);
|
||||||
@@ -214,12 +186,6 @@ if (targetLobbyId != null) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getImagePathForStatus(LobbyStatus status) {
|
|
||||||
return status == LobbyStatus.CREATED
|
|
||||||
? String.format(BUTTON_IMAGE_TEMPLATE, 0, "created")
|
|
||||||
: String.format(BUTTON_IMAGE_TEMPLATE, 0, "running");
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getImagePathForButton(int buttonId, LobbyStatus status) {
|
private String getImagePathForButton(int buttonId, LobbyStatus status) {
|
||||||
String statusStr = status == LobbyStatus.CREATED ? "created" : "running";
|
String statusStr = status == LobbyStatus.CREATED ? "created" : "running";
|
||||||
return String.format(BUTTON_IMAGE_TEMPLATE, buttonId, statusStr);
|
return String.format(BUTTON_IMAGE_TEMPLATE, buttonId, statusStr);
|
||||||
@@ -265,9 +231,6 @@ if (targetLobbyId != null) {
|
|||||||
|
|
||||||
/** Update all lobby buttons' images according to the current lobby statuses. */
|
/** Update all lobby buttons' images according to the current lobby statuses. */
|
||||||
public void updateLobbyButtonImages() {
|
public void updateLobbyButtonImages() {
|
||||||
// Run on FX thread to be safe
|
|
||||||
javafx.application.Platform.runLater(
|
|
||||||
() -> {
|
|
||||||
Map<Integer, Integer> mapping = translationManager.getButtonIdToLobbyId();
|
Map<Integer, Integer> mapping = translationManager.getButtonIdToLobbyId();
|
||||||
if (mapping.isEmpty()) {
|
if (mapping.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
@@ -279,7 +242,7 @@ if (targetLobbyId != null) {
|
|||||||
CompletableFuture.supplyAsync(() -> getLobbyStatus(lobbyId), executor)
|
CompletableFuture.supplyAsync(() -> getLobbyStatus(lobbyId), executor)
|
||||||
.thenAccept(status -> {
|
.thenAccept(status -> {
|
||||||
String path = getImagePathForButton(buttonId, status);
|
String path = getImagePathForButton(buttonId, status);
|
||||||
javafx.application.Platform.runLater(() -> {
|
javafx.application.Platform.runLater(() -> {
|
||||||
for (Node node : gridPane.getChildren()) {
|
for (Node node : gridPane.getChildren()) {
|
||||||
if (node instanceof Button && ("lobbyBtn-" + buttonId).equals(node.getId())) {
|
if (node instanceof Button && ("lobbyBtn-" + buttonId).equals(node.getId())) {
|
||||||
Button btn = (Button) node;
|
Button btn = (Button) node;
|
||||||
@@ -295,10 +258,9 @@ javafx.application.Platform.runLater(() -> {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -310,13 +272,13 @@ javafx.application.Platform.runLater(() -> {
|
|||||||
try {
|
try {
|
||||||
int lobbyId = lobbyClient.createLobby();
|
int lobbyId = lobbyClient.createLobby();
|
||||||
LOGGER.info("Lobby created via LobbyClient: {}", lobbyId);
|
LOGGER.info("Lobby created via LobbyClient: {}", lobbyId);
|
||||||
|
if (lobbyId <= 0) {
|
||||||
|
throw new RuntimeException("LobbyClient returned invalid lobby id: " + lobbyId);
|
||||||
|
}
|
||||||
return lobbyId;
|
return lobbyId;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOGGER.error("Failed to create lobby via LobbyClient: {}", e.getMessage());
|
LOGGER.error("Failed to create lobby via LobbyClient: {}", e.getMessage());
|
||||||
// Fallback: generate a local id so UI can continue to work in offline mode
|
throw new RuntimeException("Failed to create lobby", e);
|
||||||
int lobbyId = (int) (Math.random() * MAX_RANDOM_LOBBY_ID + 1);
|
|
||||||
LOGGER.warn("Falling back to local generated lobby id: {}", lobbyId);
|
|
||||||
return lobbyId;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -374,4 +336,12 @@ javafx.application.Platform.runLater(() -> {
|
|||||||
return gridPane;
|
return gridPane;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expose the configured LobbyClient so callers can invoke its methods
|
||||||
|
* directly (createLobby, fetchLobbyStatusString, joinLobby, ...).
|
||||||
|
*/
|
||||||
|
public LobbyClient getLobbyClient() {
|
||||||
|
return lobbyClient;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user