Commit 00e13552 authored by Mahmoud Aglan's avatar Mahmoud Aglan

feat(game): vibration switch in settings

Haptics (feel.haptic) are off when the player turns vibration off; the
setting persists with the rest of the player's preferences.
Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
parent 8822f88d
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
// //
// One global layer, so every screen gets the same feel without wiring it. // One global layer, so every screen gets the same feel without wiring it.
import * as audio from './audio.js'; import * as audio from './audio.js';
import * as store from './store.js';
const PRESSABLE = 'button, .deck-card, .chip, [role="button"], [role="radio"], [role="switch"], [role="tab"], .tab-item, a.btn'; const PRESSABLE = 'button, .deck-card, .chip, [role="button"], [role="radio"], [role="switch"], [role="tab"], .tab-item, a.btn';
const MOVE_CANCEL = 10; // px of travel that turns a press into a scroll const MOVE_CANCEL = 10; // px of travel that turns a press into a scroll
...@@ -21,6 +22,7 @@ let sceneMountedAt = 0; ...@@ -21,6 +22,7 @@ let sceneMountedAt = 0;
/** Haptics: native shell when present, the Vibration API otherwise. */ /** Haptics: native shell when present, the Vibration API otherwise. */
export function haptic(kind = 'light') { export function haptic(kind = 'light') {
if (store.get('hapticsEnabled') === false) return;
const bridge = window.flutter_bridge; const bridge = window.flutter_bridge;
if (bridge?.postMessage) { if (bridge?.postMessage) {
try { bridge.postMessage(JSON.stringify({ cmd: 'haptic', type: kind })); } catch (e) {} try { bridge.postMessage(JSON.stringify({ cmd: 'haptic', type: kind })); } catch (e) {}
......
This diff is collapsed.
...@@ -11,6 +11,7 @@ const defaultState = { ...@@ -11,6 +11,7 @@ const defaultState = {
features: {}, features: {},
activeWorld: 'play', activeWorld: 'play',
audioEnabled: true, audioEnabled: true,
hapticsEnabled: true,
language: 'ar' language: 'ar'
}; };
...@@ -33,6 +34,7 @@ function persist() { ...@@ -33,6 +34,7 @@ function persist() {
player: state.player, player: state.player,
activeWorld: state.activeWorld, activeWorld: state.activeWorld,
audioEnabled: state.audioEnabled, audioEnabled: state.audioEnabled,
hapticsEnabled: state.hapticsEnabled,
language: state.language, language: state.language,
home: state.home home: state.home
}; };
......
...@@ -14,6 +14,7 @@ import { screenHead, wireBack } from '../../../core/ui.js'; ...@@ -14,6 +14,7 @@ import { screenHead, wireBack } from '../../../core/ui.js';
export function mountSettings(el) { export function mountSettings(el) {
const lang = store.get('language') || 'ar'; const lang = store.get('language') || 'ar';
const audioOn = !!store.get('audioEnabled'); const audioOn = !!store.get('audioEnabled');
const hapticsOn = store.get('hapticsEnabled') !== false;
el.innerHTML = ` el.innerHTML = `
<div class="screen st"> <div class="screen st">
...@@ -28,6 +29,13 @@ export function mountSettings(el) { ...@@ -28,6 +29,13 @@ export function mountSettings(el) {
<span class="st-knob"></span> <span class="st-knob"></span>
</button> </button>
</div> </div>
<div class="row st-row">
<span class="st-tile">${gicon('hand', 34)}</span>
<span class="row-main"><span class="row-title" id="st-haptic-label">${t('settings.vibration')}</span></span>
<button class="st-switch" id="toggle-haptics" role="switch" aria-checked="${hapticsOn}" aria-labelledby="st-haptic-label">
<span class="st-knob"></span>
</button>
</div>
<button class="row st-row st-btn" id="toggle-lang"> <button class="row st-row st-btn" id="toggle-lang">
<span class="st-tile">${gicon('chat', 34)}</span> <span class="st-tile">${gicon('chat', 34)}</span>
<span class="row-main"><span class="row-title">${t('settings.language')}</span></span> <span class="row-main"><span class="row-title">${t('settings.language')}</span></span>
...@@ -121,6 +129,13 @@ export function mountSettings(el) { ...@@ -121,6 +129,13 @@ export function mountSettings(el) {
el.querySelector('#toggle-audio')?.focus(); el.querySelector('#toggle-audio')?.focus();
}); });
el.querySelector('#toggle-haptics').addEventListener('click', () => {
store.set('hapticsEnabled', store.get('hapticsEnabled') === false);
if (navigator.vibrate && store.get('hapticsEnabled')) navigator.vibrate(20);
mountSettings(el);
el.querySelector('#toggle-haptics')?.focus();
});
el.querySelector('#toggle-lang').addEventListener('click', () => { el.querySelector('#toggle-lang').addEventListener('click', () => {
const current = store.get('language') || 'ar'; const current = store.get('language') || 'ar';
const next = current === 'ar' ? 'en' : 'ar'; const next = current === 'ar' ? 'en' : 'ar';
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment