north-star / mobile / files / src / features / ui / wake_lock_controller.ts
Branch mobile · default branch · all branches
wake_lock_controller.ts
f32f5e95 2026-03-16 Pavel Safronov | 1 | import { createWakeLockManager } from '../../platform/wakelock'; |
| 2 | import { createToast } from '../../core/toast'; | |
32796e53 2026-03-16 Pavel Safronov | 3 | import { PUBLIC_SETTINGS } from '../../public_settings'; |
f495a654 2026-03-16 Pavel Safronov | 4 | |
| 5 | type WakeLockControllerOptions = { | |
| 6 | wakeLockToggle: HTMLElement | null; | |
| 7 | isSessionStarted: () => boolean; | |
| 8 | isFullscreen: () => boolean; | |
| 9 | }; | |
| 10 | ||
| 11 | const WAKE_LOCK_ENABLED_STORAGE_KEY = 'friend-compass-wake-lock-enabled'; | |
| 12 | ||
| 13 | export const initWakeLockController = ({ | |
| 14 | wakeLockToggle, | |
| 15 | isSessionStarted, | |
| 16 | isFullscreen | |
| 17 | }: WakeLockControllerOptions) => { | |
| 18 | const { | |
| 19 | setWakeLockEnabled, | |
| 20 | hasWakeLockSupport | |
| 21 | } = createWakeLockManager(); | |
| 22 | ||
d193c692 2026-03-16 Pavel Safronov | 23 | const savedWakeLockPreference = localStorage.getItem(WAKE_LOCK_ENABLED_STORAGE_KEY); |
| 24 | let wakeLockEnabledByToggle = savedWakeLockPreference !== '0'; | |
f495a654 2026-03-16 Pavel Safronov | 25 | const wakeLockToast = createToast({ className: 'wake-lock-toast' }); |
| 26 | ||
| 27 | const getEffectiveWakeLockEnabled = () => isSessionStarted() && (isFullscreen() || wakeLockEnabledByToggle); | |
| 28 | ||
| 29 | const updateWakeLockToggleUi = () => { | |
| 30 | if (!(wakeLockToggle instanceof HTMLButtonElement)) return; | |
| 31 | ||
| 32 | const supported = hasWakeLockSupport(); | |
| 33 | const forcedByFullscreen = isFullscreen(); | |
| 34 | const enabled = forcedByFullscreen || wakeLockEnabledByToggle; | |
| 35 | ||
| 36 | wakeLockToggle.disabled = !supported; | |
32796e53 2026-03-16 Pavel Safronov | 37 | wakeLockToggle.textContent = enabled |
| 38 | ? PUBLIC_SETTINGS.ui.emojis.wakeLock.on | |
| 39 | : PUBLIC_SETTINGS.ui.emojis.wakeLock.off; | |
f495a654 2026-03-16 Pavel Safronov | 40 | wakeLockToggle.classList.toggle('is-on', enabled); |
| 41 | wakeLockToggle.setAttribute('aria-pressed', String(enabled)); | |
| 42 | ||
| 43 | if (!supported) { | |
| 44 | wakeLockToggle.title = 'Wake lock is not supported on this browser/device.'; | |
| 45 | wakeLockToggle.setAttribute('aria-label', 'Wake lock unsupported'); | |
| 46 | return; | |
| 47 | } | |
| 48 | ||
| 49 | if (forcedByFullscreen) { | |
| 50 | wakeLockToggle.title = 'Stay awake is enabled automatically in fullscreen mode.'; | |
| 51 | wakeLockToggle.setAttribute('aria-label', 'Stay awake enabled in fullscreen'); | |
| 52 | return; | |
| 53 | } | |
| 54 | ||
| 55 | wakeLockToggle.title = enabled ? 'Stay awake is on. Tap to allow sleeping.' : 'Stay awake is off. Tap to keep screen awake.'; | |
| 56 | wakeLockToggle.setAttribute('aria-label', enabled ? 'Turn stay awake off' : 'Turn stay awake on'); | |
| 57 | }; | |
| 58 | ||
| 59 | const syncWakeLockPreference = ({ | |
| 60 | announce = false, | |
| 61 | source = 'toggle' | |
| 62 | }: { | |
| 63 | announce?: boolean; | |
| 64 | source?: 'toggle' | 'fullscreen'; | |
| 65 | } = {}) => { | |
| 66 | const shouldStayAwake = getEffectiveWakeLockEnabled(); | |
| 67 | void setWakeLockEnabled(shouldStayAwake); | |
| 68 | updateWakeLockToggleUi(); | |
| 69 | ||
| 70 | if (!announce) return; | |
| 71 | if (!hasWakeLockSupport()) { | |
| 72 | wakeLockToast.show('Stay awake is not supported on this browser.'); | |
| 73 | return; | |
| 74 | } | |
| 75 | ||
| 76 | if (source === 'toggle') { | |
| 77 | if (shouldStayAwake) { | |
| 78 | wakeLockToast.show(isSessionStarted() ? 'Stay awake is on.' : 'Stay awake enabled for when you start the session.'); | |
| 79 | return; | |
| 80 | } | |
| 81 | wakeLockToast.show('Stay awake is off.'); | |
| 82 | return; | |
| 83 | } | |
| 84 | ||
| 85 | if (isFullscreen()) { | |
| 86 | wakeLockToast.show(isSessionStarted() ? 'Fullscreen keeps your screen awake.' : 'Fullscreen will keep your screen awake once the session starts.'); | |
| 87 | return; | |
| 88 | } | |
| 89 | ||
| 90 | wakeLockToast.show(shouldStayAwake ? 'Exited fullscreen. Stay awake is on.' : 'Exited fullscreen. Stay awake is off.'); | |
| 91 | }; | |
| 92 | ||
| 93 | if (wakeLockToggle instanceof HTMLButtonElement) { | |
| 94 | wakeLockToggle.addEventListener('click', () => { | |
| 95 | wakeLockEnabledByToggle = !wakeLockEnabledByToggle; | |
| 96 | localStorage.setItem(WAKE_LOCK_ENABLED_STORAGE_KEY, wakeLockEnabledByToggle ? '1' : '0'); | |
| 97 | syncWakeLockPreference({ announce: true, source: 'toggle' }); | |
| 98 | }); | |
| 99 | } | |
| 100 | ||
| 101 | updateWakeLockToggleUi(); | |
| 102 | ||
| 103 | return { | |
| 104 | syncWakeLockPreference, | |
| 105 | updateWakeLockToggleUi | |
| 106 | }; | |
| 107 | }; |