diff --git a/src/main/java/es/iesquevedo/controller/GameController.java b/src/main/java/es/iesquevedo/controller/GameController.java index bb92515..5068f7e 100644 --- a/src/main/java/es/iesquevedo/controller/GameController.java +++ b/src/main/java/es/iesquevedo/controller/GameController.java @@ -5,6 +5,7 @@ import es.iesquevedo.model.GameState; import es.iesquevedo.model.Move; import es.iesquevedo.model.Player; +import es.iesquevedo.service.impl.GameServiceImpl; import es.iesquevedo.service.impl.InazumaGoMoveValidator; import es.iesquevedo.exception.InvalidMoveException; import es.iesquevedo.exception.PlayerNotInTurnException; @@ -43,6 +44,7 @@ public class GameController { private String player1Name = "Jugador 1"; private String player2Name = "Jugador 2"; + private String matchingPlayerName = "Jugador"; private long player1TimeMs = 0; private long player2TimeMs = 0; private AnimationTimer gameTimer; @@ -313,8 +315,15 @@ private void onBoardClick(MouseEvent event) { } public void initGame(String gameId, String playerName) { - this.player1Name = playerName + " (Negro)"; - this.player2Name = "Oponente (Blanco)"; + this.matchingPlayerName = playerName != null ? playerName : "Jugador"; + this.player1Name = this.matchingPlayerName; + this.player2Name = "Oponente"; + + if (game != null && game.getPlayers().size() >= 2) { + game.getPlayers().get(0).setName(this.player1Name); + game.getPlayers().get(1).setName(this.player2Name); + } + updatePlayerInfo(); LOGGER.log(Level.INFO, "Partida iniciada - GameID: " + gameId + " - Jugador: " + playerName); } @@ -462,10 +471,27 @@ private void onSurrender() { @FXML private void onBackToMenu() { stopGameTimer(); - LOGGER.log(Level.INFO, "Volviendo al menú"); - // Castear a Stage para poder cerrar la ventana - javafx.stage.Stage stage = (javafx.stage.Stage) boardCanvas.getScene().getWindow(); - stage.close(); + LOGGER.log(Level.INFO, "Volviendo al emparejamiento"); + goToMatchingScreen(); + } + + private void goToMatchingScreen() { + try { + javafx.fxml.FXMLLoader loader = new javafx.fxml.FXMLLoader(getClass().getResource("/fxml/MatchingScreen.fxml")); + javafx.scene.Parent root = loader.load(); + + es.iesquevedo.ui.MatchingScreenController controller = loader.getController(); + controller.setGameService(new GameServiceImpl()); + controller.startMatching(new Player(matchingPlayerName, matchingPlayerName)); + + javafx.stage.Stage stage = (javafx.stage.Stage) boardCanvas.getScene().getWindow(); + stage.setScene(new javafx.scene.Scene(root, 500, 300)); + stage.setTitle("InazumaGo - Emparejamiento"); + stage.show(); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, "Error al volver al emparejamiento", e); + statusLabel.setText("Error al volver al emparejamiento"); + } } private void endGame() { diff --git a/src/main/java/es/iesquevedo/controller/LoginController.java b/src/main/java/es/iesquevedo/controller/LoginController.java index 307a469..f09a902 100644 --- a/src/main/java/es/iesquevedo/controller/LoginController.java +++ b/src/main/java/es/iesquevedo/controller/LoginController.java @@ -6,10 +6,12 @@ import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; +import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.PasswordField; import javafx.scene.control.TextField; import javafx.scene.paint.Color; +import javafx.stage.Stage; import java.util.logging.Level; import java.util.logging.Logger; @@ -31,6 +33,9 @@ public class LoginController { @FXML private Label statusLabel; + @FXML + private Button registerButton; + private AuthService authService; private AppState appState; @@ -105,8 +110,8 @@ public void onLoginClicked() { emailField.clear(); passwordField.clear(); - // Navegar a la pantalla de juego - navigateToGame(email); + // Navegar a la pantalla de emparejamiento + navigateToMatching(email); } catch (Exception e) { updateStatus("✗ Error de login: " + e.getMessage(), "error"); @@ -115,29 +120,37 @@ public void onLoginClicked() { } /** - * Navega a la pantalla de juego después del login exitoso. + * Navega a la pantalla de emparejamiento después del login exitoso. * - * @param playerName nombre del jugador autenticado + * @param playerEmail email del jugador autenticado */ - private void navigateToGame(String playerName) { + private void navigateToMatching(String playerEmail) { try { - FXMLLoader gameLoader = new FXMLLoader(getClass().getResource("/fxml/Game.fxml")); - Parent gameRoot = gameLoader.load(); + FXMLLoader matchingLoader = new FXMLLoader(getClass().getResource("/fxml/MatchingScreen.fxml")); + Parent matchingRoot = matchingLoader.load(); - GameController gameController = gameLoader.getController(); - gameController.setPlayerNames(playerName, "Oponente"); - gameController.setInitialScores(0, 0); + es.iesquevedo.ui.MatchingScreenController matchingController = matchingLoader.getController(); + String playerName = buildDisplayName(playerEmail); + matchingController.startMatching(new es.iesquevedo.model.Player(playerEmail, playerName)); Scene scene = emailField.getScene(); - scene.setRoot(gameRoot); + scene.setRoot(matchingRoot); javafx.stage.Stage stage = (javafx.stage.Stage) scene.getWindow(); - stage.setTitle("InazumaGo - Partida"); + stage.setTitle("InazumaGo - Emparejamiento"); - LOGGER.log(Level.INFO, "Navegado a pantalla de juego para: " + playerName); + LOGGER.log(Level.INFO, "Navegado a pantalla de emparejamiento para: " + playerEmail); } catch (Exception e) { - updateStatus("✗ Error al cargar pantalla de juego: " + e.getMessage(), "error"); - LOGGER.log(Level.SEVERE, "Error al cargar Game.fxml: " + e.getMessage()); + updateStatus("✗ Error al cargar pantalla de emparejamiento: " + e.getMessage(), "error"); + LOGGER.log(Level.SEVERE, "Error al cargar MatchingScreen.fxml: " + e.getMessage()); + } + } + + private String buildDisplayName(String email) { + if (email == null || email.trim().isEmpty()) { + return "Jugador"; } + int atIndex = email.indexOf('@'); + return atIndex > 0 ? email.substring(0, atIndex) : email; } /** @@ -171,6 +184,25 @@ private void updateStatus(String message, String type) { } } - // ...existing code... + /** + * Navega a la pantalla de registro. + */ + @FXML + public void onRegisterClicked() { + try { + FXMLLoader registerLoader = new FXMLLoader(getClass().getResource("/fxml/Register.fxml")); + Parent registerRoot = registerLoader.load(); + + Scene scene = emailField.getScene(); + scene.setRoot(registerRoot); + Stage stage = (Stage) scene.getWindow(); + stage.setTitle("InazumaGo - Registro"); + + LOGGER.log(Level.INFO, "Navegado a pantalla de registro"); + } catch (Exception e) { + updateStatus("✗ Error al cargar pantalla de registro: " + e.getMessage(), "error"); + LOGGER.log(Level.SEVERE, "Error al cargar Register.fxml: " + e.getMessage()); + } + } } diff --git a/src/main/java/es/iesquevedo/controller/MainController.java b/src/main/java/es/iesquevedo/controller/MainController.java index e7e2fb5..a78efca 100644 --- a/src/main/java/es/iesquevedo/controller/MainController.java +++ b/src/main/java/es/iesquevedo/controller/MainController.java @@ -5,6 +5,8 @@ import es.iesquevedo.service.MainService; import javafx.fxml.FXML; import javafx.scene.control.Label; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; import java.util.logging.Level; import java.util.logging.Logger; @@ -12,11 +14,29 @@ public class MainController { private static final Logger LOGGER = Logger.getLogger(MainController.class.getName()); private final MainErrorHandler errorHandler = new MainErrorHandler(); + // Configurable image paths + private static final String GAME_BOARD_PATH = "/images/game-board.png"; + private static final String BLACK_STONE_PATH = "/images/stone-black.png"; + private static final String WHITE_STONE_PATH = "/images/stone-white.png"; + private static final String RESOURCE_NOT_FOUND_PREFIX = "Recurso no encontrado: "; + private MainService mainService; @FXML private Label salutoLabel; + @FXML + @SuppressWarnings("FieldCanBeLocal") + private ImageView gameBoardImageView; + + @FXML + @SuppressWarnings("FieldCanBeLocal") + private ImageView blackStoneImageView; + + @FXML + @SuppressWarnings("FieldCanBeLocal") + private ImageView whiteStoneImageView; + public MainController() { // Constructor sin parámetros necesario para FXML this.mainService = null; @@ -31,30 +51,105 @@ public void setService(MainService mainService) { @FXML public void initialize() { // Este método se llama automáticamente después de que FXML carga los componentes + setupGreeting(); + + // Cargar imagen del tablero y fichas + loadGameBoard(); + loadStones(); + } + + private void setupGreeting() { if (mainService != null && salutoLabel != null) { try { String saludo = mainService.greet(); - salutoLabel.setText(saludo); - LOGGER.info("Saludo establecido: " + saludo); + handleGreetingSuccess(saludo); } catch (RuntimeException e) { - ApiError apiError = errorHandler.toApiError(e); - LOGGER.log(Level.SEVERE, "Error al obtener saludo del servicio", e); - salutoLabel.setText(formatApiError(apiError)); + handleGreetingError(e); } } else if (salutoLabel != null) { salutoLabel.setText("Servicio no disponible"); } } + + private void handleGreetingSuccess(String saludo) { + salutoLabel.setText(saludo); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info(String.format("Saludo establecido: %s", saludo)); + } + } + + private void handleGreetingError(RuntimeException e) { + ApiError apiError = errorHandler.toApiError(e); + LOGGER.log(Level.SEVERE, "Error al obtener saludo del servicio", e); + salutoLabel.setText(formatApiError(apiError)); + } + + private void loadGameBoard() { + if (gameBoardImageView != null) { + loadImage(gameBoardImageView, GAME_BOARD_PATH, "Tablero cargado correctamente", "No se pudo cargar la imagen del tablero"); + } + } + + private void loadStones() { + loadStone(blackStoneImageView, BLACK_STONE_PATH, 100, 100); + loadStone(whiteStoneImageView, WHITE_STONE_PATH, 200, 200); + } + + private void loadImage(ImageView imageView, String path, String successMessage, String errorMessage) { + try { + var resourceStream = getClass().getResourceAsStream(path); + if (resourceStream != null) { + Image image = new Image(resourceStream); + imageView.setImage(image); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info(successMessage); + } + } else { + if (LOGGER.isLoggable(Level.WARNING)) { + LOGGER.log(Level.WARNING, String.format("%s%s", RESOURCE_NOT_FOUND_PREFIX, path)); + } + } + } catch (Exception e) { + if (LOGGER.isLoggable(Level.WARNING)) { + LOGGER.log(Level.WARNING, errorMessage, e); + } + // El ImageView se queda vacío si no encuentra la imagen + } + } + + private void loadStone(ImageView imageView, String path, double x, double y) { + if (imageView == null) return; + try { + var stream = getClass().getResourceAsStream(path); + if (stream == null) { + logResourceNotFound(path); + return; + } + Image stone = new Image(stream); + imageView.setImage(stone); + imageView.setFitWidth(40); + imageView.setFitHeight(40); + // Ejemplo: posición sobre el tablero (ajustar según el layout real) + imageView.setLayoutX(x); + imageView.setLayoutY(y); + } catch (Exception e) { + if (LOGGER.isLoggable(Level.WARNING)) { + LOGGER.log(Level.WARNING, "No se pudo cargar la ficha", e); + } + } + } + + private void logResourceNotFound(String path) { + if (LOGGER.isLoggable(Level.WARNING)) { + LOGGER.log(Level.WARNING, String.format("%s%s", RESOURCE_NOT_FOUND_PREFIX, path)); + } + } public String greet() { return mainService != null ? mainService.greet() : "Servicio no disponible"; } static String formatApiError(ApiError apiError) { - return "Error [" + apiError.getCode() + "]: " + apiError.getMessage(); - } - - public void setSalutoLabel(Label label) { - this.salutoLabel = label; + return String.format("Error [%s]: %s", apiError.getCode(), apiError.getMessage()); } } diff --git a/src/main/java/es/iesquevedo/controller/RegisterController.java b/src/main/java/es/iesquevedo/controller/RegisterController.java new file mode 100644 index 0000000..750d439 --- /dev/null +++ b/src/main/java/es/iesquevedo/controller/RegisterController.java @@ -0,0 +1,161 @@ +package es.iesquevedo.controller; + +import es.iesquevedo.config.AppConfig; +import es.iesquevedo.config.AppState; +import es.iesquevedo.model.Player; +import es.iesquevedo.service.AuthService; +import es.iesquevedo.service.impl.AuthServiceImpl; +import es.iesquevedo.service.impl.GameServiceImpl; +import javafx.application.Platform; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.Scene; +import javafx.scene.control.*; +import javafx.stage.Stage; + +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Controlador para la pantalla de Registro. + * Permite crear nuevos usuarios en Firebase Authentication. + */ +public class RegisterController { + private static final Logger LOGGER = Logger.getLogger(RegisterController.class.getName()); + + @FXML + private TextField emailField; + @FXML + private PasswordField passwordField; + @FXML + private PasswordField confirmPasswordField; + @FXML + private Button registerButton; + @FXML + private Button backButton; + @FXML + private Label messageLabel; + + private AuthService authService; + + @FXML + public void initialize() { + // Inicializar AuthService con Firebase Auth real + this.authService = new AuthServiceImpl(); + messageLabel.setText(""); + } + + @FXML + public void onRegisterButtonClicked(ActionEvent event) { + String email = emailField.getText().trim(); + String password = passwordField.getText(); + String confirmPassword = confirmPasswordField.getText(); + + // Validaciones básicas + if (email.isEmpty()) { + showError("Por favor ingresa un email"); + return; + } + + if (password.isEmpty()) { + showError("Por favor ingresa una contraseña"); + return; + } + + if (password.length() < 6) { + showError("La contraseña debe tener al menos 6 caracteres"); + return; + } + + if (!password.equals(confirmPassword)) { + showError("Las contraseñas no coinciden"); + return; + } + + // Validar email básico + if (!email.contains("@")) { + showError("Email inválido"); + return; + } + + registerButton.setDisable(true); + showInfo("Registrando..."); + + // Llamar al signup de AuthService + if (authService instanceof AuthServiceImpl) { + AuthServiceImpl authImpl = (AuthServiceImpl) authService; + authImpl.signup(email, password) + .thenAccept(token -> { + Platform.runLater(() -> { + AppState.getInstance().setAuthToken(token); + AppState.getInstance().setCurrentUserEmail(email); + showInfo("¡Registro exitoso! Bienvenido " + email); + navigateToMatching(email); + }); + }) + .exceptionally(ex -> { + Platform.runLater(() -> { + LOGGER.log(Level.WARNING, "Signup error: " + ex.getMessage()); + showError("Error en registro: " + ex.getMessage()); + registerButton.setDisable(false); + }); + return null; + }); + } + } + + @FXML + public void onBackButtonClicked(ActionEvent event) { + navigateToLogin(); + } + + private void showError(String message) { + messageLabel.setStyle("-fx-text-fill: #cc0000;"); + messageLabel.setText(message); + } + + private void showInfo(String message) { + messageLabel.setStyle("-fx-text-fill: #0066cc;"); + messageLabel.setText(message); + } + + private void navigateToMatching(String email) { + try { + FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/MatchingScreen.fxml")); + Scene scene = new Scene(loader.load(), 500, 300); + es.iesquevedo.ui.MatchingScreenController controller = loader.getController(); + String playerName = buildDisplayName(email); + controller.startMatching(new Player(email, playerName)); + Stage stage = (Stage) registerButton.getScene().getWindow(); + stage.setScene(scene); + stage.setTitle("InazumaGo - Emparejamiento"); + } catch (IOException e) { + LOGGER.log(Level.SEVERE, "Error navigating to Matching: " + e.getMessage()); + showError("Error al abrir la pantalla de emparejamiento"); + } + } + + private String buildDisplayName(String email) { + if (email == null || email.trim().isEmpty()) { + return "Jugador"; + } + int atIndex = email.indexOf('@'); + return atIndex > 0 ? email.substring(0, atIndex) : email; + } + + private void navigateToLogin() { + try { + FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/Login.fxml")); + Scene scene = new Scene(loader.load(), 400, 300); + Stage stage = (Stage) backButton.getScene().getWindow(); + stage.setScene(scene); + } catch (IOException e) { + LOGGER.log(Level.SEVERE, "Error navigating to Login: " + e.getMessage()); + } + } +} + + + diff --git a/src/main/java/es/iesquevedo/service/impl/AuthServiceImpl.java b/src/main/java/es/iesquevedo/service/impl/AuthServiceImpl.java index 260306d..a67bd89 100644 --- a/src/main/java/es/iesquevedo/service/impl/AuthServiceImpl.java +++ b/src/main/java/es/iesquevedo/service/impl/AuthServiceImpl.java @@ -1,38 +1,135 @@ package es.iesquevedo.service.impl; +import com.google.gson.Gson; +import com.google.gson.JsonObject; import es.iesquevedo.service.AuthService; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; -import java.util.UUID; +import java.io.IOException; import java.util.concurrent.CompletableFuture; import java.util.logging.Level; import java.util.logging.Logger; /** - * Implementación mock de AuthService para desarrollo. - * En producción, se usaría Firebase Authentication real. + * Implementación de AuthService con Firebase Authentication REST API. + * Usa los endpoints de Google Identity Toolkit para signup/signin. */ public class AuthServiceImpl implements AuthService { private static final Logger LOGGER = Logger.getLogger(AuthServiceImpl.class.getName()); + + // Firebase Web API Key + private static final String API_KEY = "AIzaSyAiRDDRO6MJjuMgbQ28v6CvtaF2qx_ZVIk"; + + // Firebase Authentication REST endpoints + private static final String SIGN_UP_URL = "https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=" + API_KEY; + private static final String SIGN_IN_URL = "https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=" + API_KEY; + + private static final String CONTENT_TYPE = "application/json"; + + private final OkHttpClient httpClient; + private final Gson gson; private String currentToken; private String currentEmail; + private String currentUserId; + + public AuthServiceImpl() { + this.httpClient = new OkHttpClient.Builder() + .connectTimeout(10, java.util.concurrent.TimeUnit.SECONDS) + .readTimeout(10, java.util.concurrent.TimeUnit.SECONDS) + .build(); + this.gson = new Gson(); + } + + /** + * Registrar un nuevo usuario en Firebase Authentication + */ + public CompletableFuture signup(String email, String password) { + return CompletableFuture.supplyAsync(() -> { + if (email == null || email.isBlank()) { + throw new IllegalArgumentException("Email no puede estar vacío"); + } + if (password == null || password.length() < 6) { + throw new IllegalArgumentException("Contraseña debe tener al menos 6 caracteres"); + } + + try { + JsonObject requestBody = new JsonObject(); + requestBody.addProperty("email", email); + requestBody.addProperty("password", password); + requestBody.addProperty("returnSecureToken", true); + + Request request = new Request.Builder() + .url(SIGN_UP_URL) + .post(RequestBody.create(gson.toJson(requestBody), + okhttp3.MediaType.parse(CONTENT_TYPE))) + .build(); + + try (Response response = httpClient.newCall(request).execute()) { + if (!response.isSuccessful() || response.body() == null) { + String errorBody = response.body() != null ? response.body().string() : "Unknown error"; + LOGGER.log(Level.WARNING, "Signup failed: " + errorBody); + throw new RuntimeException("Signup failed: HTTP " + response.code()); + } + + JsonObject responseBody = gson.fromJson(response.body().string(), JsonObject.class); + this.currentToken = responseBody.get("idToken").getAsString(); + this.currentEmail = email; + this.currentUserId = responseBody.get("localId").getAsString(); + + LOGGER.log(Level.INFO, "Signup exitoso: " + email); + return this.currentToken; + } + } catch (IOException e) { + LOGGER.log(Level.SEVERE, "Signup error: " + e.getMessage()); + throw new RuntimeException("Error en signup: " + e.getMessage(), e); + } + }); + } @Override public CompletableFuture login(String email, String password) { return CompletableFuture.supplyAsync(() -> { - // Validaciones mínimas (en prod, verificar contra Firebase Auth) if (email == null || email.isBlank()) { throw new IllegalArgumentException("Email no puede estar vacío"); } if (password == null || password.length() < 6) { throw new IllegalArgumentException("Contraseña debe tener al menos 6 caracteres"); } - - // Generar token mock (en prod sería de Firebase) - this.currentToken = "dev-token-" + UUID.randomUUID(); - this.currentEmail = email; - - LOGGER.log(Level.INFO, "Login exitoso: " + email); - return this.currentToken; + + try { + JsonObject requestBody = new JsonObject(); + requestBody.addProperty("email", email); + requestBody.addProperty("password", password); + requestBody.addProperty("returnSecureToken", true); + + Request request = new Request.Builder() + .url(SIGN_IN_URL) + .post(RequestBody.create(gson.toJson(requestBody), + okhttp3.MediaType.parse(CONTENT_TYPE))) + .build(); + + try (Response response = httpClient.newCall(request).execute()) { + if (!response.isSuccessful() || response.body() == null) { + String errorBody = response.body() != null ? response.body().string() : "Unknown error"; + LOGGER.log(Level.WARNING, "Login failed: " + errorBody); + throw new RuntimeException("Login failed: credenciales inválidas"); + } + + JsonObject responseBody = gson.fromJson(response.body().string(), JsonObject.class); + this.currentToken = responseBody.get("idToken").getAsString(); + this.currentEmail = email; + this.currentUserId = responseBody.get("localId").getAsString(); + + LOGGER.log(Level.INFO, "Login exitoso: " + email); + return this.currentToken; + } + } catch (IOException e) { + LOGGER.log(Level.SEVERE, "Login error: " + e.getMessage()); + throw new RuntimeException("Error en login: " + e.getMessage(), e); + } }); } @@ -41,10 +138,19 @@ public String getCurrentToken() { return currentToken; } + public String getCurrentUserId() { + return currentUserId; + } + + public String getCurrentEmail() { + return currentEmail; + } + @Override public void logout() { this.currentToken = null; this.currentEmail = null; + this.currentUserId = null; LOGGER.log(Level.INFO, "Logout realizado"); } } diff --git a/src/main/java/es/iesquevedo/ui/MatchingScreenController.java b/src/main/java/es/iesquevedo/ui/MatchingScreenController.java index 9bdb5bf..41745a8 100644 --- a/src/main/java/es/iesquevedo/ui/MatchingScreenController.java +++ b/src/main/java/es/iesquevedo/ui/MatchingScreenController.java @@ -4,6 +4,7 @@ import es.iesquevedo.model.Game; import es.iesquevedo.model.Player; import es.iesquevedo.service.GameService; +import es.iesquevedo.service.impl.GameServiceImpl; import javafx.application.Platform; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; @@ -33,7 +34,10 @@ public class MatchingScreenController { @FXML private Button cancelButton; - private GameService gameService; + @FXML + private Button searchButton; + + private GameService gameService = new GameServiceImpl(); private Player currentPlayer; private Timer timer; private int elapsedSeconds = 0; @@ -46,6 +50,23 @@ public void setGameService(GameService gameService) { public void startMatching(Player player) { this.currentPlayer = player; + if (this.gameService == null) { + this.gameService = new GameServiceImpl(); + } + updateReadyState(); + } + + @FXML + private void onSearchClicked() { + if (currentPlayer == null) { + statusLabel.setText("No hay jugador autenticado"); + return; + } + if (searching) { + return; + } + searching = true; + elapsedSeconds = 0; startTimer(); startSearch(); } @@ -65,6 +86,12 @@ public void run() { private void startSearch() { statusLabel.setText("Buscando jugador disponible..."); + if (searchButton != null) { + searchButton.setDisable(true); + } + if (cancelButton != null) { + cancelButton.setText("Cancelar"); + } currentSearch = CompletableFuture.supplyAsync(() -> { try { @@ -84,6 +111,10 @@ private void startSearch() { if (game != null && searching) { Platform.runLater(() -> { stopTimer(); + searching = false; + if (searchButton != null) { + searchButton.setDisable(false); + } statusLabel.setText("¡Oponente encontrado!"); navigateToGame(game.getId()); }); @@ -92,6 +123,10 @@ private void startSearch() { Platform.runLater(() -> { if (searching) { statusLabel.setText("Error en la búsqueda. Intenta de nuevo."); + searching = false; + if (searchButton != null) { + searchButton.setDisable(false); + } cancelButton.setText("Volver"); } }); @@ -126,23 +161,45 @@ private void navigateToGame(String gameId) { @FXML private void onCancel() { - searching = false; - if (currentSearch != null) { - currentSearch.cancel(true); + if (searching) { + searching = false; + if (currentSearch != null) { + currentSearch.cancel(true); + } + stopTimer(); + if (searchButton != null) { + searchButton.setDisable(false); + } + goBackToMainMenu(); + return; } - stopTimer(); goBackToMainMenu(); } + private void updateReadyState() { + searching = false; + statusLabel.setText(currentPlayer != null + ? "Listo para buscar partida. Pulsa 'Buscar partida'." + : "Cargando jugador..."); + if (timeLabel != null) { + timeLabel.setText("Tiempo de espera: 0s"); + } + if (searchButton != null) { + searchButton.setDisable(false); + } + if (cancelButton != null) { + cancelButton.setText("Volver"); + } + } + private void goBackToMainMenu() { try { - FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/MainScreen.fxml")); + FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/Login.fxml")); Parent root = loader.load(); - // Just load the main screen - no additional setup needed Stage stage = (Stage) cancelButton.getScene().getWindow(); stage.setScene(new Scene(root, 700, 500)); - stage.setTitle("InazumaGo - Pantalla Principal"); + stage.setTitle("InazumaGo - Login"); stage.show(); } catch (IOException e) { diff --git a/src/main/resources/fxml/Login.fxml b/src/main/resources/fxml/Login.fxml index e4aa710..69d370e 100644 --- a/src/main/resources/fxml/Login.fxml +++ b/src/main/resources/fxml/Login.fxml @@ -1,59 +1,54 @@ - - - - - - - - - - - - - - -