-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #139 from Team-40-IDATT2003/123-quit-button-pop-up
123 quit button pop up
- Loading branch information
Showing
8 changed files
with
810 additions
and
157 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
23 changes: 23 additions & 0 deletions
23
src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ingame/quit/QuitDialogActions.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| package edu.ntnu.idi.idatt2003.g40.mappe.view.ingame.quit; | ||
|
|
||
| /** | ||
| * User-triggered actions available in the in-game quit dialog overlay. | ||
| * | ||
| * <p>The quit dialog is shown when the player clicks the "Quit" button | ||
| * from the in-game dashboard, and lets them choose between continuing, | ||
| * saving in place, saving and returning to the main menu, or saving | ||
| * and exiting the application.</p> | ||
| * */ | ||
| public enum QuitDialogActions { | ||
| /** Closes the dialog and returns the player to the game. */ | ||
| CONTINUE, | ||
|
|
||
| /** Saves the current game state without leaving the in-game session. */ | ||
| SAVE, | ||
|
|
||
| /** Saves the current game state and returns to the main menu. */ | ||
| SAVE_AND_QUIT_TO_MAIN_MENU, | ||
|
|
||
| /** Saves the current game state and exits the application. */ | ||
| SAVE_AND_QUIT_GAME; | ||
| } |
188 changes: 188 additions & 0 deletions
188
src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ingame/quit/QuitDialogController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,188 @@ | ||
| package edu.ntnu.idi.idatt2003.g40.mappe.view.ingame.quit; | ||
|
|
||
| import edu.ntnu.idi.idatt2003.g40.mappe.model.SaveGame; | ||
| import edu.ntnu.idi.idatt2003.g40.mappe.service.GameStateLoader; | ||
| import edu.ntnu.idi.idatt2003.g40.mappe.service.SaveGameService; | ||
| import edu.ntnu.idi.idatt2003.g40.mappe.service.event.EventManager; | ||
| import edu.ntnu.idi.idatt2003.g40.mappe.view.ViewController; | ||
| import edu.ntnu.idi.idatt2003.g40.mappe.view.ViewEnum; | ||
| import edu.ntnu.idi.idatt2003.g40.mappe.view.ingame.InGameView; | ||
|
|
||
| /** | ||
| * Controller for {@link QuitDialogView}. | ||
| * | ||
| * <p>Wires the four dialog buttons to the appropriate save / scene-change | ||
| * / application-exit actions:</p> | ||
| * <ul> | ||
| * <li>{@code CONTINUE} - hides the overlay; the player stays in the | ||
| * current game session.</li> | ||
| * <li>{@code SAVE} - snapshots and writes the active save to disk, but | ||
| * keeps the overlay open so the player sees the confirmation message. | ||
| * They can then choose to continue, quit, or exit.</li> | ||
| * <li>{@code SAVE_AND_QUIT_TO_MAIN_MENU} - snapshots, writes to disk, | ||
| * hides the overlay, and changes the scene back to the main menu.</li> | ||
| * <li>{@code SAVE_AND_QUIT_GAME} - snapshots, writes to disk, then | ||
| * invokes the configured exit-application runnable to close the JVM.</li> | ||
| * </ul> | ||
| * | ||
| * <p>The save logic mirrors the auto-save hook in {@code Main}: a missing | ||
| * active save (e.g. before any game has been loaded) is treated as a | ||
| * no-op rather than an error, since there's nothing meaningful to write.</p> | ||
| * */ | ||
| public final class QuitDialogController | ||
| extends ViewController<QuitDialogView> { | ||
|
|
||
| /** The in-game view hosting this overlay. */ | ||
| private final InGameView inGameView; | ||
|
|
||
| /** Builds {@link SaveGame} snapshots of the current player/exchange. */ | ||
| private final GameStateLoader gameStateLoader; | ||
|
|
||
| /** Persists save games to disk. */ | ||
| private final SaveGameService saveGameService; | ||
|
|
||
| /** Runnable invoked to close the application. */ | ||
| private Runnable onExitApplication = () -> { }; | ||
|
|
||
| /** | ||
| * Constructor. | ||
| * | ||
| * @param view the {@link QuitDialogView} this controller is | ||
| * attached to. | ||
| * @param eventManager the active {@link EventManager}, used to | ||
| * publish scene-change events. | ||
| * @param inGameView the in-game view that hosts this overlay. | ||
| * @param gameStateLoader the loader used to snapshot the active save. | ||
| * @param saveGameService the service used to persist saves to disk. | ||
| * | ||
| * @throws IllegalArgumentException if any constructor argument is null. | ||
| * */ | ||
| public QuitDialogController(final QuitDialogView view, | ||
| final EventManager eventManager, | ||
| final InGameView inGameView, | ||
| final GameStateLoader gameStateLoader, | ||
| final SaveGameService saveGameService) | ||
| throws IllegalArgumentException { | ||
| this.inGameView = inGameView; | ||
| this.gameStateLoader = gameStateLoader; | ||
| this.saveGameService = saveGameService; | ||
| super(view, eventManager); | ||
| if (inGameView == null | ||
| || gameStateLoader == null | ||
| || saveGameService == null) { | ||
| throw new IllegalArgumentException( | ||
| "Invalid QuitDialogController arguments!"); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Installs the runnable used to close the application when the player | ||
| * chooses "Save and quit game". | ||
| * | ||
| * <p>Typically this is wired to {@code Platform.exit()} (plus a | ||
| * {@code System.exit(0)} fallback) from {@code Main}, so the controller | ||
| * itself stays decoupled from the JavaFX runtime.</p> | ||
| * | ||
| * @param exitRunnable runnable invoked after the save completes; a null | ||
| * value resets the hook to a no-op. | ||
| * */ | ||
| public void setOnExitApplication(final Runnable exitRunnable) { | ||
| this.onExitApplication = | ||
| (exitRunnable != null) ? exitRunnable : () -> { }; | ||
| } | ||
|
|
||
| /** {@inheritDoc} */ | ||
| @Override | ||
| protected void initInteractions() { | ||
| getViewElement().setOnAction(QuitDialogActions.CONTINUE, this::close); | ||
|
|
||
| getViewElement().setOnAction(QuitDialogActions.SAVE, () -> { | ||
| boolean ok = performSave(); | ||
| if (ok) { | ||
| getViewElement().setStatus("Game saved.", false); | ||
| } | ||
| // Failures already wrote an error to the status label inside | ||
| // performSave(); nothing more to do here. | ||
| }); | ||
|
|
||
| getViewElement().setOnAction( | ||
| QuitDialogActions.SAVE_AND_QUIT_TO_MAIN_MENU, () -> { | ||
| if (performSave()) { | ||
| close(); | ||
| changeScene(ViewEnum.MAIN_MENU); | ||
| } | ||
| }); | ||
|
|
||
| getViewElement().setOnAction(QuitDialogActions.SAVE_AND_QUIT_GAME, () -> { | ||
| if (performSave()) { | ||
| close(); | ||
| onExitApplication.run(); | ||
| } | ||
| }); | ||
| } | ||
|
|
||
| /** | ||
| * Shows the quit dialog overlay on the host {@link InGameView}. | ||
| * | ||
| * <p>Clears any stale status message left over from a previous opening | ||
| * so the player doesn't see "Game saved." from a save they made hours | ||
| * ago.</p> | ||
| * */ | ||
| public void show() { | ||
| getViewElement().setStatus(null, false); | ||
| inGameView.showSettingsOverlay(getViewElement().getRootPane()); | ||
| } | ||
|
|
||
| /** | ||
| * Hides the overlay if it's currently visible. | ||
| * */ | ||
| private void close() { | ||
| inGameView.hideSettingsOverlay(); | ||
| } | ||
|
|
||
| /** | ||
| * Snapshots the active save and writes it to disk. | ||
| * | ||
| * <p>If no save is currently active (e.g. the player got into the | ||
| * in-game view through a path that doesn't load a save), this is | ||
| * treated as a successful no-op so the quit / exit flows can proceed. | ||
| * Any I/O failure is reported back to the player via the dialog's | ||
| * status label.</p> | ||
| * | ||
| * @return {@code true} when the operation can be considered successful | ||
| * (a real save was written, or no save was needed); {@code false} | ||
| * when an actual error occurred. | ||
| * */ | ||
| private boolean performSave() { | ||
| SaveGame snapshot; | ||
| try { | ||
| snapshot = gameStateLoader.snapshotActiveSave(); | ||
| } catch (Exception e) { | ||
| System.err.println("[quit-dialog] Snapshot failed: " | ||
| + e.getMessage()); | ||
| getViewElement().setStatus( | ||
| "Could not prepare save: " + e.getMessage(), true); | ||
| return false; | ||
| } | ||
|
|
||
| if (snapshot == null) { | ||
| System.out.println( | ||
| "[quit-dialog] No active save - nothing to write."); | ||
| // Nothing to persist, but the user's intent (continue past this | ||
| // step) is still valid - treat as success. | ||
| return true; | ||
| } | ||
|
|
||
| try { | ||
| saveGameService.saveGame(snapshot); | ||
| System.out.println("[quit-dialog] Wrote save '" | ||
| + snapshot.getName() + "' to disk."); | ||
| return true; | ||
| } catch (Exception e) { | ||
| System.err.println("[quit-dialog] Save failed: " + e.getMessage()); | ||
| getViewElement().setStatus( | ||
| "Save failed: " + e.getMessage(), true); | ||
| return false; | ||
| } | ||
| } | ||
| } |
Oops, something went wrong.