From 6d16b6d8eb1a13ba66b9a011b2d21b506b34797a Mon Sep 17 00:00:00 2001 From: JavierDS12 Date: Tue, 12 May 2026 12:37:08 +0200 Subject: [PATCH 1/3] =?UTF-8?q?A=C3=B1adido=20de=20imagenes=20de=20tablero?= =?UTF-8?q?=20y=20fichas=20en=20la=20interfaz?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iesquevedo/controller/MainController.java | 78 +++++++++++++++++- src/main/resources/fxml/Main.fxml | 9 ++ src/main/resources/images/game-board.png | Bin 0 -> 17664 bytes src/main/resources/images/stone-black.png | Bin 0 -> 2860 bytes src/main/resources/images/stone-white.png | Bin 0 -> 6076 bytes .../iesquevedo/service/MainServiceTest.java | 32 ++++--- 6 files changed, 105 insertions(+), 14 deletions(-) create mode 100644 src/main/resources/images/game-board.png create mode 100644 src/main/resources/images/stone-black.png create mode 100644 src/main/resources/images/stone-white.png diff --git a/src/main/java/es/iesquevedo/controller/MainController.java b/src/main/java/es/iesquevedo/controller/MainController.java index e7e2fb5..779ed55 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,25 @@ 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 MainService mainService; @FXML private Label salutoLabel; + @FXML + private ImageView gameBoardImageView; + + @FXML + private ImageView blackStoneImageView; + + @FXML + private ImageView whiteStoneImageView; + public MainController() { // Constructor sin parámetros necesario para FXML this.mainService = null; @@ -35,7 +51,9 @@ public void initialize() { try { String saludo = mainService.greet(); salutoLabel.setText(saludo); - LOGGER.info("Saludo establecido: " + saludo); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info(String.format("Saludo establecido: %s", saludo)); + } } catch (RuntimeException e) { ApiError apiError = errorHandler.toApiError(e); LOGGER.log(Level.SEVERE, "Error al obtener saludo del servicio", e); @@ -44,6 +62,62 @@ public void initialize() { } else if (salutoLabel != null) { salutoLabel.setText("Servicio no disponible"); } + + // Cargar imagen del tablero y fichas + loadGameBoard(); + loadStones(); + } + + private void loadGameBoard() { + if (gameBoardImageView != null) { + try { + Image image = new Image(getClass().getResourceAsStream(GAME_BOARD_PATH)); + gameBoardImageView.setImage(image); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info("Tablero cargado correctamente"); + } + } catch (Exception e) { + if (LOGGER.isLoggable(Level.WARNING)) { + LOGGER.log(Level.WARNING, "No se pudo cargar la imagen del tablero", e); + } + // El ImageView se queda vacío si no encuentra la imagen + } + } + } + + private void loadStones() { + // Cargar ficha negra + if (blackStoneImageView != null) { + try { + Image blackStone = new Image(getClass().getResourceAsStream(BLACK_STONE_PATH)); + blackStoneImageView.setImage(blackStone); + blackStoneImageView.setFitWidth(40); + blackStoneImageView.setFitHeight(40); + // Ejemplo: posición sobre el tablero (ajustar según el layout real) + blackStoneImageView.setLayoutX(100); + blackStoneImageView.setLayoutY(100); + } catch (Exception e) { + if (LOGGER.isLoggable(Level.WARNING)) { + LOGGER.log(Level.WARNING, "No se pudo cargar la ficha negra", e); + } + } + } + // Cargar ficha blanca + if (whiteStoneImageView != null) { + try { + Image whiteStone = new Image(getClass().getResourceAsStream(WHITE_STONE_PATH)); + whiteStoneImageView.setImage(whiteStone); + whiteStoneImageView.setFitWidth(40); + whiteStoneImageView.setFitHeight(40); + // Ejemplo: posición sobre el tablero (ajustar según el layout real) + whiteStoneImageView.setLayoutX(200); + whiteStoneImageView.setLayoutY(200); + } catch (Exception e) { + if (LOGGER.isLoggable(Level.WARNING)) { + LOGGER.log(Level.WARNING, "No se pudo cargar la ficha blanca", e); + } + } + } } public String greet() { @@ -51,7 +125,7 @@ public String greet() { } static String formatApiError(ApiError apiError) { - return "Error [" + apiError.getCode() + "]: " + apiError.getMessage(); + return String.format("Error [%s]: %s", apiError.getCode(), apiError.getMessage()); } public void setSalutoLabel(Label label) { diff --git a/src/main/resources/fxml/Main.fxml b/src/main/resources/fxml/Main.fxml index 74e3b63..1d55004 100644 --- a/src/main/resources/fxml/Main.fxml +++ b/src/main/resources/fxml/Main.fxml @@ -1,6 +1,8 @@ + + diff --git a/src/main/resources/images/game-board.png b/src/main/resources/images/game-board.png new file mode 100644 index 0000000000000000000000000000000000000000..ab002bc0d6cabe7e8713b8b503f4a9eec56d19ca GIT binary patch literal 17664 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/images/stone-black.png b/src/main/resources/images/stone-black.png new file mode 100644 index 0000000000000000000000000000000000000000..f48011b923e67cf2b51b66f14e80284dbb279d16 GIT binary patch literal 2860 zcmYk8c{~(c7sqGpW(*m`*hALFQuYSn$&wn3wPZ`0L4<5igAt)-EW;=yYbe>5tXYy| zUn*O~*s_g%%~)P~p7-;<_jAuZzt8WS`@Q$igEG|969WSPR#$aQEKO9cK>z@N=_Js= z(|zIy|8-)?n*vgS(ik8HsOhWz(opPmR;K8~JZmEBGZ&9Z$0Oz=;2y^wMiT!-+Ooh+qFBCi45B2VAkmzUXCWm|M?r=F>Td?+H zAqx-DV;QjRoW;3n@|3bms6eN%st(2c=D{Ail1Ip~fa!2tdCSbe8|F5P!m+y%8iu=M zrB>qfGWV7;rWNnAwKb_z-d||krFA9p6Vzj>-RX-TSGvI)Phzif>eTG4rJfuAGkzs+ z1&ROR$cv6ehMGbP?>hNl1H&<#9k72HxveeUmWB@sQM$5C3 z7HSVJpUbD?f7*l-=aSv?vtBHj%8g*nO@AO`i`r_=nPBY{H6qb1np5@n*jdgcQ%)}e z8zs;-8@7s_oO(wsArr$yzEIGYw@K;+y84FUMhyZl^z4HGYJ&=w&eM&jG&rJGBc0>W z-j)2+4RlOU>(F`k$f(?pt z+)pHEgEwMJjTunUGKNh7b{Qc>(fkdXyP6*t!vFv(L4K7Teodw?Kw`_c=wm7SP$)@b zRs1=~aWs+>Rxd1BYwrFUE#bkTYq9>pJ82P!u9!+3+fT9c;~T~ofGo|1(2euT)l%-bfUF zOOW|c0F(G_Przul$sy3Fsv2UaJQh{jw6xUvl15l7Hr3dfo!gSOnzI8jeQ>9wr z3KbruI0e0RtW~hhj+7+bR^wiQV65_Fb@P>bV|r0L3)wf4)lfZVXqWk>9cQyI;L0 zVZ(CIdm{=noxN+sdRvNnF1@}X6^@B1-SpMwu^%0*#>p5PKq3on^lF-p<;PGul{SzN z%1nz!XHD_6{|nAmslgSd6!+jHlurzd{4_Lu_Ux{rk##mWhJCyH8Tdn(*cj|FJt**E zokX?k{U3uY{zV}%tCb`;kmx>`YBd8C(ZVD%GAaXEcJu3l0R= z2>jqEq9u84eE@zOM9(lBO*_{u=w#Gt^1|?U*$xq8mD0^Kou1D%a(~xn6>#UpLS{$0e(4GR)m>BbW1jVnj%Dy0bZ`7EH<)?m5tqc ztI-41bUm3A)yneVRev=bT^&$Us4I*u0QQ0s^Z^m6!=zr{u~v&2d{Er=8+)lISr#MJ zs^G-Qv2BOS61_HItah!9Z}bSl0J2-(W|9_Fx}i9vTC(utu18%(cKpPz2>Y;|V zhTx)OTvXh>6gtpmQ1N|Vug#PtbEKLfeT&;F%%!76=RQMBrpa>eea#5HoI5MkWbT}-XJuku#7 zd=5og9En_L`&-EUB^}iCxpH3mJY0IC=>Wx?22H4dbjc9tQQ@5sYizkuD68bzTt?1m z0UD>zDr*+>=keXEMjMWe4ry;26<|XqoKWra*BE_wuIg%uwY3}6g_tBk%Iy^Q&#AH^ zOuuh^x#dV`Hu#t?9lOzCY|$8huDe9+Yf!-QLDHxff5@szGy=j4Tqd@XBld2DDnru4 z-MkGXT|*Db&b7I5w@>iQ&dYpcY#R;wO5=rACJI# zzA+AN;t|4=B<9OMFLYwh$K2U(T6UNAS47p}A4|+UY?|M>P!S^+Y(eyhQ8VinPEHa1 zXx3Gvs`nkVUo>7&@*Rdm7*F3b&Vkbe1yx)YOqO<>>YcLwmLe61CuARIM1uMSf@4Ay zd!)}l%+R72%nIGeV20ZsPD6bxzCVk^a2KRwdLE5WMC=}3L2kT+22DH9lWvl2uAZx? znbYLtRp;4*SjmV7by|)dQ8!=bjAK|hN-eFbQ9MK0Mua=WzV}gH%%goDbs($9bCZ^Q z!f#lY9INAoU%eAc?{8H#<}#bb`&;>VSFy(P2N=B{iD#TIbBk3+`qcjoUITJfM<3rz z3Dss_&`&q3jSUX|@lxtB-58pg=ctA)@x{A#pk&7rUzfnLK^s+(4>|T1OIBL^XiC9i zu8(_#@GI-}a<`+>%r(bp2WW>&*NoRp+@3hn?cruswJ?(~B^gw?-stIm>IoN6^OZ$pdRm!}s7k2fOnVa@UbhG*w&o6sv-h6mkFs!rfI+SuW(4v;Hf_Ro_1YNa8+nMAf82eEh} z)HV4E`PFAR7^Xpgt~nZLQOk!!T`V9_rk`!vLQhhy0DJ`I-oAu&3&sM|g>L7Ub+)2D4@)6I1`PxRgh z!I9RUY-m@Yu3KVqr5>z$YSXrSQg&3u^@?98PS$>_U!1{_<0de!e7 zmQWC}rXOrk-{VrTf;SB&O-?4ttJa2kwWm42&SU^UfwTbNiGLcrK>9z~ z@QTb6G#4{f;=$p9}PSq g05bmd73AfC8UGNEj{yLhjDLuj6AbPD=~MiF0E0g^=l}o! literal 0 HcmV?d00001 diff --git a/src/main/resources/images/stone-white.png b/src/main/resources/images/stone-white.png new file mode 100644 index 0000000000000000000000000000000000000000..ec727a166e2eda7fa3099aa760ffc61003f37cc5 GIT binary patch literal 6076 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

4ptnV3MuV2^5_#|d3qA9mn!#=9w zLyMs7=CdQzM7fsTun{Wi3jyYNY59YC_iEJnDFJL3Gaf4nByP>o`eedkTXKeE%ur%R zkW@x8paC>%O2;wpgk${xwEn0*KTu`=N$)sx^vOA2K~DIGZENXu%`?g{-t}vx%-0Rm z?ZC`(kAiYF-X7KJ2@G)_=q~CfhI0niku;0QtI**v_8+CmIt<=ITNjCU!2V5xkY|dk zzM~%wNsXqtQb}IZ5awCArk6^x-fr*B_LA5)()1^6*xMEYrR7gTKuw)4IXbf}hw4r` z;^>4U*c;6WC-V+U+v>|xp+q-PFX^I`bvP((`g)(;TzqCf>^_U=4UpWfSj5I}FX(Kf zKDRi|8=3>&GyMJF20--`fXPtX7{|E)TInfAYI z@|QXOJA?L@$Ssb6$=1}!v Date: Tue, 12 May 2026 12:47:49 +0200 Subject: [PATCH 2/3] =?UTF-8?q?A=C3=B1adido=20de=20imagenes=20de=20tablero?= =?UTF-8?q?=20y=20fichas=20en=20la=20interfaz?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iesquevedo/controller/MainController.java | 127 ++++++++++-------- 1 file changed, 74 insertions(+), 53 deletions(-) diff --git a/src/main/java/es/iesquevedo/controller/MainController.java b/src/main/java/es/iesquevedo/controller/MainController.java index 779ed55..a78efca 100644 --- a/src/main/java/es/iesquevedo/controller/MainController.java +++ b/src/main/java/es/iesquevedo/controller/MainController.java @@ -18,6 +18,7 @@ public class MainController { 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; @@ -25,12 +26,15 @@ public class MainController { private Label salutoLabel; @FXML + @SuppressWarnings("FieldCanBeLocal") private ImageView gameBoardImageView; @FXML + @SuppressWarnings("FieldCanBeLocal") private ImageView blackStoneImageView; @FXML + @SuppressWarnings("FieldCanBeLocal") private ImageView whiteStoneImageView; public MainController() { @@ -47,78 +51,99 @@ 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); - if (LOGGER.isLoggable(Level.INFO)) { - LOGGER.info(String.format("Saludo establecido: %s", 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"); } - - // Cargar imagen del tablero y fichas - loadGameBoard(); - loadStones(); + } + + 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) { - try { - Image image = new Image(getClass().getResourceAsStream(GAME_BOARD_PATH)); - gameBoardImageView.setImage(image); - if (LOGGER.isLoggable(Level.INFO)) { - LOGGER.info("Tablero cargado correctamente"); - } - } catch (Exception e) { - if (LOGGER.isLoggable(Level.WARNING)) { - LOGGER.log(Level.WARNING, "No se pudo cargar la imagen del tablero", e); - } - // El ImageView se queda vacío si no encuentra la imagen - } + loadImage(gameBoardImageView, GAME_BOARD_PATH, "Tablero cargado correctamente", "No se pudo cargar la imagen del tablero"); } } private void loadStones() { - // Cargar ficha negra - if (blackStoneImageView != null) { - try { - Image blackStone = new Image(getClass().getResourceAsStream(BLACK_STONE_PATH)); - blackStoneImageView.setImage(blackStone); - blackStoneImageView.setFitWidth(40); - blackStoneImageView.setFitHeight(40); - // Ejemplo: posición sobre el tablero (ajustar según el layout real) - blackStoneImageView.setLayoutX(100); - blackStoneImageView.setLayoutY(100); - } catch (Exception e) { + 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, "No se pudo cargar la ficha negra", e); + 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 } - // Cargar ficha blanca - if (whiteStoneImageView != null) { - try { - Image whiteStone = new Image(getClass().getResourceAsStream(WHITE_STONE_PATH)); - whiteStoneImageView.setImage(whiteStone); - whiteStoneImageView.setFitWidth(40); - whiteStoneImageView.setFitHeight(40); - // Ejemplo: posición sobre el tablero (ajustar según el layout real) - whiteStoneImageView.setLayoutX(200); - whiteStoneImageView.setLayoutY(200); - } catch (Exception e) { - if (LOGGER.isLoggable(Level.WARNING)) { - LOGGER.log(Level.WARNING, "No se pudo cargar la ficha blanca", e); - } + } + + 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"; @@ -127,8 +152,4 @@ public String greet() { static String formatApiError(ApiError apiError) { return String.format("Error [%s]: %s", apiError.getCode(), apiError.getMessage()); } - - public void setSalutoLabel(Label label) { - this.salutoLabel = label; - } } From d2b541326109b63ace750838ee9e17c29f2fac23 Mon Sep 17 00:00:00 2001 From: Santaro13 Date: Fri, 22 May 2026 15:23:22 +0200 Subject: [PATCH 3/3] Registro de usuarios real implementando ui existente --- .../iesquevedo/controller/GameController.java | 38 ++++- .../controller/LoginController.java | 64 +++++-- .../controller/RegisterController.java | 161 ++++++++++++++++++ .../service/impl/AuthServiceImpl.java | 128 ++++++++++++-- .../ui/MatchingScreenController.java | 73 +++++++- src/main/resources/fxml/Login.fxml | 109 ++++++------ src/main/resources/fxml/MatchingScreen.fxml | 12 +- src/main/resources/fxml/Register.fxml | 55 ++++++ .../controller/RegisterControllerTest.java | 84 +++++++++ .../iesquevedo/service/AuthServiceTest.java | 41 +++-- 10 files changed, 649 insertions(+), 116 deletions(-) create mode 100644 src/main/java/es/iesquevedo/controller/RegisterController.java create mode 100644 src/main/resources/fxml/Register.fxml create mode 100644 src/test/java/es/iesquevedo/controller/RegisterControllerTest.java 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/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 @@ - - - - - - - - - - - - - - -