Skip to content

Commit

Permalink
Merge pull request #117 from Team-40-IDATT2003/enhancement/107-stats-…
Browse files Browse the repository at this point in the history
…page

upload save
  • Loading branch information
tommyah authored May 23, 2026
2 parents cde71bc + 294fdcd commit 9e70218
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
public enum PlayGameActions {
NEW_GAME,
BACK,
UPLOAD_SAVE,
}
Original file line number Diff line number Diff line change
@@ -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}.
*
* <p>Extends {@link ViewController}</p>
*
* <p>
* Handles three user actions: starting a new game, going back to the
* main menu, and uploading a custom save file from disk.
* </p>
*/
public class PlayGameController extends ViewController<PlayGameView> {

Expand All @@ -24,19 +40,88 @@ public PlayGameController(final PlayGameView view,
}

/**
* {@inheritDoc}-
* {@inheritDoc}
*
* <p>Sets create new game, back, and save-row click functionality. </p>
* <p>Sets create new game, upload save, back, and save-row click
* functionality.</p>
*/
@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.
*
* <p>
* Shows an alert if the user picks a file that contains no valid
* save entries.
* </p>
*/
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<SaveGame> 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();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
* View shown after the player clicks "Play" on the main menu.
*
* <p>
* 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".
* </p>
*
* <p>
Expand All @@ -41,13 +41,16 @@ public class PlayGameView extends ViewElement<StackPane, PlayGameActions> {
/** "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. */
Expand Down Expand Up @@ -77,13 +80,33 @@ public PlayGameView() {
/**
* Sets the list of saves to display and rebuilds the rows.
*
* <p>Replaces any saves currently displayed.</p>
*
* @param saves saves to display.
*/
public void setSaves(final List<SaveGame> saves) {
this.saves = new ArrayList<>(saves);
rebuildSaveList();
}

/**
* Appends additional saves to the displayed list and rebuilds the rows.
*
* <p>
* 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.
* </p>
*
* @param newSaves saves to append. Null or empty lists are ignored.
*/
public void addSaves(final List<SaveGame> newSaves) {
if (newSaves == null || newSaves.isEmpty()) {
return;
}
this.saves.addAll(newSaves);
rebuildSaveList();
}

/**
* Sets the handler called when a save row is clicked.
*
Expand All @@ -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);
Expand All @@ -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);
}

Expand All @@ -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");
}

Expand Down Expand Up @@ -189,4 +216,4 @@ private String formatBalance(final double balance) {
DecimalFormat df = new DecimalFormat("+#,##0.00;-#,##0.00", symbols);
return df.format(balance) + "kr";
}
}
}

0 comments on commit 9e70218

Please sign in to comment.