Fix: Resolving Git Merge Conflicts #253

Merged
j.kropff merged 69 commits from chore/ui-checkstyle-fixes into main 2026-04-11 15:10:58 +02:00
Showing only changes of commit 76e62b3cff - Show all commits
@@ -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,55 +95,38 @@ 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());
Collections.sort(buttonIds); Collections.sort(buttonIds);
int index = 0; int index = 0;
for (Integer buttonId : buttonIds) { for (Integer buttonId : buttonIds) {
int lobbyId = mapping.get(buttonId); int lobbyId = mapping.get(buttonId);
Button btn = new Button(); Button btn = new Button();
btn.setId("lobbyBtn-" + buttonId); btn.setId("lobbyBtn-" + buttonId);
// 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
});
// 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);
});
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,40 +231,36 @@ 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 Map<Integer, Integer> mapping = translationManager.getButtonIdToLobbyId();
javafx.application.Platform.runLater( if (mapping.isEmpty()) {
() -> {
Map<Integer, Integer> mapping = translationManager.getButtonIdToLobbyId();
if (mapping.isEmpty()) {
return; return;
} }
List<Integer> buttonIds = new ArrayList<>(mapping.keySet()); List<Integer> buttonIds = new ArrayList<>(mapping.keySet());
Collections.sort(buttonIds); Collections.sort(buttonIds);
for (Integer buttonId : buttonIds) { for (Integer buttonId : buttonIds) {
int lobbyId = mapping.get(buttonId); int lobbyId = mapping.get(buttonId);
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;
ImageView iv = new ImageView(safeLoadImage(path)); ImageView iv = new ImageView(safeLoadImage(path));
iv.setPreserveRatio(true); iv.setPreserveRatio(true);
iv.fitWidthProperty() iv.fitWidthProperty()
.bind( .bind(
gridPane.widthProperty() gridPane.widthProperty()
.divide(COLS) .divide(COLS)
.subtract(BUTTON_WIDTH_MARGIN)); .subtract(BUTTON_WIDTH_MARGIN));
iv.setSmooth(true); iv.setSmooth(true);
btn.setGraphic(iv); btn.setGraphic(iv);
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;
}
} }