feat(settings): persisted Music level; SettingsMenu applies via GameIO
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -67,8 +67,7 @@ public final class App {
|
|||||||
SaveService saves = new SaveService();
|
SaveService saves = new SaveService();
|
||||||
SettingsStore settingsStore = new SettingsStore();
|
SettingsStore settingsStore = new SettingsStore();
|
||||||
Settings settings = settingsStore.load();
|
Settings settings = settingsStore.load();
|
||||||
ConsoleIO consoleIo = io instanceof ConsoleIO c ? c : null;
|
SettingsMenu.apply(settings, io);
|
||||||
SettingsMenu.apply(settings, consoleIo);
|
|
||||||
|
|
||||||
boolean running = true;
|
boolean running = true;
|
||||||
while (running) {
|
while (running) {
|
||||||
@@ -84,7 +83,7 @@ public final class App {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case SETTINGS -> settings = SettingsMenu.show(io, settings, settingsStore, consoleIo);
|
case SETTINGS -> settings = SettingsMenu.show(io, settings, settingsStore);
|
||||||
case QUIT -> running = false;
|
case QUIT -> running = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,50 +2,47 @@ package thb.jeanluc.adventure.menu;
|
|||||||
|
|
||||||
import thb.jeanluc.adventure.io.ConsoleIO;
|
import thb.jeanluc.adventure.io.ConsoleIO;
|
||||||
import thb.jeanluc.adventure.io.GameIO;
|
import thb.jeanluc.adventure.io.GameIO;
|
||||||
|
import thb.jeanluc.adventure.io.MusicLevel;
|
||||||
import thb.jeanluc.adventure.save.Settings;
|
import thb.jeanluc.adventure.save.Settings;
|
||||||
import thb.jeanluc.adventure.save.SettingsStore;
|
import thb.jeanluc.adventure.save.SettingsStore;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/** Minimal settings screen: toggle colour and glyph mode; persists + applies. */
|
/** Settings screen: cycle colour, glyph, and music level; persists + applies. */
|
||||||
public final class SettingsMenu {
|
public final class SettingsMenu {
|
||||||
|
|
||||||
private SettingsMenu() {
|
private SettingsMenu() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Loops the settings screen until "Back", persisting + applying each change. */
|
||||||
* Loops the settings screen until the player picks "Back", persisting and
|
public static Settings show(GameIO io, Settings current, SettingsStore store) {
|
||||||
* applying each change. Returns the final settings.
|
|
||||||
*
|
|
||||||
* @param io active IO
|
|
||||||
* @param current starting settings
|
|
||||||
* @param store where to persist
|
|
||||||
* @param consoleIo the console IO to apply changes to live, or null if not console
|
|
||||||
*/
|
|
||||||
public static Settings show(GameIO io, Settings current, SettingsStore store, ConsoleIO consoleIo) {
|
|
||||||
Settings s = current;
|
Settings s = current;
|
||||||
while (true) {
|
while (true) {
|
||||||
int i = io.choose("SETTINGS", List.of(
|
int i = io.choose("SETTINGS", List.of(
|
||||||
"Colour: " + s.colorMode(),
|
"Colour: " + s.colorMode(),
|
||||||
"Glyphs: " + s.glyphMode(),
|
"Glyphs: " + s.glyphMode(),
|
||||||
|
"Music: " + s.musicLevel(),
|
||||||
"Back"));
|
"Back"));
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
s = new Settings(nextColor(s.colorMode()), s.glyphMode());
|
s = new Settings(nextColor(s.colorMode()), s.glyphMode(), s.musicLevel());
|
||||||
} else if (i == 1) {
|
} else if (i == 1) {
|
||||||
s = new Settings(s.colorMode(), nextGlyph(s.glyphMode()));
|
s = new Settings(s.colorMode(), nextGlyph(s.glyphMode()), s.musicLevel());
|
||||||
|
} else if (i == 2) {
|
||||||
|
s = new Settings(s.colorMode(), s.glyphMode(), s.musicLevel().next());
|
||||||
} else {
|
} else {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
store.save(s);
|
store.save(s);
|
||||||
apply(s, consoleIo);
|
apply(s, io);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Applies colour/glyph settings to the console IO (no-op if null). */
|
/** Applies settings to the IO: music level always; colour/glyph only on the console. */
|
||||||
public static void apply(Settings s, ConsoleIO consoleIo) {
|
public static void apply(Settings s, GameIO io) {
|
||||||
if (consoleIo != null) {
|
io.setMusicLevel(s.musicLevel());
|
||||||
consoleIo.setColorMode(s.colorMode());
|
if (io instanceof ConsoleIO c) {
|
||||||
consoleIo.setGlyphMode(s.glyphMode());
|
c.setColorMode(s.colorMode());
|
||||||
|
c.setGlyphMode(s.glyphMode());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,23 @@
|
|||||||
package thb.jeanluc.adventure.save;
|
package thb.jeanluc.adventure.save;
|
||||||
|
|
||||||
import thb.jeanluc.adventure.io.ConsoleIO;
|
import thb.jeanluc.adventure.io.ConsoleIO;
|
||||||
|
import thb.jeanluc.adventure.io.MusicLevel;
|
||||||
|
|
||||||
/** Persisted user preferences (minimal: colour + glyph fidelity). */
|
/** Persisted user preferences (colour + glyph fidelity + music level). */
|
||||||
public record Settings(ConsoleIO.ColorMode colorMode, ConsoleIO.GlyphMode glyphMode) {
|
public record Settings(ConsoleIO.ColorMode colorMode, ConsoleIO.GlyphMode glyphMode, MusicLevel musicLevel) {
|
||||||
|
|
||||||
|
public Settings {
|
||||||
|
if (musicLevel == null) {
|
||||||
|
musicLevel = MusicLevel.MEDIUM; // backward-compat: old saves lack this field
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Backward-compatible constructor for callers that don't set music. */
|
||||||
|
public Settings(ConsoleIO.ColorMode colorMode, ConsoleIO.GlyphMode glyphMode) {
|
||||||
|
this(colorMode, glyphMode, MusicLevel.MEDIUM);
|
||||||
|
}
|
||||||
|
|
||||||
public static Settings defaults() {
|
public static Settings defaults() {
|
||||||
return new Settings(ConsoleIO.ColorMode.AUTO, ConsoleIO.GlyphMode.UNICODE);
|
return new Settings(ConsoleIO.ColorMode.AUTO, ConsoleIO.GlyphMode.UNICODE, MusicLevel.MEDIUM);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import thb.jeanluc.adventure.save.SaveSlotInfo;
|
|||||||
import thb.jeanluc.adventure.save.Settings;
|
import thb.jeanluc.adventure.save.Settings;
|
||||||
import thb.jeanluc.adventure.save.SettingsStore;
|
import thb.jeanluc.adventure.save.SettingsStore;
|
||||||
import thb.jeanluc.adventure.io.ConsoleIO;
|
import thb.jeanluc.adventure.io.ConsoleIO;
|
||||||
|
import thb.jeanluc.adventure.io.MusicLevel;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
|
||||||
@@ -64,11 +65,18 @@ class MenuTest {
|
|||||||
@Test
|
@Test
|
||||||
void settingsMenuTogglesGlyphAndPersists(@TempDir Path dir) {
|
void settingsMenuTogglesGlyphAndPersists(@TempDir Path dir) {
|
||||||
SettingsStore store = new SettingsStore(dir.resolve("settings.json"));
|
SettingsStore store = new SettingsStore(dir.resolve("settings.json"));
|
||||||
// choose "Glyph mode" (assume option 2) → its toggle, then "Back" (last)
|
TestIO io = new TestIO().enqueue("2").enqueue("4"); // toggle Glyphs, then Back
|
||||||
TestIO io = new TestIO().enqueue("2").enqueue("3");
|
Settings result = SettingsMenu.show(io, Settings.defaults(), store);
|
||||||
Settings result = SettingsMenu.show(io, Settings.defaults(), store, new ConsoleIO());
|
|
||||||
// UNICODE default toggles to ASCII; persisted
|
|
||||||
assertThat(result.glyphMode()).isEqualTo(ConsoleIO.GlyphMode.ASCII);
|
assertThat(result.glyphMode()).isEqualTo(ConsoleIO.GlyphMode.ASCII);
|
||||||
assertThat(store.load().glyphMode()).isEqualTo(ConsoleIO.GlyphMode.ASCII);
|
assertThat(store.load().glyphMode()).isEqualTo(ConsoleIO.GlyphMode.ASCII);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void settingsMenuCyclesMusicLevelAndPersists(@TempDir Path dir) {
|
||||||
|
SettingsStore store = new SettingsStore(dir.resolve("settings.json"));
|
||||||
|
TestIO io = new TestIO().enqueue("3").enqueue("4"); // cycle Music once, then Back
|
||||||
|
Settings result = SettingsMenu.show(io, Settings.defaults(), store);
|
||||||
|
assertThat(result.musicLevel()).isEqualTo(MusicLevel.MEDIUM.next()); // HIGH
|
||||||
|
assertThat(store.load().musicLevel()).isEqualTo(MusicLevel.MEDIUM.next());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package thb.jeanluc.adventure.save;
|
|||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.io.TempDir;
|
import org.junit.jupiter.api.io.TempDir;
|
||||||
import thb.jeanluc.adventure.io.ConsoleIO;
|
import thb.jeanluc.adventure.io.ConsoleIO;
|
||||||
|
import thb.jeanluc.adventure.io.MusicLevel;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
@@ -34,4 +35,18 @@ class SettingsStoreTest {
|
|||||||
Settings loaded = new SettingsStore(file).load();
|
Settings loaded = new SettingsStore(file).load();
|
||||||
assertThat(loaded).isEqualTo(Settings.defaults());
|
assertThat(loaded).isEqualTo(Settings.defaults());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void musicLevelRoundTrips(@TempDir Path dir) {
|
||||||
|
SettingsStore store = new SettingsStore(dir.resolve("settings.json"));
|
||||||
|
store.save(new Settings(ConsoleIO.ColorMode.AUTO, ConsoleIO.GlyphMode.UNICODE, MusicLevel.HIGH));
|
||||||
|
assertThat(store.load().musicLevel()).isEqualTo(MusicLevel.HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void oldSettingsWithoutMusicDefaultToMedium(@TempDir Path dir) throws Exception {
|
||||||
|
Path file = dir.resolve("settings.json");
|
||||||
|
Files.writeString(file, "{\"colorMode\":\"ON\",\"glyphMode\":\"ASCII\"}");
|
||||||
|
assertThat(new SettingsStore(file).load().musicLevel()).isEqualTo(MusicLevel.MEDIUM);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user