diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/playgame/PlayGameActions.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/playgame/PlayGameActions.java index 03053e3..aa52832 100644 --- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/playgame/PlayGameActions.java +++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/playgame/PlayGameActions.java @@ -3,4 +3,5 @@ public enum PlayGameActions { NEW_GAME, BACK, + UPLOAD_SAVE, } diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/playgame/PlayGameController.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/playgame/PlayGameController.java index 22d9db4..4ca725c 100644 --- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/playgame/PlayGameController.java +++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/playgame/PlayGameController.java @@ -1,13 +1,29 @@ package edu.ntnu.idi.idatt2003.g40.mappe.view.playgame; +import edu.ntnu.idi.idatt2003.g40.mappe.model.SaveGame; +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 java.io.File; +import java.util.List; + +import javafx.scene.Scene; +import javafx.scene.control.Alert; +import javafx.scene.control.Alert.AlertType; +import javafx.stage.FileChooser; +import javafx.stage.Window; + /** * Controller for the {@link PlayGameView}. * *

Extends {@link ViewController}

+ * + *

+ * Handles three user actions: starting a new game, going back to the + * main menu, and uploading a custom save file from disk. + *

*/ public class PlayGameController extends ViewController { @@ -24,19 +40,88 @@ public PlayGameController(final PlayGameView view, } /** - * {@inheritDoc}- + * {@inheritDoc} * - *

Sets create new game, back, and save-row click functionality.

+ *

Sets create new game, upload save, back, and save-row click + * functionality.

*/ @Override protected void initInteractions() { getViewElement().setOnAction(PlayGameActions.NEW_GAME, () -> - changeScene(ViewEnum.IN_GAME)); + changeScene(ViewEnum.IN_GAME)); getViewElement().setOnAction(PlayGameActions.BACK, () -> - changeScene(ViewEnum.MAIN_MENU)); + changeScene(ViewEnum.MAIN_MENU)); + + getViewElement().setOnAction(PlayGameActions.UPLOAD_SAVE, + this::handleUploadSave); getViewElement().setOnSaveSelected(save -> - changeScene(ViewEnum.IN_GAME)); + changeScene(ViewEnum.IN_GAME)); + } + + /** + * Opens a {@link FileChooser} for the user to pick a save file from + * disk. Parses it using {@link SaveGameService} and appends the + * loaded saves to the view's current list. + * + *

+ * Shows an alert if the user picks a file that contains no valid + * save entries. + *

+ */ + private void handleUploadSave() { + FileChooser fileChooser = new FileChooser(); + fileChooser.setTitle("Choose save file"); + fileChooser.getExtensionFilters().addAll( + new FileChooser.ExtensionFilter("Save files (*.txt)", "*.txt"), + new FileChooser.ExtensionFilter("All files", "*.*") + ); + + Window window = getOwnerWindow(); + File selectedFile = fileChooser.showOpenDialog(window); + if (selectedFile == null) { + // User cancelled the dialog. + return; + } + + SaveGameService service = + new SaveGameService(selectedFile.getAbsolutePath()); + List uploadedSaves = service.loadSaves(); + + if (uploadedSaves.isEmpty()) { + showAlert(AlertType.WARNING, + "No saves found", + "The selected file did not contain any valid save entries.\n\n" + + "Expected format (one entry per line):\n" + + " SaveName, 1234567.89"); + return; + } + + getViewElement().addSaves(uploadedSaves); + } + + /** + * Looks up the {@link Window} that hosts the view, so we can parent + * the file chooser to it. Returns null if the view is not yet + * attached to a scene (in which case the FileChooser opens + * un-parented, which still works). + */ + private Window getOwnerWindow() { + Scene scene = getViewElement().getRootPane().getScene(); + return (scene != null) ? scene.getWindow() : null; + } + + /** + * Shows a modal {@link Alert} with the given type, header and content. + */ + private void showAlert(final AlertType type, + final String header, + final String content) { + Alert alert = new Alert(type); + alert.setTitle("Upload save"); + alert.setHeaderText(header); + alert.setContentText(content); + alert.showAndWait(); } -} \ No newline at end of file +} diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/playgame/PlayGameView.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/playgame/PlayGameView.java index f4f5691..3403b68 100644 --- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/playgame/PlayGameView.java +++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/playgame/PlayGameView.java @@ -27,8 +27,8 @@ * View shown after the player clicks "Play" on the main menu. * *

- * Displays a list of existing save games and two action buttons: - * "Create new game" and "Back". + * Displays a list of existing save games and three action buttons: + * "Create new game", "Upload save" and "Back". *

* *

@@ -41,13 +41,16 @@ public class PlayGameView extends ViewElement { /** "Create new game" button. */ private Button createNewGameButton; + /** "Upload save" button - lets the user pick a save file from disk. */ + private Button uploadSaveButton; + /** "Back" button. */ private Button backButton; /** Vertical container holding the save rows. Rebuilt on every update. */ private VBox saveListContainer; - /** Bottom row with the two action buttons. */ + /** Bottom row with the three action buttons. */ private HBox bottomButtonRow; /** Centered panel: save list + bottom buttons stacked. */ @@ -77,6 +80,8 @@ public PlayGameView() { /** * Sets the list of saves to display and rebuilds the rows. * + *

Replaces any saves currently displayed.

+ * * @param saves saves to display. */ public void setSaves(final List saves) { @@ -84,6 +89,24 @@ public void setSaves(final List saves) { rebuildSaveList(); } + /** + * Appends additional saves to the displayed list and rebuilds the rows. + * + *

+ * Used by the controller after the user uploads a save file from disk. + * Existing saves are kept; the new ones are appended at the bottom. + *

+ * + * @param newSaves saves to append. Null or empty lists are ignored. + */ + public void addSaves(final List newSaves) { + if (newSaves == null || newSaves.isEmpty()) { + return; + } + this.saves.addAll(newSaves); + rebuildSaveList(); + } + /** * Sets the handler called when a save row is clicked. * @@ -106,9 +129,11 @@ protected void initLayout() { saveListContainer.setPadding(new Insets(20)); createNewGameButton = new Button("Create new game"); + uploadSaveButton = new Button("Upload save"); backButton = new Button("Back"); - bottomButtonRow = new HBox(40, createNewGameButton, backButton); + bottomButtonRow = new HBox(20, + createNewGameButton, uploadSaveButton, backButton); bottomButtonRow.setAlignment(Pos.CENTER); mainPanel = new VBox(30, saveListContainer, bottomButtonRow); @@ -123,6 +148,7 @@ protected void initLayout() { backgroundImage.fitHeightProperty().bind(getRootPane().heightProperty()); registerButton(PlayGameActions.NEW_GAME, createNewGameButton); + registerButton(PlayGameActions.UPLOAD_SAVE, uploadSaveButton); registerButton(PlayGameActions.BACK, backButton); } @@ -132,6 +158,7 @@ protected void initStyling() { getRootPane().getStyleClass().add("main-menu-bg"); saveListContainer.getStyleClass().add("save-list"); createNewGameButton.getStyleClass().add("menu-button"); + uploadSaveButton.getStyleClass().add("menu-button"); backButton.getStyleClass().add("menu-button"); } @@ -189,4 +216,4 @@ private String formatBalance(final double balance) { DecimalFormat df = new DecimalFormat("+#,##0.00;-#,##0.00", symbols); return df.format(balance) + "kr"; } -} \ No newline at end of file +}