Spaces:
Running
Running
Update index.html
Browse files- index.html +81 -27
index.html
CHANGED
|
@@ -121,11 +121,11 @@
|
|
| 121 |
<audio id="story-audio" controls style="display:none;"></audio>
|
| 122 |
<audio id="click-sound" src="audio/click_2.mp3" preload="auto"></audio>
|
| 123 |
<audio id="success-sound" src="audio/Correct and Incorrect sound effect - right or wrong(M4A_128K)(2).mp3" preload="auto"></audio>
|
| 124 |
-
<audio id="error-sound" src="audio/Correct and Incorrect sound effect - right or wrong(M4A_128K)(3).
|
| 125 |
<audio id="background-music" src="audio/Funny Kids _ Children_s Music (Instrumental Music For Kids)(M4A_128K).m4a" preload="auto" loop></audio>
|
| 126 |
<script>
|
| 127 |
// --- 1. تعريف الأيقونات كـ SVG نصي ---
|
| 128 |
-
|
| 129 |
const ICONS = {
|
| 130 |
Home: (cls) => `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="${cls}"><path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>`,
|
| 131 |
Share2: (cls) => `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="${cls}"><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><line x1="8.59" x2="15.42" y1="13.51" y2="17.49"/><line x1="15.41" x2="8.59" y1="6.51" y2="10.49"/></svg>`,
|
|
@@ -262,63 +262,105 @@
|
|
| 262 |
isAppMuted: false,
|
| 263 |
isRecording: false,
|
| 264 |
isUsernameSubmitted: false,
|
| 265 |
-
isBackgroundMusicPlaying: false,
|
| 266 |
};
|
| 267 |
|
| 268 |
-
// --- 4. وظائف التحكم الصوتي (
|
| 269 |
|
| 270 |
/** يشغل صوت النقر على زر */
|
| 271 |
const playClickSound = () => {
|
| 272 |
const audio = document.getElementById('click-sound');
|
| 273 |
-
if (audio) {
|
| 274 |
audio.currentTime = 0;
|
| 275 |
audio.play().catch(e => console.error("Error playing click sound:", e));
|
| 276 |
}
|
| 277 |
};
|
| 278 |
|
| 279 |
-
/** يشغل
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 280 |
const toggleBackgroundMusic = (shouldPlay) => {
|
| 281 |
const music = document.getElementById('background-music');
|
| 282 |
if (!music) return;
|
| 283 |
|
|
|
|
| 284 |
if (shouldPlay === undefined) {
|
| 285 |
-
// تبديل الحالة إذا لم يتم تحديد القيمة
|
| 286 |
shouldPlay = !appState.isBackgroundMusicPlaying;
|
| 287 |
}
|
| 288 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 289 |
if (shouldPlay) {
|
| 290 |
-
|
| 291 |
-
music.volume = 0.3; // خفض الصوت ليكون خلفية
|
| 292 |
music.play().then(() => {
|
| 293 |
-
|
|
|
|
| 294 |
}).catch(e => {
|
| 295 |
console.warn("Background music autoplay failed:", e);
|
| 296 |
-
|
| 297 |
-
|
| 298 |
});
|
| 299 |
} else {
|
| 300 |
music.pause();
|
| 301 |
-
|
|
|
|
| 302 |
}
|
| 303 |
};
|
| 304 |
|
| 305 |
-
// دالة تحديث الحالة وإعادة رسم التطبيق
|
| 306 |
window.setState = (newState) => {
|
| 307 |
|
| 308 |
-
// 🚨 تشغيل صوت النقر لكل تغيير حالة
|
| 309 |
if (newState.isMenuOpen === undefined && newState.isRecording === undefined && newState.currentScreen !== 'welcome') {
|
| 310 |
playClickSound();
|
| 311 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 312 |
|
| 313 |
-
|
| 314 |
-
|
| 315 |
-
|
| 316 |
-
|
| 317 |
-
// إذا كان الانتقال إلى شاشة التعلم، شغل الموسيقى
|
| 318 |
-
const isLearningScreen = CATEGORIES.some(c => c.id === newState.currentScreen);
|
| 319 |
if (isLearningScreen) {
|
| 320 |
-
toggleBackgroundMusic(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 321 |
}
|
|
|
|
| 322 |
|
| 323 |
if (newState.currentScreen && newState.currentScreen !== appState.selectedCategory) {
|
| 324 |
appState.currentIndex = 0;
|
|
@@ -342,13 +384,20 @@
|
|
| 342 |
window.startRecording = () => {
|
| 343 |
setState({ isRecording: true, currentScreen: appState.currentScreen });
|
| 344 |
console.log("Recording Started...");
|
| 345 |
-
// في التطبيق الحقيقي: تشغيل صوت البداية
|
| 346 |
};
|
| 347 |
|
| 348 |
window.stopRecording = () => {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 349 |
setState({ isRecording: false, currentScreen: appState.currentScreen });
|
| 350 |
console.log("Recording Stopped.");
|
| 351 |
-
// في التطبيق الحقيقي: تشغيل صوت الإيقاف أو النجاح/الخطأ
|
| 352 |
};
|
| 353 |
|
| 354 |
// 🚨 دالة جديدة لإرسال اسم المستخدم
|
|
@@ -380,7 +429,7 @@
|
|
| 380 |
|
| 381 |
|
| 382 |
// --- 5. مكونات الواجهة المشتركة (رأس الصفحة وتذييلها) ---
|
| 383 |
-
|
| 384 |
const renderHeader = () => {
|
| 385 |
const headerElement = document.getElementById('app-header');
|
| 386 |
const categoryMeta = CATEGORIES.find(c => c.id === appState.selectedCategory);
|
|
@@ -711,7 +760,7 @@
|
|
| 711 |
`;
|
| 712 |
};
|
| 713 |
|
| 714 |
-
// --- 9. شاشة الإعدادات (Settings Screen)
|
| 715 |
const renderSettingsScreen = () => {
|
| 716 |
const content = document.getElementById('app-content');
|
| 717 |
|
|
@@ -764,6 +813,8 @@
|
|
| 764 |
`;
|
| 765 |
};
|
| 766 |
|
|
|
|
|
|
|
| 767 |
const renderInfoScreen = () => {
|
| 768 |
const content = document.getElementById('app-content');
|
| 769 |
|
|
@@ -853,7 +904,6 @@
|
|
| 853 |
};
|
| 854 |
|
| 855 |
|
| 856 |
-
// --- 10. القائمة الجانبية (Menu) ---
|
| 857 |
const renderMenu = () => {
|
| 858 |
if (!appState.isMenuOpen) return '';
|
| 859 |
|
|
@@ -944,6 +994,8 @@
|
|
| 944 |
} else if (screen === 'appDefinition') {
|
| 945 |
renderAppDefinitionScreen();
|
| 946 |
} else if (CATEGORIES.some(c => c.id === screen)) {
|
|
|
|
|
|
|
| 947 |
renderLearningScreen();
|
| 948 |
} else {
|
| 949 |
content.innerHTML = `
|
|
@@ -973,6 +1025,8 @@
|
|
| 973 |
|
| 974 |
// تهيئة التطبيق عند تحميل النافذة
|
| 975 |
window.onload = () => {
|
|
|
|
|
|
|
| 976 |
renderApp();
|
| 977 |
};
|
| 978 |
|
|
|
|
| 121 |
<audio id="story-audio" controls style="display:none;"></audio>
|
| 122 |
<audio id="click-sound" src="audio/click_2.mp3" preload="auto"></audio>
|
| 123 |
<audio id="success-sound" src="audio/Correct and Incorrect sound effect - right or wrong(M4A_128K)(2).mp3" preload="auto"></audio>
|
| 124 |
+
<audio id="error-sound" src="audio/Correct and Incorrect sound effect - right or wrong(M4A_128K)(3).mp3" preload="auto"></audio>
|
| 125 |
<audio id="background-music" src="audio/Funny Kids _ Children_s Music (Instrumental Music For Kids)(M4A_128K).m4a" preload="auto" loop></audio>
|
| 126 |
<script>
|
| 127 |
// --- 1. تعريف الأيقونات كـ SVG نصي ---
|
| 128 |
+
|
| 129 |
const ICONS = {
|
| 130 |
Home: (cls) => `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="${cls}"><path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>`,
|
| 131 |
Share2: (cls) => `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="${cls}"><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><line x1="8.59" x2="15.42" y1="13.51" y2="17.49"/><line x1="15.41" x2="8.59" y1="6.51" y2="10.49"/></svg>`,
|
|
|
|
| 262 |
isAppMuted: false,
|
| 263 |
isRecording: false,
|
| 264 |
isUsernameSubmitted: false,
|
| 265 |
+
isBackgroundMusicPlaying: false,
|
| 266 |
};
|
| 267 |
|
| 268 |
+
// --- 4. وظائف التحكم الصوتي (UPDATED) ---
|
| 269 |
|
| 270 |
/** يشغل صوت النقر على زر */
|
| 271 |
const playClickSound = () => {
|
| 272 |
const audio = document.getElementById('click-sound');
|
| 273 |
+
if (audio && !appState.isAppMuted) {
|
| 274 |
audio.currentTime = 0;
|
| 275 |
audio.play().catch(e => console.error("Error playing click sound:", e));
|
| 276 |
}
|
| 277 |
};
|
| 278 |
|
| 279 |
+
/** 🚨 NEW: يشغل صوت النجاح */
|
| 280 |
+
const playSuccessSound = () => {
|
| 281 |
+
const audio = document.getElementById('success-sound');
|
| 282 |
+
if (audio && !appState.isAppMuted) {
|
| 283 |
+
audio.currentTime = 0;
|
| 284 |
+
audio.play().catch(e => console.error("Error playing success sound:", e));
|
| 285 |
+
}
|
| 286 |
+
};
|
| 287 |
+
|
| 288 |
+
/** 🚨 NEW: يشغل صوت الخطأ */
|
| 289 |
+
const playErrorSound = () => {
|
| 290 |
+
const audio = document.getElementById('error-sound');
|
| 291 |
+
if (audio && !appState.isAppMuted) {
|
| 292 |
+
audio.currentTime = 0;
|
| 293 |
+
audio.play().catch(e => console.error("Error playing error sound:", e));
|
| 294 |
+
}
|
| 295 |
+
};
|
| 296 |
+
|
| 297 |
+
/** يشغل أو يوقف موسيقى الخلفية (مع الاحتفاظ بحالة الإعدادات) */
|
| 298 |
const toggleBackgroundMusic = (shouldPlay) => {
|
| 299 |
const music = document.getElementById('background-music');
|
| 300 |
if (!music) return;
|
| 301 |
|
| 302 |
+
// القيمة الافتراضية للتشغيل/الإيقاف تعتمد على ما تم تمريره، أو تبديل الحالة الحالية
|
| 303 |
if (shouldPlay === undefined) {
|
|
|
|
| 304 |
shouldPlay = !appState.isBackgroundMusicPlaying;
|
| 305 |
}
|
| 306 |
|
| 307 |
+
// إذا كان المطلوب التشغيل لكن المستخدم قام بكتم التطبيق يدوياً، لا تفعل شيئاً
|
| 308 |
+
if (shouldPlay && appState.isAppMuted) {
|
| 309 |
+
// تحديث الحالة لتعكس أن الموسيقى متوقفة بسبب الكتم العام
|
| 310 |
+
appState.isBackgroundMusicPlaying = false;
|
| 311 |
+
music.pause();
|
| 312 |
+
return;
|
| 313 |
+
}
|
| 314 |
+
|
| 315 |
if (shouldPlay) {
|
| 316 |
+
music.volume = 0.3;
|
|
|
|
| 317 |
music.play().then(() => {
|
| 318 |
+
appState.isBackgroundMusicPlaying = true;
|
| 319 |
+
renderApp();
|
| 320 |
}).catch(e => {
|
| 321 |
console.warn("Background music autoplay failed:", e);
|
| 322 |
+
appState.isBackgroundMusicPlaying = true;
|
| 323 |
+
renderApp();
|
| 324 |
});
|
| 325 |
} else {
|
| 326 |
music.pause();
|
| 327 |
+
appState.isBackgroundMusicPlaying = false;
|
| 328 |
+
renderApp();
|
| 329 |
}
|
| 330 |
};
|
| 331 |
|
| 332 |
+
// دالة تحديث الحالة وإعادة رسم التطبيق (UPDATED)
|
| 333 |
window.setState = (newState) => {
|
| 334 |
|
| 335 |
+
// 🚨 تشغيل صوت النقر لكل تغيير حالة
|
| 336 |
if (newState.isMenuOpen === undefined && newState.isRecording === undefined && newState.currentScreen !== 'welcome') {
|
| 337 |
playClickSound();
|
| 338 |
}
|
| 339 |
+
|
| 340 |
+
const prevScreen = appState.currentScreen;
|
| 341 |
+
const nextScreen = newState.currentScreen || prevScreen;
|
| 342 |
+
|
| 343 |
+
// تحديد ما إذا كانت الشاشة الجديدة هي شاشة تعلم (ضمن الفئات)
|
| 344 |
+
const isLearningScreen = CATEGORIES.some(c => c.id === nextScreen);
|
| 345 |
+
// تحديد ما إذا كانت الشاشة الجديدة هي شاشة تنقل رئيسية
|
| 346 |
+
const isMainScreen = ['home', 'settings', 'info', 'profile', 'appDefinition'].includes(nextScreen);
|
| 347 |
|
| 348 |
+
|
| 349 |
+
// 🚨 منطق التحكم في موسيقى الخلفية
|
| 350 |
+
|
| 351 |
+
// 1. إذا كان الانتقال إلى شاشة تعلم، أوقف الموسيقى
|
|
|
|
|
|
|
| 352 |
if (isLearningScreen) {
|
| 353 |
+
toggleBackgroundMusic(false);
|
| 354 |
+
}
|
| 355 |
+
|
| 356 |
+
// 2. إذا كان الانتقال من شاشة تعلم إلى شاشة رئيسية، أو من الترحيب إلى الرئيسية، شغل الموسيقى
|
| 357 |
+
if ((isMainScreen) && (prevScreen === 'welcome' || CATEGORIES.some(c => c.id === prevScreen))) {
|
| 358 |
+
// تأكد من أن الموسيقى لم يتم كتمها يدويا عبر الإعدادات
|
| 359 |
+
if (!appState.isAppMuted) {
|
| 360 |
+
toggleBackgroundMusic(true);
|
| 361 |
+
}
|
| 362 |
}
|
| 363 |
+
|
| 364 |
|
| 365 |
if (newState.currentScreen && newState.currentScreen !== appState.selectedCategory) {
|
| 366 |
appState.currentIndex = 0;
|
|
|
|
| 384 |
window.startRecording = () => {
|
| 385 |
setState({ isRecording: true, currentScreen: appState.currentScreen });
|
| 386 |
console.log("Recording Started...");
|
|
|
|
| 387 |
};
|
| 388 |
|
| 389 |
window.stopRecording = () => {
|
| 390 |
+
// 🚨 NEW: إضافة منطق محاكاة النتيجة
|
| 391 |
+
if (Math.random() > 0.5) {
|
| 392 |
+
playSuccessSound();
|
| 393 |
+
console.log("Playback Success Sound");
|
| 394 |
+
} else {
|
| 395 |
+
playErrorSound();
|
| 396 |
+
console.log("Playback Error Sound");
|
| 397 |
+
}
|
| 398 |
+
|
| 399 |
setState({ isRecording: false, currentScreen: appState.currentScreen });
|
| 400 |
console.log("Recording Stopped.");
|
|
|
|
| 401 |
};
|
| 402 |
|
| 403 |
// 🚨 دالة جديدة لإرسال اسم المستخدم
|
|
|
|
| 429 |
|
| 430 |
|
| 431 |
// --- 5. مكونات الواجهة المشتركة (رأس الصفحة وتذييلها) ---
|
| 432 |
+
|
| 433 |
const renderHeader = () => {
|
| 434 |
const headerElement = document.getElementById('app-header');
|
| 435 |
const categoryMeta = CATEGORIES.find(c => c.id === appState.selectedCategory);
|
|
|
|
| 760 |
`;
|
| 761 |
};
|
| 762 |
|
| 763 |
+
// --- 9. شاشة الإعدادات (Settings Screen) ---
|
| 764 |
const renderSettingsScreen = () => {
|
| 765 |
const content = document.getElementById('app-content');
|
| 766 |
|
|
|
|
| 813 |
`;
|
| 814 |
};
|
| 815 |
|
| 816 |
+
// --- 10. شاشة حول التطبيق والقائمة الجانبية (The rest of the rendering functions) ---
|
| 817 |
+
|
| 818 |
const renderInfoScreen = () => {
|
| 819 |
const content = document.getElementById('app-content');
|
| 820 |
|
|
|
|
| 904 |
};
|
| 905 |
|
| 906 |
|
|
|
|
| 907 |
const renderMenu = () => {
|
| 908 |
if (!appState.isMenuOpen) return '';
|
| 909 |
|
|
|
|
| 994 |
} else if (screen === 'appDefinition') {
|
| 995 |
renderAppDefinitionScreen();
|
| 996 |
} else if (CATEGORIES.some(c => c.id === screen)) {
|
| 997 |
+
content.style.paddingTop = shouldShowNav ? '4rem' : '0';
|
| 998 |
+
content.style.paddingBottom = shouldShowNav ? '5rem' : '0';
|
| 999 |
renderLearningScreen();
|
| 1000 |
} else {
|
| 1001 |
content.innerHTML = `
|
|
|
|
| 1025 |
|
| 1026 |
// تهيئة التطبيق عند تحميل النافذة
|
| 1027 |
window.onload = () => {
|
| 1028 |
+
// التشغيل الأولي للموسيقى (لتجهيزها)
|
| 1029 |
+
toggleBackgroundMusic(false);
|
| 1030 |
renderApp();
|
| 1031 |
};
|
| 1032 |
|