diff options
| author | sowgro <tpoke.ferrari@gmail.com> | 2025-11-16 02:01:58 -0500 |
|---|---|---|
| committer | sowgro <tpoke.ferrari@gmail.com> | 2025-11-16 02:01:58 -0500 |
| commit | 969b8071dd799dfaed939e10bf77b8a1ad42f9dc (patch) | |
| tree | 214016dc742a155512fbb2f851cf589509f3b361 /src/main/java/design/controller/userinput | |
| parent | cf59d52cba70742f1d4098c38b4c7a798b3d89fa (diff) | |
| parent | 43530df067b1132b944e9619bdf60b72264829ec (diff) | |
| download | designproject-design-6-969b8071dd799dfaed939e10bf77b8a1ad42f9dc.tar.gz designproject-design-6-969b8071dd799dfaed939e10bf77b8a1ad42f9dc.tar.bz2 designproject-design-6-969b8071dd799dfaed939e10bf77b8a1ad42f9dc.zip | |
Merge branch 'main' into import-exportimport-export
# Conflicts:
# data/personaldb.json
# src/main/java/design/controller/userinput/menus/MainMenu.java
# src/main/java/design/persistence/JSONLeagueDatabase.java
# src/main/java/design/persistence/JSONPersonalDatabase.java
# src/test/java/design/model/ClubTest.java
# src/test/java/design/model/GolferTest.java
Diffstat (limited to '')
10 files changed, 290 insertions, 49 deletions
diff --git a/src/main/java/design/controller/userinput/UndoActions.java b/src/main/java/design/controller/userinput/UndoActions.java new file mode 100644 index 0000000..6417284 --- /dev/null +++ b/src/main/java/design/controller/userinput/UndoActions.java @@ -0,0 +1,51 @@ +package design.controller.userinput; + +import design.model.undo.UndoManager; +import design.persistence.PersonalDatabase; +import design.runtime.Session; +import java.io.IOException; + +public final class UndoActions { + + private UndoActions() { + } + + public static void undoWithSave() { + UndoManager um = UndoManager.instance(); + if (!um.canUndo()) { + System.out.println("Nothing to undo."); + return; + } + + String label = um.peekUndoLabel(); + um.undo(); + System.out.println("Undo: " + label); + + saveCurrentGolfer(); + } + + public static void redoWithSave() { + UndoManager um = UndoManager.instance(); + if (!um.canRedo()) { + System.out.println("Nothing to redo."); + return; + } + + String label = um.peekRedoLabel(); + um.redo(); + System.out.println("Redo: " + label); + + saveCurrentGolfer(); + } + + private static void saveCurrentGolfer() { + try { + var g = Session.getCurrentGolfer(); + if (g != null) { + PersonalDatabase.instance().updateGolfer(g); + } + } catch (IOException e) { + System.err.println("Failed to save after undo/redo: " + e.getMessage()); + } + } +} diff --git a/src/main/java/design/controller/userinput/menus/CourseSearch.java b/src/main/java/design/controller/userinput/menus/CourseSearch.java index b84247a..4dd2cad 100644 --- a/src/main/java/design/controller/userinput/menus/CourseSearch.java +++ b/src/main/java/design/controller/userinput/menus/CourseSearch.java @@ -9,6 +9,7 @@ import design.model.course_search.CurrentSearchQuery; import design.model.course_search.ICourse; import design.persistence.PersonalDatabase; import design.runtime.Session; +import design.model.undo.UndoManager; import java.io.IOException; import java.util.ArrayList; @@ -71,7 +72,7 @@ public class CourseSearch extends Menu { } // recursively go through tree structure of courselist to make menu options. - // this is all for displaying the menu options, not the actual sorting. + // this is all for displaying the menu options, not the actual sorting. private void addCoursesRecursive(List<MenuOption> menuOptions, CourseList list) { for (ICourse icourse : list.getCourses()) { // if we find a leaf (course), display it as a menu option @@ -79,6 +80,8 @@ public class CourseSearch extends Menu { var name = String.format("%s, %s, Difficulty: %s, %s holes, %s total par", c.getName(), c.getLocation(), c.getDifficultyRating(), c.getHoleCount(), c.getTotalPar()); menuOptions.add(new MenuOption(name, () -> { + UndoManager.instance().capture(golfer, "Add course " + c.getName()); + // add the course, try to save to DB. golfer.addCourse(c); try { @@ -89,8 +92,7 @@ public class CourseSearch extends Menu { System.out.println("\n Course added to profile. \n"); new MainMenu().present(); - } - )); + })); } // if not, we need to traverse another courselist else if (icourse instanceof CourseList sublist) { diff --git a/src/main/java/design/controller/userinput/menus/HolePlayMenu.java b/src/main/java/design/controller/userinput/menus/HolePlayMenu.java index e0d1572..6651500 100644 --- a/src/main/java/design/controller/userinput/menus/HolePlayMenu.java +++ b/src/main/java/design/controller/userinput/menus/HolePlayMenu.java @@ -3,12 +3,15 @@ package design.controller.userinput.menus; import design.controller.userinput.Menu; import design.controller.userinput.MenuOption; import design.model.Course; +import design.model.Golfer; import design.model.Hole; import design.runtime.Session; import design.model.Club; import design.model.Round; import design.model.holeplay.HolePlayContext; import design.persistence.PersonalDatabase; +import design.model.undo.UndoManager; +import design.controller.userinput.UndoActions; import java.util.ArrayList; import java.util.List; @@ -18,10 +21,11 @@ public class HolePlayMenu extends Menu { private final Round round; private final HolePlayContext ctx; + private final Golfer golfer = Session.getCurrentGolfer(); public HolePlayMenu() { this.round = createRound(); - this.ctx = new HolePlayContext(Session.getCurrentGolfer(), round, PersonalDatabase.instance()); + this.ctx = new HolePlayContext(this.golfer, round, PersonalDatabase.instance()); } @Override @@ -34,17 +38,37 @@ public class HolePlayMenu extends Menu { public List<MenuOption> getMenuOptions() { List<MenuOption> opts = new ArrayList<>(); + // End round (always shown) 1 + opts.add(new MenuOption("end round", () -> { + UndoManager.instance().capture(golfer, "End round on " + round.getCourse().getName()); + ctx.endRoundNow(); + System.out.println("Round ended."); + new MainMenu().present(); + })); + + // 2 + opts.add(new MenuOption("undo", () -> { + UndoActions.undoWithSave(); + this.present(); + })); + + // 3 + opts.add(new MenuOption("redo", () -> { + UndoActions.redoWithSave(); + this.present(); + })); + boolean inSetup = (ctx.getCurrentPlay() == null); if (inSetup) { - // 0) Start hole + // 4) Start hole opts.add(new MenuOption("start hole", () -> { ctx.startHole(); System.out.println("Started hole " + round.getCurrentHole().getNumber() + "."); this.present(); })); } else { - // 0) Take a shot + // 4) Take a shot opts.add(new MenuOption("take a shot", () -> { var selector = new SelectClub(); selector.present(); @@ -60,6 +84,8 @@ public class HolePlayMenu extends Menu { dist = Integer.parseInt(ds); } + UndoManager.instance().capture(ctx, "Shot with " + club.getNickname() + " for " + dist + " yds"); + // Records shot ctx.recordShot(club, dist); System.out.println("Shot recorded: " + dist + " yds with " + club.getNickname()); @@ -67,23 +93,19 @@ public class HolePlayMenu extends Menu { this.present(); })); - // 1) Hole out + // 5) Hole out opts.add(new MenuOption("hole out", () -> { // Precedes to next hole int prev = round.getCurrentHole().getNumber(); + + UndoManager.instance().capture(golfer, "Hole out on " + prev + " at " + round.getCourse().getName()); + ctx.holeOut(); System.out.println("Holed out on " + prev + ". Next: " + round.getCurrentHole().getNumber()); this.present(); })); } - // End round (always shown) - opts.add(new MenuOption("end round", () -> { - ctx.endRoundNow(); - System.out.println("Round ended."); - new MainMenu().present(); - })); - return opts; } @@ -118,6 +140,8 @@ public class HolePlayMenu extends Menu { // Starts round and sends user to HolePlayMenu Hole startHole = course.getHoles().get(startHoleNum - 1); Round r = new Round(course, Session.getDateTime(), startHole); + // Undo puts golfer back to before round existed. + UndoManager.instance().capture(golfer, "Start round on " + course.getName() + " (hole " + startHoleNum + ")"); golfer.addRound(r); return r; } diff --git a/src/main/java/design/controller/userinput/menus/LeageMenu.java b/src/main/java/design/controller/userinput/menus/LeageMenu.java new file mode 100644 index 0000000..d9afa91 --- /dev/null +++ b/src/main/java/design/controller/userinput/menus/LeageMenu.java @@ -0,0 +1,30 @@ +package design.controller.userinput.menus; + +import design.controller.userinput.Menu; +import design.controller.userinput.MenuOption; +import design.model.League; + +import java.util.ArrayList; +import java.util.List; + +public class LeageMenu extends Menu { + private final League league; + + public LeageMenu(League league) { + this.league = league; + } + + @Override + public String getTitle() { + return "League Menu"; + } + + @Override + public List<MenuOption> getMenuOptions() { + List<MenuOption> options = new ArrayList<>(); + options.add(new MenuOption("statistics...", () -> {})); + options.add(new MenuOption("leaderboard...", () -> {})); + options.add(new MenuOption("log round...", () -> {})); + return options; + } +} diff --git a/src/main/java/design/controller/userinput/menus/MainMenu.java b/src/main/java/design/controller/userinput/menus/MainMenu.java index 9d5204f..0c42422 100644 --- a/src/main/java/design/controller/userinput/menus/MainMenu.java +++ b/src/main/java/design/controller/userinput/menus/MainMenu.java @@ -2,6 +2,8 @@ package design.controller.userinput.menus; import design.controller.userinput.Menu; import design.controller.userinput.MenuOption; +import design.controller.userinput.UndoActions; +import design.runtime.Session; import java.util.List; @@ -13,14 +15,33 @@ public class MainMenu extends Menu { @Override public List<MenuOption> getMenuOptions() { - return List.of( - new MenuOption("quit", () -> System.exit(0)), - new MenuOption("user settings...", () -> new UserSettings().present()), - new MenuOption("manage courses...", () -> new ManageCourses().present()), - new MenuOption("manage clubs...", () -> new ManageClubs().present()), - new MenuOption("statistics...", () -> new StatisticsMenu().present()), - new MenuOption("log round...", () -> new HolePlayMenu().present()), - new MenuOption("manage data...", () -> new ImportExportMenu().present()) - ); + boolean guest = Session.isGuest(); + if (guest) { + return List.of( + new MenuOption("quit", () -> System.exit(0)), + new MenuOption("guest settings...", () -> new UserSettings().present()), + new MenuOption("browse courses...", () -> new SearchMenu().present()) + + ); + } else { + return List.of( + new MenuOption("quit", () -> System.exit(0)), + new MenuOption("undo", () -> { + UndoActions.undoWithSave(); + this.present(); + }), + new MenuOption("redo", () -> { + UndoActions.redoWithSave(); + this.present(); + }), + new MenuOption("user settings...", () -> new UserSettings().present()), + new MenuOption("manage courses...", () -> new ManageCourses().present()), + new MenuOption("manage clubs...", () -> new ManageClubs().present()), + new MenuOption("statistics...", () -> new StatisticsMenu().present()), + new MenuOption("log round...", () -> new HolePlayMenu().present()), + new MenuOption("League play...", () -> new SelectLeague().present()), + new MenuOption("manage data...", () -> new ImportExportMenu().present()) + ); + } } } diff --git a/src/main/java/design/controller/userinput/menus/ManageClubs.java b/src/main/java/design/controller/userinput/menus/ManageClubs.java index 6b6811b..9c23433 100644 --- a/src/main/java/design/controller/userinput/menus/ManageClubs.java +++ b/src/main/java/design/controller/userinput/menus/ManageClubs.java @@ -6,6 +6,7 @@ import design.model.Club; import design.model.Golfer; import design.persistence.PersonalDatabase; import design.runtime.Session; +import design.model.undo.UndoManager; import java.io.IOException; import java.util.Arrays; @@ -36,7 +37,11 @@ public class ManageClubs extends Menu { opts.add(new MenuOption("remove club...", () -> { var selector = new SelectClub(); selector.present(); - golfer.removeClub(selector.getResult()); + Club toRemove = selector.getResult(); + + UndoManager.instance().capture(golfer, "Remove club " + toRemove); + + golfer.removeClub(toRemove); try { personalDB.updateGolfer(golfer); } catch (IOException ex) { @@ -46,6 +51,8 @@ public class ManageClubs extends Menu { })); opts.add(new MenuOption("add club...", () -> { + UndoManager.instance().capture(golfer, "Add club"); + Scanner sc = new Scanner(System.in); System.out.print("Manufacturer: "); diff --git a/src/main/java/design/controller/userinput/menus/ManageCourses.java b/src/main/java/design/controller/userinput/menus/ManageCourses.java index b592cd2..4f3efe5 100644 --- a/src/main/java/design/controller/userinput/menus/ManageCourses.java +++ b/src/main/java/design/controller/userinput/menus/ManageCourses.java @@ -6,6 +6,7 @@ import design.model.Course; import design.model.Golfer; import design.persistence.PersonalDatabase; import design.runtime.Session; +import design.model.undo.UndoManager; import java.io.IOException; import java.util.List; @@ -34,7 +35,11 @@ public class ManageCourses extends Menu { opts.add(new MenuOption("remove course...", () -> { var selector = new SelectCourse(); selector.present(); - golfer.removeCourse(selector.getResult()); + Course course = selector.getResult(); + + UndoManager.instance().capture(golfer, "Remove course " + course.getName()); + + golfer.removeCourse(course); try { personalDB.updateGolfer(golfer); } catch (IOException ex) { diff --git a/src/main/java/design/controller/userinput/menus/SelectLeague.java b/src/main/java/design/controller/userinput/menus/SelectLeague.java new file mode 100644 index 0000000..08f6c91 --- /dev/null +++ b/src/main/java/design/controller/userinput/menus/SelectLeague.java @@ -0,0 +1,83 @@ +package design.controller.userinput.menus; + +import design.controller.userinput.Menu; +import design.controller.userinput.MenuOption; +import design.model.Golfer; +import design.model.League; +import design.model.ScrambleLeague; +import design.model.StrokeLeague; +import design.persistence.LeagueDatabase; +import design.runtime.Session; + +import java.io.IOException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; + +public class SelectLeague extends Menu { + private final Golfer golfer = Session.getCurrentGolfer(); + + @Override + public String getTitle() { + return "Select League"; + } + + @Override + public List<MenuOption> getMenuOptions() { + List<MenuOption> options = new ArrayList<>(); + for (League l : LeagueDatabase.instance().getLeagues()) { + options.add(new MenuOption(l.getName(), () -> { + if (l instanceof ScrambleLeague sl && sl.locateTeam(golfer) == null) { + Scanner sc = new Scanner(System.in); + System.out.print("You are not a member of a team for this league. Would you like to create one (Y/n): "); + if (sc.next().equals("n")) { + new MainMenu().present(); + } else { + // create team + } + } else { + new LeageMenu(l).present(); + } + })); + } + options.add(new MenuOption("<create>", this::createLeagueWizard)); + return options; + } + + private void createLeagueWizard() { + try { + Scanner scanner = new Scanner(System.in); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + + System.out.print("Enter league name: "); + String name = scanner.nextLine(); + + System.out.print("Enter registration date (yyyy-MM-dd): "); + Date registrationDate = dateFormat.parse(scanner.nextLine()); + + System.out.print("Enter start date (yyyy-MM-dd): "); + Date startDate = dateFormat.parse(scanner.nextLine()); + + System.out.print("Enter end date (yyyy-MM-dd): "); + Date endDate = dateFormat.parse(scanner.nextLine()); + + Golfer owner = Session.getCurrentGolfer(); + + System.out.print("Enter format (stroke/scramble): "); + String scramble = scanner.nextLine(); + + League league; + switch (scramble) { + case "scramble" -> league = new ScrambleLeague(name, registrationDate, startDate, endDate, owner); + case "stroke" -> league = new StrokeLeague(name, registrationDate, startDate, endDate, owner); + default -> throw new RuntimeException(); + } + LeagueDatabase.instance().addLeague(league); + } catch (ParseException ex) { + System.out.println("Invalid format"); + } catch (IOException ex) { + System.out.println("Error writing to file"); + } + this.present(); + } +} diff --git a/src/main/java/design/controller/userinput/menus/SelectUser.java b/src/main/java/design/controller/userinput/menus/SelectUser.java index 4b7928c..6931a4b 100644 --- a/src/main/java/design/controller/userinput/menus/SelectUser.java +++ b/src/main/java/design/controller/userinput/menus/SelectUser.java @@ -6,6 +6,7 @@ import design.controller.userinput.MenuOption; import design.model.Golfer; import design.runtime.Session; import design.persistence.PersonalDatabase; +import design.model.undo.UndoManager; import java.io.IOException; import java.util.ArrayList; @@ -52,6 +53,12 @@ public class SelectUser extends Menu { this.present(); })); + opts.add(new MenuOption("<guest login>", () -> { + Session.setCurrentGolfer(null); + Session.setGuest(true); + doAfter.onAction(); + })); + return opts; } @@ -61,6 +68,7 @@ public class SelectUser extends Menu { if (g.checkPassword(password)) { // Sets user in Session too Session.setCurrentGolfer(g); + UndoManager.instance().purge(); System.out.printf("Loaded user: %s%n", g); doAfter.onAction(); } else { diff --git a/src/main/java/design/controller/userinput/menus/UserSettings.java b/src/main/java/design/controller/userinput/menus/UserSettings.java index 47b0a5b..1b2082d 100644 --- a/src/main/java/design/controller/userinput/menus/UserSettings.java +++ b/src/main/java/design/controller/userinput/menus/UserSettings.java @@ -12,6 +12,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Scanner; +import design.model.undo.UndoManager; + public class UserSettings extends Menu { private final Golfer golfer = Session.getCurrentGolfer(); @@ -25,6 +27,8 @@ public class UserSettings extends Menu { @Override public List<MenuOption> getMenuOptions() { + boolean guest = Session.isGuest(); + var opts = new ArrayList<MenuOption>(); opts.add(new MenuOption("return to main menu", () -> new MainMenu().present())); @@ -34,31 +38,37 @@ public class UserSettings extends Menu { new SelectUser(doAfter).present(); })); - opts.add(new MenuOption("set password...", () -> { - System.out.print("Enter password: "); - var password = scanner.nextLine(); - - golfer.setPassword(password); - try { - personalDatabase.updateGolfer(golfer); - } catch (IOException ex) { - throw new RuntimeException(ex); - } - this.present(); - })); + if (!guest) { + opts.add(new MenuOption("set password...", () -> { + UndoManager.instance().capture(golfer, "Change password for @" + golfer.getUsername()); - opts.add(new MenuOption("set full name...", () -> { - System.out.print("Enter full name: "); - var fullName = scanner.nextLine(); - - golfer.setFullName(fullName); - try { - personalDatabase.updateGolfer(golfer); - } catch (IOException ex) { - throw new RuntimeException(ex); - } - this.present(); - })); + System.out.print("Enter password: "); + var password = scanner.nextLine(); + + golfer.setPassword(password); + try { + personalDatabase.updateGolfer(golfer); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + this.present(); + })); + + opts.add(new MenuOption("set full name...", () -> { + UndoManager.instance().capture(golfer, "Change full name for @" + golfer.getUsername()); + + System.out.print("Enter full name: "); + var fullName = scanner.nextLine(); + + golfer.setFullName(fullName); + try { + personalDatabase.updateGolfer(golfer); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + this.present(); + })); + } return opts; } |
