Refactor CapitalsQuiz and FlagQuiz to utilize shared logic for achievements and settings management, enhancing code consistency and maintainability.

This commit is contained in:
sHa
2025-08-15 00:37:47 +03:00
parent eb139840ba
commit 63d6c99ff1
2 changed files with 72 additions and 212 deletions

View File

@@ -1,4 +1,9 @@
<script>
import { updateAchievementCount as sharedUpdateAchievementCount } from '../quizLogic/quizAchievements.js';
import { saveSettings as sharedSaveSettings, loadSettings as sharedLoadSettings } from '../quizLogic/quizSettings.js';
import { loadGlobalStats as sharedLoadGlobalStats, updateGlobalStats as sharedUpdateGlobalStats } from '../quizLogic/quizGlobalStats.js';
import { saveSessionState as sharedSaveSessionState, loadSessionState as sharedLoadSessionState, clearSessionState as sharedClearSessionState } from '../quizLogic/quizSession.js';
import { playCorrectSound as sharedPlayCorrectSound, playWrongSound as sharedPlayWrongSound } from '../quizLogic/quizSound.js';
import { quizInfo } from '../quizInfo/CapitalsQuizInfo.js';
import { onMount } from "svelte";
import Header from "../components/Header.svelte";
@@ -87,21 +92,18 @@
// Update achievement count when achievements component is available
$: if (achievementsComponent) {
updateAchievementCount();
achievementCount = sharedUpdateAchievementCount(achievementsComponent);
}
// Save settings when they change (after initial load)
$: if (settingsLoaded && typeof reduceCorrectAnswers !== "undefined") {
localStorage.setItem(
"capitalsQuizSettings",
JSON.stringify({
sharedSaveSettings("capitalsQuizSettings", {
autoAdvance,
focusWrongAnswers,
reduceCorrectAnswers,
soundEnabled,
sessionLength,
}),
);
});
}
// Load game stats from localStorage
@@ -162,31 +164,23 @@
}
// Load settings
const savedSettings = localStorage.getItem("capitalsQuizSettings");
if (savedSettings) {
try {
const settings = JSON.parse(savedSettings);
autoAdvance =
settings.autoAdvance !== undefined ? settings.autoAdvance : true;
focusWrongAnswers =
settings.focusWrongAnswers !== undefined
? settings.focusWrongAnswers
: false;
reduceCorrectAnswers =
settings.reduceCorrectAnswers !== undefined
? settings.reduceCorrectAnswers
: false;
soundEnabled =
settings.soundEnabled !== undefined ? settings.soundEnabled : true;
sessionLength =
settings.sessionLength !== undefined ? settings.sessionLength : 10;
} catch (e) {
console.error("Error loading settings:", e);
}
const loadedSettings = sharedLoadSettings("capitalsQuizSettings", {
autoAdvance,
focusWrongAnswers,
reduceCorrectAnswers,
soundEnabled,
sessionLength,
});
if (loadedSettings) {
autoAdvance = loadedSettings.autoAdvance;
focusWrongAnswers = loadedSettings.focusWrongAnswers;
reduceCorrectAnswers = loadedSettings.reduceCorrectAnswers;
soundEnabled = loadedSettings.soundEnabled;
sessionLength = loadedSettings.sessionLength;
}
// Load global stats and update them
loadGlobalStats();
sharedLoadGlobalStats("globalQuizStats");
}
await loadFlags();
@@ -255,33 +249,30 @@
sessionStartTime,
questionKey,
};
localStorage.setItem("capitalsQuizSessionState", JSON.stringify(sessionState));
sharedSaveSessionState("capitalsQuizSessionState", sessionState);
}
function loadSessionState() {
const savedState = localStorage.getItem("capitalsQuizSessionState");
if (savedState) {
try {
const state = JSON.parse(savedState);
if (state.sessionInProgress) {
const loadedSession = sharedLoadSessionState("capitalsQuizSessionState", null);
if (loadedSession) {
// Restore session
sessionInProgress = state.sessionInProgress;
currentSessionQuestions = state.currentSessionQuestions || 0;
sessionStats = state.sessionStats || {
sessionInProgress = loadedSession.sessionInProgress;
currentSessionQuestions = loadedSession.currentSessionQuestions || 0;
sessionStats = loadedSession.sessionStats || {
correct: 0,
wrong: 0,
skipped: 0,
total: 0,
sessionLength,
};
score = state.score || { correct: 0, total: 0, skipped: 0 };
currentQuestion = state.currentQuestion;
selectedAnswer = state.selectedAnswer;
showResult = state.showResult || false;
gameState = state.gameState || "question";
score = loadedSession.score || { correct: 0, total: 0, skipped: 0 };
currentQuestion = loadedSession.currentQuestion;
selectedAnswer = loadedSession.selectedAnswer;
showResult = loadedSession.showResult || false;
gameState = loadedSession.gameState || "question";
quizSubpage = "quiz";
sessionStartTime = state.sessionStartTime;
questionKey = state.questionKey || 0;
sessionStartTime = loadedSession.sessionStartTime;
questionKey = loadedSession.questionKey || 0;
// Mark that session was restored from reload
sessionRestoredFromReload = true;
@@ -290,16 +281,6 @@
if (!currentQuestion) {
generateQuestion();
}
} else {
// No active session, show welcome page
quizSubpage = "welcome";
gameState = "welcome";
}
} catch (e) {
console.error("Error loading session state:", e);
quizSubpage = "welcome";
gameState = "welcome";
}
} else {
// No saved state, show welcome page
quizSubpage = "welcome";
@@ -308,7 +289,7 @@
}
function clearSessionState() {
localStorage.removeItem("capitalsQuizSessionState");
sharedClearSessionState("capitalsQuizSessionState");
}
function generateQuestion() {
@@ -676,10 +657,6 @@
localStorage.setItem("capitalsQuizStats", JSON.stringify(gameStats));
}
function saveSettings() {
const settings = { autoAdvance };
localStorage.setItem("capitalsQuizSettings", JSON.stringify(settings));
}
function toggleSettings() {
showSettings = !showSettings;
@@ -736,7 +713,7 @@
// Reset achievements if component is available
if (achievementsComponent) {
achievementsComponent.resetAllAchievements();
achievementsComponent.resetConsecutiveSkips();
}
showResetConfirmation = false;
@@ -799,134 +776,27 @@
return `/images/flags/${flag.path}`;
}
function updateAchievementCount() {
if (achievementsComponent) {
achievementCount = achievementsComponent.getAchievementCount();
}
}
function handleAchievementsUnlocked() {
updateAchievementCount();
achievementCount = sharedUpdateAchievementCount(achievementsComponent);
}
// Global statistics functions
function loadGlobalStats() {
const savedGlobalStats = localStorage.getItem("globalQuizStats");
if (savedGlobalStats) {
try {
const globalStats = JSON.parse(savedGlobalStats);
console.log("Loaded global stats:", globalStats);
} catch (e) {
console.error("Error loading global stats:", e);
}
}
sharedLoadGlobalStats("globalQuizStats");
}
function updateGlobalStats(isCorrect, isSkipped = false) {
let globalStats = {};
// Load existing global stats
const savedGlobalStats = localStorage.getItem("globalQuizStats");
if (savedGlobalStats) {
try {
globalStats = JSON.parse(savedGlobalStats);
} catch (e) {
console.error("Error parsing global stats:", e);
}
}
// Initialize stats structure if it doesn't exist
if (!globalStats.capitalsQuiz) {
globalStats.capitalsQuiz = { correct: 0, wrong: 0, total: 0, skipped: 0 };
}
if (!globalStats.overall) {
globalStats.overall = { correct: 0, wrong: 0, total: 0, skipped: 0 };
}
// Update capitals quiz stats
globalStats.capitalsQuiz.total++;
globalStats.overall.total++;
if (isSkipped) {
globalStats.capitalsQuiz.skipped++;
globalStats.overall.skipped++;
} else if (isCorrect) {
globalStats.capitalsQuiz.correct++;
globalStats.overall.correct++;
} else {
globalStats.capitalsQuiz.wrong++;
globalStats.overall.wrong++;
}
// Save updated global stats
localStorage.setItem("globalQuizStats", JSON.stringify(globalStats));
console.log("Updated global stats:", globalStats);
sharedUpdateGlobalStats("globalQuizStats", "capitalsQuiz", isCorrect, isSkipped);
}
// Sound functions
function playCorrectSound() {
if (!soundEnabled) return;
try {
const audioContext = new (window.AudioContext ||
window.webkitAudioContext)();
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
// Pleasant ascending tone for correct answer
oscillator.frequency.setValueAtTime(523.25, audioContext.currentTime); // C5
oscillator.frequency.setValueAtTime(
659.25,
audioContext.currentTime + 0.1,
); // E5
oscillator.frequency.setValueAtTime(
783.99,
audioContext.currentTime + 0.2,
); // G5
gainNode.gain.setValueAtTime(0.3, audioContext.currentTime);
gainNode.gain.exponentialRampToValueAtTime(
0.001,
audioContext.currentTime + 0.4,
);
oscillator.start(audioContext.currentTime);
oscillator.stop(audioContext.currentTime + 0.4);
} catch (e) {
console.log("Audio not supported:", e);
}
sharedPlayCorrectSound(soundEnabled);
}
function playWrongSound() {
if (!soundEnabled) return;
try {
const audioContext = new (window.AudioContext ||
window.webkitAudioContext)();
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
// Descending tone for wrong answer
oscillator.frequency.setValueAtTime(400, audioContext.currentTime); // Lower frequency
oscillator.frequency.setValueAtTime(300, audioContext.currentTime + 0.15);
gainNode.gain.setValueAtTime(0.3, audioContext.currentTime);
gainNode.gain.exponentialRampToValueAtTime(
0.001,
audioContext.currentTime + 0.3,
);
oscillator.start(audioContext.currentTime);
oscillator.stop(audioContext.currentTime + 0.3);
} catch (e) {
console.log("Audio not supported:", e);
}
sharedPlayWrongSound(soundEnabled);
}
</script>

View File

@@ -1,4 +1,6 @@
<script>
import { updateAchievementCount as sharedUpdateAchievementCount } from '../quizLogic/quizAchievements.js';
import { saveSettings as sharedSaveSettings } from '../quizLogic/quizSettings.js';
import { quizInfo } from '../quizInfo/FlagQuizInfo.js';
import { onMount } from "svelte";
import Header from "../components/Header.svelte";
@@ -87,21 +89,18 @@ import { quizInfo } from '../quizInfo/FlagQuizInfo.js';
// Update achievement count when achievements component is available
$: if (achievementsComponent) {
updateAchievementCount();
achievementCount = sharedUpdateAchievementCount(achievementsComponent);
}
// Save settings when they change (after initial load)
$: if (settingsLoaded && typeof reduceCorrectAnswers !== "undefined") {
localStorage.setItem(
"flagQuizSettings",
JSON.stringify({
sharedSaveSettings("flagQuizSettings", {
autoAdvance,
focusWrongAnswers,
reduceCorrectAnswers,
soundEnabled,
sessionLength,
}),
);
});
}
// Load game stats from localStorage
@@ -670,10 +669,6 @@ import { quizInfo } from '../quizInfo/FlagQuizInfo.js';
localStorage.setItem("flagQuizStats", JSON.stringify(gameStats));
}
function saveSettings() {
const settings = { autoAdvance };
localStorage.setItem("flagQuizSettings", JSON.stringify(settings));
}
function toggleSettings() {
showSettings = !showSettings;
@@ -730,7 +725,7 @@ import { quizInfo } from '../quizInfo/FlagQuizInfo.js';
// Reset achievements if component is available
if (achievementsComponent) {
achievementsComponent.resetAllAchievements();
achievementsComponent.resetConsecutiveSkips();
}
showResetConfirmation = false;
@@ -789,14 +784,9 @@ import { quizInfo } from '../quizInfo/FlagQuizInfo.js';
return `/images/flags/${flag.path}`;
}
function updateAchievementCount() {
if (achievementsComponent) {
achievementCount = achievementsComponent.getAchievementCount();
}
}
function handleAchievementsUnlocked() {
updateAchievementCount();
achievementCount = sharedUpdateAchievementCount(achievementsComponent);
}
// Global statistics functions