diff --git a/MindShift-Windows/MindShift-v1.0.5.apk b/MindShift-Windows/MindShift-v1.0.5.apk new file mode 100644 index 0000000..5f98266 Binary files /dev/null and b/MindShift-Windows/MindShift-v1.0.5.apk differ diff --git a/MindShift-Windows/package.json b/MindShift-Windows/package.json index 71063d7..1ea59d8 100644 --- a/MindShift-Windows/package.json +++ b/MindShift-Windows/package.json @@ -1,6 +1,6 @@ { "name": "mindshift-cbt-therapy", - "version": "1.0.4", + "version": "1.0.5", "description": "MindShift - Your personal CBT therapy companion for Windows 11", "main": "src/main.js", "homepage": "./", diff --git a/MindShift-Windows/src/app.js b/MindShift-Windows/src/app.js index e3e5a05..2c1a94d 100644 --- a/MindShift-Windows/src/app.js +++ b/MindShift-Windows/src/app.js @@ -1222,72 +1222,119 @@ function quickRelax() { startGuidedRelaxation(); } -// --- Guided Relaxation (5-4-3-2-1 Grounding) --- +// --- Guided Relaxation (Mindfulness System) --- let relaxationState = { + mode: null, // 'grounding', 'body_scan', 'visualization' step: 0, isActive: false, - steps: [] // Will be populated dynamically based on language + isPaused: false, + steps: [], + timer: null, + duration: 0 }; -function getRelaxationSteps() { +// Data Providers +function getGroundingSteps() { return [ - { - title: t('guided_sight_title'), - instruction: t('guided_sight_instruction'), - sub: t('guided_sight_sub'), - count: 5, - icon: "👁️", - color: "#64B5F6" - }, - { - title: t('guided_touch_title'), - instruction: t('guided_touch_instruction'), - sub: t('guided_touch_sub'), - count: 4, - icon: "✋", - color: "#81C784" - }, - { - title: t('guided_sound_title'), - instruction: t('guided_sound_instruction'), - sub: t('guided_sound_sub'), - count: 3, - icon: "👂", - color: "#FFB74D" - }, - { - title: t('guided_smell_title'), - instruction: t('guided_smell_instruction'), - sub: t('guided_smell_sub'), - count: 2, - icon: "👃", - color: "#BA68C8" - }, - { - title: t('guided_taste_title'), - instruction: t('guided_taste_instruction'), - sub: t('guided_taste_sub'), - count: 1, - icon: "👅", - color: "#E57373" - } + { title: t('guided_sight_title'), instruction: t('guided_sight_instruction'), sub: t('guided_sight_sub'), count: 5, icon: "👁️", color: "#64B5F6" }, + { title: t('guided_touch_title'), instruction: t('guided_touch_instruction'), sub: t('guided_touch_sub'), count: 4, icon: "✋", color: "#81C784" }, + { title: t('guided_sound_title'), instruction: t('guided_sound_instruction'), sub: t('guided_sound_sub'), count: 3, icon: "👂", color: "#FFB74D" }, + { title: t('guided_smell_title'), instruction: t('guided_smell_instruction'), sub: t('guided_smell_sub'), count: 2, icon: "👃", color: "#BA68C8" }, + { title: t('guided_taste_title'), instruction: t('guided_taste_instruction'), sub: t('guided_taste_sub'), count: 1, icon: "👅", color: "#E57373" } ]; } +function getBodyScanSteps() { + return [ + { instruction: t('scan_intro'), duration: 5000 }, + { instruction: t('scan_feet'), duration: 8000 }, + { instruction: t('scan_legs'), duration: 8000 }, + { instruction: t('scan_stomach'), duration: 8000 }, + { instruction: t('scan_chest'), duration: 8000 }, + { instruction: t('scan_shoulders'), duration: 8000 }, + { instruction: t('scan_face'), duration: 8000 }, + { instruction: t('scan_outro'), duration: 6000 } + ]; +} + +function getVisualizationSteps() { + return [ + { instruction: t('vis_intro'), duration: 6000 }, + { instruction: t('vis_step1'), duration: 10000 }, + { instruction: t('vis_step2'), duration: 10000 }, + { instruction: t('vis_step3'), duration: 10000 }, + { instruction: t('vis_step4'), duration: 10000 }, + { instruction: t('vis_outro'), duration: 8000 } + ]; +} + +// Entry Point function startGuidedRelaxation() { - relaxationState.step = 0; - relaxationState.isActive = true; - relaxationState.steps = getRelaxationSteps(); + relaxationState = { mode: null, step: 0, isActive: true, isPaused: false, steps: [], timer: null, duration: 0 }; const overlay = document.createElement('div'); overlay.id = 'guided-relaxation-overlay'; overlay.className = 'guided-overlay'; document.body.appendChild(overlay); - renderRelaxationStep(); + // Add styles dynamically if not present (using the styles we wrote to guided-styles.css but injecting here for simplicity in single file context if needed, but best to rely on CSS file) + // Assuming guided-styles.css is linked or merged. For safety, we rely on the styles.css update. + + renderModeSelection(); } -function renderRelaxationStep() { +function renderModeSelection() { + const overlay = document.getElementById('guided-relaxation-overlay'); + if (!overlay) return; + + overlay.innerHTML = ` +
+ +
+ +

${t('guided_select_mode')}

+ +
+
+ 🌿 + ${t('mode_grounding')} +
+
+ 🧘 + ${t('mode_body_scan')} +
+
+ 🌄 + ${t('mode_visualization')} +
+
+ `; +} + +function startSession(mode) { + relaxationState.mode = mode; + relaxationState.step = 0; + relaxationState.isActive = true; + + const overlay = document.getElementById('guided-relaxation-overlay'); + if (overlay) overlay.className = `guided-overlay mode-${mode}`; + + if (mode === 'grounding') { + relaxationState.steps = getGroundingSteps(); + renderGroundingStep(); + } else if (mode === 'body_scan') { + relaxationState.steps = getBodyScanSteps(); + runAutoSession(); + } else if (mode === 'visualization') { + relaxationState.steps = getVisualizationSteps(); + runAutoSession(); + } +} + +// --- Grounding Logic (Interactive) --- +function renderGroundingStep() { const overlay = document.getElementById('guided-relaxation-overlay'); if (!overlay || !relaxationState.isActive) return; @@ -1312,24 +1359,20 @@ function renderRelaxationStep() { ${progressDots} - `; - // Speak instruction speakText(`${currentStep.instruction} ${currentStep.sub}`); } let currentDotIndex = 0; - -function nextRelaxationSubStep() { +function nextGroundingSubStep() { const dots = document.querySelectorAll('.progress-dot'); if (currentDotIndex < dots.length) { dots[currentDotIndex].classList.add('active'); - // Haptic feedback if (navigator.vibrate) navigator.vibrate(50); - // Sound feedback soundManager.playTone(400 + (currentDotIndex * 50), 'sine', 0.1, 0.1); currentDotIndex++; @@ -1339,16 +1382,75 @@ function nextRelaxationSubStep() { currentDotIndex = 0; relaxationState.step++; if (relaxationState.step < relaxationState.steps.length) { - renderRelaxationStep(); + renderGroundingStep(); } else { - finishGuidedRelaxation(); + finishSession(); } }, 1000); } } } -function finishGuidedRelaxation() { +// --- Auto Session Logic (Body Scan & Visualization) --- +function runAutoSession() { + const overlay = document.getElementById('guided-relaxation-overlay'); + if (!overlay || !relaxationState.isActive) return; + + const step = relaxationState.steps[relaxationState.step]; + const totalSteps = relaxationState.steps.length; + const progress = ((relaxationState.step) / totalSteps) * 100; + + // Visuals based on mode + let visualHTML = ''; + if (relaxationState.mode === 'body_scan') { + visualHTML = `
🧘
`; + } else { + visualHTML = `
🌄
`; + } + + overlay.innerHTML = ` +
+ +
+ + ${visualHTML} + +
${step.instruction}
+ +
+
+
+ +
+ +
+ `; + + // Speak and advance + speakText(step.instruction, () => { + // On end of speech, wait remainder of duration + if (!relaxationState.isActive) return; + + relaxationState.timer = setTimeout(() => { + relaxationState.step++; + if (relaxationState.step < relaxationState.steps.length) { + runAutoSession(); + } else { + finishSession(); + } + }, 2000); // Short pause after speech + }); + + // Animate progress bar + setTimeout(() => { + const bar = document.querySelector('.guided-progress-bar'); + if (bar) bar.style.width = `${((relaxationState.step + 1) / totalSteps) * 100}%`; + }, 100); +} + +function finishSession() { const overlay = document.getElementById('guided-relaxation-overlay'); if (overlay) { overlay.innerHTML = ` @@ -1361,11 +1463,17 @@ function finishGuidedRelaxation() { `; speakText(`${t('guided_complete_title')} ${t('guided_complete_sub')}`); triggerSuccessPing(); + + // Log stats + const duration = relaxationState.mode === 'grounding' ? 180 : + relaxationState.mode === 'body_scan' ? 300 : 240; + exerciseAPI.logSession(relaxationState.mode, duration).then(() => updateProgress()); } } function closeGuidedRelaxation() { relaxationState.isActive = false; + if (relaxationState.timer) clearTimeout(relaxationState.timer); currentDotIndex = 0; const overlay = document.getElementById('guided-relaxation-overlay'); if (overlay) overlay.remove(); @@ -1373,29 +1481,27 @@ function closeGuidedRelaxation() { if (window.speechSynthesis) { window.speechSynthesis.cancel(); } - - // Log session - if (relaxationState.step >= relaxationState.steps.length) { - exerciseAPI.logSession('grounding', 180).then(() => updateProgress()); - } } -function speakText(text) { +// Enhanced TTS Wrapper +function speakText(text, onEndCallback) { if ('speechSynthesis' in window) { - window.speechSynthesis.cancel(); // Stop previous + window.speechSynthesis.cancel(); const utterance = new SpeechSynthesisUtterance(text); - utterance.rate = 0.9; + utterance.rate = 0.85; // Slightly slower for relaxation utterance.pitch = 1.0; - // Map language codes to TTS locales - const langMap = { - 'en': 'en-US', - 'ru': 'ru-RU', - 'he': 'he-IL' - }; + const langMap = { 'en': 'en-US', 'ru': 'ru-RU', 'he': 'he-IL' }; utterance.lang = langMap[currentLang] || 'en-US'; + if (onEndCallback) { + utterance.onend = onEndCallback; + } + window.speechSynthesis.speak(utterance); + } else { + // Fallback if no TTS + if (onEndCallback) setTimeout(onEndCallback, 3000); } } diff --git a/MindShift-Windows/src/guided-styles.css b/MindShift-Windows/src/guided-styles.css new file mode 100644 index 0000000..b660078 --- /dev/null +++ b/MindShift-Windows/src/guided-styles.css @@ -0,0 +1,183 @@ +/* Guided Relaxation - Mindfulness Session */ +.guided-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: radial-gradient(circle at center, #2E7D32, #004D40); + z-index: 6000; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + color: white; + animation: fadeIn 0.5s ease; + padding: 20px; + text-align: center; + transition: background 1s ease; +} + +/* Mode specific backgrounds */ +.guided-overlay.mode-body_scan { + background: radial-gradient(circle at center, #4A148C, #311B92); +} + +.guided-overlay.mode-visualization { + background: radial-gradient(circle at center, #00695C, #004D40); +} + +.guided-title-large { + font-size: 32px; + font-weight: 300; + margin-bottom: 40px; + letter-spacing: 1px; + animation: slideInDown 0.5s ease; +} + +.guided-step-icon { + font-size: 100px; + margin-bottom: 40px; + animation: floatIcon 4s ease-in-out infinite; + filter: drop-shadow(0 0 30px rgba(255,255,255,0.4)); + transition: all 0.5s ease; +} + +@keyframes floatIcon { + 0%, 100% { transform: translateY(0) scale(1); } + 50% { transform: translateY(-20px) scale(1.05); } +} + +.guided-instruction { + font-size: 28px; + font-weight: 400; + margin-bottom: 20px; + line-height: 1.4; + max-width: 800px; + animation: fadeIn 0.5s ease; +} + +.guided-sub { + font-size: 20px; + opacity: 0.8; + margin-bottom: 50px; + max-width: 600px; + font-weight: 300; + animation: fadeIn 0.5s ease 0.2s both; +} + +/* Progress Bar for auto-playing sessions */ +.guided-progress-bar-container { + width: 80%; + max-width: 300px; + height: 6px; + background: rgba(255,255,255,0.2); + border-radius: 3px; + margin-bottom: 40px; + overflow: hidden; +} + +.guided-progress-bar { + height: 100%; + background: white; + width: 0%; + transition: width linear; +} + +/* Mode Selection Menu */ +.guided-mode-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); + gap: 20px; + width: 100%; + max-width: 800px; +} + +.guided-mode-card { + background: rgba(255,255,255,0.1); + border: 1px solid rgba(255,255,255,0.3); + border-radius: 20px; + padding: 24px; + cursor: pointer; + transition: all 0.3s ease; + backdrop-filter: blur(10px); +} + +.guided-mode-card:hover { + background: rgba(255,255,255,0.2); + transform: translateY(-5px); + box-shadow: 0 10px 30px rgba(0,0,0,0.2); +} + +.guided-mode-icon { + font-size: 48px; + margin-bottom: 16px; + display: block; +} + +.guided-mode-title { + font-size: 18px; + font-weight: 500; +} + +.guided-controls { + position: absolute; + top: 20px; + right: 20px; + display: flex; + gap: 16px; + z-index: 10; +} + +.guided-bottom-controls { + display: flex; + gap: 20px; + align-items: center; +} + +.play-pause-btn { + width: 64px; + height: 64px; + border-radius: 50%; + background: white; + color: var(--primary-dark); + border: none; + display: flex; + align-items: center; + justify-content: center; + font-size: 32px; + cursor: pointer; + box-shadow: 0 4px 20px rgba(0,0,0,0.3); + transition: transform 0.2s; +} + +.play-pause-btn:hover { + transform: scale(1.1); +} + +.play-pause-btn:active { + transform: scale(0.95); +} + +/* Pulse Animation for Body Scan */ +.body-scan-pulse { + position: absolute; + width: 300px; + height: 300px; + border-radius: 50%; + border: 2px solid rgba(255,255,255,0.3); + animation: scanPulse 4s infinite; + pointer-events: none; +} + +@keyframes scanPulse { + 0% { transform: scale(0.8); opacity: 0; } + 50% { opacity: 1; } + 100% { transform: scale(1.5); opacity: 0; } +} + +/* RTL Fixes for Guided */ +html[dir="rtl"] .guided-controls { + right: auto; + left: 20px; +} diff --git a/MindShift-Windows/src/index.html b/MindShift-Windows/src/index.html index 1d23cda..3f8394a 100644 --- a/MindShift-Windows/src/index.html +++ b/MindShift-Windows/src/index.html @@ -24,6 +24,7 @@ + diff --git a/MindShift-Windows/src/translations.js b/MindShift-Windows/src/translations.js index 5a6f14c..37c692d 100644 --- a/MindShift-Windows/src/translations.js +++ b/MindShift-Windows/src/translations.js @@ -94,7 +94,14 @@ export const translations = { "quick_relax_now": "Relax Now", "close": "Close", - // Guided Relaxation (Grounding) + // Guided Relaxation + "guided_title": "Mindfulness Session", + "guided_select_mode": "Select a Session", + "mode_grounding": "Grounding (5-4-3-2-1)", + "mode_body_scan": "Body Scan", + "mode_visualization": "Visualization", + + // Grounding "guided_sight_title": "Sight", "guided_sight_instruction": "Look around you.", "guided_sight_sub": "Find 5 things you can see.", @@ -114,6 +121,24 @@ export const translations = { "guided_complete_title": "You did great!", "guided_complete_sub": "Feeling more grounded?", "guided_complete_btn": "Complete", + + // Body Scan Script + "scan_intro": "Find a comfortable position and close your eyes.", + "scan_feet": "Focus on your feet. Feel the weight of them.", + "scan_legs": "Move your attention to your legs. Let them relax.", + "scan_stomach": "Notice your stomach. Breathe deeply into it.", + "scan_chest": "Feel your chest rise and fall with each breath.", + "scan_shoulders": "Release any tension in your shoulders.", + "scan_face": "Soften your jaw and forehead.", + "scan_outro": "Take a deep breath. When you're ready, open your eyes.", + + // Visualization Script + "vis_intro": "Close your eyes and imagine a peaceful place.", + "vis_step1": "You are walking in a quiet, ancient forest.", + "vis_step2": "The air is fresh and smells of pine.", + "vis_step3": "Sunlight filters through the leaves above.", + "vis_step4": "You hear a gentle stream nearby.", + "vis_outro": "Carry this peace with you. Open your eyes.", // Smart Breathing "breath_balance": "Balance", @@ -228,6 +253,12 @@ export const translations = { "close": "Закрыть", // Guided Relaxation + "guided_title": "Сессия осознанности", + "guided_select_mode": "Выберите сессию", + "mode_grounding": "Заземление (5-4-3-2-1)", + "mode_body_scan": "Сканирование тела", + "mode_visualization": "Визуализация", + "guided_sight_title": "Зрение", "guided_sight_instruction": "Оглянитесь вокруг.", "guided_sight_sub": "Найдите 5 вещей, которые вы видите.", @@ -247,6 +278,24 @@ export const translations = { "guided_complete_title": "Отлично!", "guided_complete_sub": "Чувствуете себя спокойнее?", "guided_complete_btn": "Завершить", + + // Body Scan Script + "scan_intro": "Примите удобное положение и закройте глаза.", + "scan_feet": "Сосредоточьтесь на ногах. Почувствуйте их вес.", + "scan_legs": "Переведите внимание на ноги. Расслабьте их.", + "scan_stomach": "Заметьте свой живот. Дышите глубоко.", + "scan_chest": "Почувствуйте, как поднимается грудь при вдохе.", + "scan_shoulders": "Отпустите напряжение в плечах.", + "scan_face": "Расслабьте челюсть и лоб.", + "scan_outro": "Сделайте глубокий вдох. Откройте глаза.", + + // Visualization Script + "vis_intro": "Закройте глаза и представьте спокойное место.", + "vis_step1": "Вы идете по тихому древнему лесу.", + "vis_step2": "Воздух свежий и пахнет хвоей.", + "vis_step3": "Солнечный свет пробивается сквозь листву.", + "vis_step4": "Вы слышите тихий ручей неподалеку.", + "vis_outro": "Сохраните это спокойствие. Откройте глаза.", // Smart Breathing "breath_balance": "Баланс", @@ -361,6 +410,12 @@ export const translations = { "close": "סגור", // Guided Relaxation + "guided_title": "אימון קשיבות", + "guided_select_mode": "בחר אימון", + "mode_grounding": "קרקוע (5-4-3-2-1)", + "mode_body_scan": "סריקת גוף", + "mode_visualization": "דמיון מודרך", + "guided_sight_title": "ראייה", "guided_sight_instruction": "הביטו סביבכם.", "guided_sight_sub": "מצאו 5 דברים שאתם רואים.", @@ -380,6 +435,24 @@ export const translations = { "guided_complete_title": "כל הכבוד!", "guided_complete_sub": "מרגישים מקורקעים יותר?", "guided_complete_btn": "סיים", + + // Body Scan Script + "scan_intro": "מצאו תנוחה נוחה ועצמו עיניים.", + "scan_feet": "התמקדו בכפות הרגליים. הרגישו את המשקל שלהן.", + "scan_legs": "העבירו את תשומת הלב לרגליים. הרפו אותן.", + "scan_stomach": "שימו לב לבטן. נשמו עמוק לתוכה.", + "scan_chest": "הרגישו את החזה עולה ויורד עם כל נשימה.", + "scan_shoulders": "שחררו כל מתח בכתפיים.", + "scan_face": "הרפו את הלסת והמצח.", + "scan_outro": "קחו נשימה עמוקה. כשאתם מוכנים, פקחו עיניים.", + + // Visualization Script + "vis_intro": "עצמו עיניים ודמיינו מקום שליו.", + "vis_step1": "אתם הולכים ביער עתיק ושקט.", + "vis_step2": "האוויר רענן ומריח כמו אורנים.", + "vis_step3": "אור השמש מסתנן מבעד לעלים.", + "vis_step4": "אתם שומעים פלג מים עדין בקרבת מקום.", + "vis_outro": "שאו את השלווה הזו איתכם. פקחו עיניים.", // Smart Breathing "breath_balance": "איזון",