Implement preferences overlay

This commit is contained in:
Florine W. Dekker 2020-08-12 19:06:16 +02:00
parent 1e840ae7c2
commit 9fb009c8f7
Signed by: FWDekker
GPG Key ID: B1B567AF58D6EE0F
4 changed files with 96 additions and 11 deletions

View File

@ -1,6 +1,6 @@
{
"name": "minesweeper",
"version": "0.81.0",
"version": "0.81.1",
"description": "Just Minesweeper!",
"author": "Felix W. Dekker",
"browser": "dist/bundle.js",

View File

@ -27,6 +27,19 @@
<section class="container" id="mainContainer">
<!-- Controls -->
<div class="row controls">
<div class="column">
<!-- Preferences -->
<form id="preferencesOpenForm">
<button><i class="fa fa-cogs"></i>&emsp;Preferences</button>
</form>
<!-- Statistics -->
<form id="statisticsOpenForm">
<button><i class="fa fa-tachometer"></i>&emsp;Statistics</button>
</form>
</div>
</div>
<div class="row controls">
<div class="column">
<!-- Difficulty -->
@ -49,11 +62,6 @@
<form id="seedOpenForm">
<button><i class="fa fa-tree"></i>&emsp;Enter seed</button>
</form>
<!-- Statistics -->
<form id="statisticsOpenForm">
<button><i class="fa fa-tachometer"></i>&emsp;Statistics</button>
</form>
</div>
</div>
<div class="row controls">
@ -134,6 +142,21 @@
</form>
</div>
</div>
<!-- Preferences overlay -->
<div class="overlayWrapper" id="preferencesOverlay">
<div class="overlay">
<form id="preferencesForm">
<label for="preferencesEnableMarks">Enable question marks</label>
<input type="checkbox" id="preferencesEnableMarks" />
<br /><br />
<button>Save</button>
</form>
<form id="preferencesCancelForm">
<button class="cancel">Cancel</button>
</form>
</div>
</div>
<!-- Statistics overlay -->
<div class="overlayWrapper" id="statisticsOverlay">
<div class="overlay">

View File

@ -34,6 +34,9 @@ export class Game {
private readonly heightInput: HTMLInputElement;
private readonly minesInput: HTMLInputElement;
private readonly solvableInput: HTMLInputElement;
private readonly preferencesOverlay: Overlay;
private readonly enableMarksInput: HTMLInputElement;
private readonly preferencesOpenForm: HTMLFormElement;
private readonly statisticsOverlay: Overlay;
private readonly statisticsDiv: HTMLDivElement;
private readonly statisticsResetForm: HTMLFormElement;
@ -52,9 +55,10 @@ export class Game {
/**
* Constructs and starts a new game of Minesweeper.
*
* @param preferences the preferences to play the game under; may be changed during gameplay
* @param withForkAwesome whether ForkAwesome can be used
*/
constructor(withForkAwesome: boolean = true) {
constructor(preferences: Preferences, withForkAwesome: boolean = true) {
this.canvas = $("#canvas");
this.field = null; // Placeholder until `initNewField`
@ -227,6 +231,25 @@ export class Game {
}
);
// Preferences
this.enableMarksInput = $("#preferencesEnableMarks");
this.preferencesOpenForm = $("#preferencesOpenForm");
this.preferencesOpenForm.addEventListener(
"submit",
event => {
event.preventDefault();
this.enableMarksInput.checked = preferences.marksEnabled;
this.preferencesOverlay.show();
}
);
this.preferencesOverlay = new Overlay(
$("#preferencesOverlay"),
$("#preferencesForm"),
$("#preferencesCancelForm"),
() => preferences.marksEnabled = this.enableMarksInput.checked
);
// Statistics
this.statisticsDiv = $("#statisticsDiv");
this.statisticsOpenForm = $("#statisticsOpenForm");
@ -298,7 +321,8 @@ export class Game {
if (square !== undefined) {
if (square.hasFlag) {
this.field.toggleFlag(coords);
this.field.toggleMark(coords);
if (preferences.marksEnabled)
this.field.toggleMark(coords);
} else if (square.hasMark) {
this.field.toggleMark(coords);
} else {
@ -415,3 +439,41 @@ export class Game {
}, 1000);
}
}
/**
* The player's preferences.
*/
export class Preferences {
private static readonly storageKey = "/tools/minesweeper//preferences";
/**
* Reads the object stored in local storage.
*
* @return the object stored in local storage, or an empty object if there is nothing in the local storage
* @private
*/
private read(): { [key: string]: string } {
return JSON.parse(localStorage.getItem(Preferences.storageKey) ?? "{}");
}
/**
* Writes the given object to local storage.
*
* @param statistics the object to write to local storage
* @private
*/
private write(statistics: { [key: string]: string }): void {
localStorage.setItem(Preferences.storageKey, JSON.stringify(statistics));
}
get marksEnabled(): boolean {
return (this.read()["marksEnabled"] ?? "true") === "true";
}
set marksEnabled(value: boolean) {
const preferences = this.read();
preferences["marksEnabled"] = "" + value;
this.write(preferences);
}
}

View File

@ -3,7 +3,7 @@ import "../css/main.css";
// @ts-ignore
import {$, doAfterLoad, footer, header, nav} from "@fwdekker/template";
import {waitForForkAwesome} from "./Common";
import {Game} from "./Game";
import {Game, Preferences} from "./Game";
doAfterLoad(() => {
@ -24,10 +24,10 @@ doAfterLoad(() => {
// Start game
waitForForkAwesome(
() => new Game(),
() => new Game(new Preferences()),
() => {
alert("External font could not be loaded. Using fallback font. Is a browser extension blocking fonts?");
new Game(false);
new Game(new Preferences(), false);
},
3000
);