Add monitor wake lock toggle

This commit is contained in:
seo
2026-06-15 19:37:16 +09:00
parent 2eb396cdfe
commit 05376742cd
2 changed files with 98 additions and 10 deletions
+93 -10
View File
@@ -875,20 +875,18 @@ if (isset($_GET['mode']) && $_GET['mode'] === 'usage') {
font-family: 'SF Mono', monospace; font-size: 0.75rem;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 180px; margin: 0 auto;
}
.btn-theme-toggle {
.btn-icon-toggle {
width: 40px; height: 40px; border-radius: 50%; border: 1px solid var(--card-border);
background: var(--card-bg); color: var(--text-primary);
display: flex; align-items: center; justify-content: center; cursor: pointer;
transition: all 0.2s;
}
.btn-theme-toggle:hover { background: var(--bg-body); transform: scale(1.05); }
.btn-lang-toggle {
width: 40px; height: 40px; border-radius: 50%; border: 1px solid var(--card-border);
background: var(--card-bg); color: var(--text-primary);
display: flex; align-items: center; justify-content: center; cursor: pointer;
transition: all 0.2s;
.btn-icon-toggle:hover { background: var(--bg-body); transform: scale(1.05); }
.btn-icon-toggle.active {
background: var(--box-bg-green);
border-color: rgba(34, 197, 94, 0.45);
color: var(--accent-green);
}
.btn-lang-toggle:hover { background: var(--bg-body); transform: scale(1.05); }
@keyframes pulse-ring {
0% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.7); }
@@ -1041,10 +1039,13 @@ if (isset($_GET['mode']) && $_GET['mode'] === 'usage') {
<div class="label-text mb-0" data-i18n="lastData">LAST DATA</div>
<div id="last-updated" class="font-mono fw-bold text-primary">--:--:--</div>
</div>
<button class="btn-lang-toggle shadow-sm" id="lang-btn" onclick="toggleLanguage()" title="Language">
<button class="btn-icon-toggle shadow-sm" id="wakelock-btn" onclick="toggleWakeLock()" title="WakeLock">
<i class="fas fa-mobile-screen-button"></i>
</button>
<button class="btn-icon-toggle shadow-sm" id="lang-btn" onclick="toggleLanguage()" title="Language">
<i class="fas fa-globe"></i>
</button>
<button class="btn-theme-toggle shadow-sm" id="theme-btn" onclick="toggleTheme()">
<button class="btn-icon-toggle shadow-sm" id="theme-btn" onclick="toggleTheme()">
<i class="fas fa-moon"></i>
</button>
</div>
@@ -1371,6 +1372,8 @@ if (isset($_GET['mode']) && $_GET['mode'] === 'usage') {
engineStateOnSentence: '시동이 {duration} 켜져있음',
engineStateOffSentence: '시동이 {duration} 꺼져있음',
dataUsageTitle: '{month} 데이터 사용량 / {days}일 남음',
wakeLockTitle: '화면 켜짐 유지',
wakeLockUnsupported: '화면 켜짐 유지 미지원',
languageTitle: '언어 변경',
rawView: '원본 보기',
cmdStatus: '상태',
@@ -1434,6 +1437,8 @@ if (isset($_GET['mode']) && $_GET['mode'] === 'usage') {
engineStateOnSentence: 'Engine has been ON for {duration}',
engineStateOffSentence: 'Engine has been OFF for {duration}',
dataUsageTitle: '{month} Data Usage / {days}d left',
wakeLockTitle: 'Keep screen awake',
wakeLockUnsupported: 'WakeLock unavailable',
languageTitle: 'Change language',
rawView: 'View RAW',
cmdStatus: 'STATUS',
@@ -1470,16 +1475,25 @@ if (isset($_GET['mode']) && $_GET['mode'] === 'usage') {
let usageTimer = null;
let usageRefreshIntervalSec = DEFAULT_USAGE_REFRESH_INTERVAL_SEC;
let usageInFlight = false;
let wakeLockSentinel = null;
let wakeLockWanted = false;
document.addEventListener('DOMContentLoaded', () => {
initLanguage();
initTheme();
initWakeLock();
initChart();
fetchData();
refreshTimer = setInterval(fetchData, 1000);
fetchUsage();
});
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible' && wakeLockWanted) {
requestWakeLock();
}
});
function initLanguage() {
const saved = localStorage.getItem('lang');
const browser = (navigator.language || navigator.userLanguage || 'ko').toLowerCase();
@@ -1515,6 +1529,7 @@ if (isset($_GET['mode']) && $_GET['mode'] === 'usage') {
langBtn.title = t('languageTitle');
langBtn.setAttribute('aria-label', t('languageTitle'));
}
updateWakeLockButton();
}
function initTheme() {
@@ -1539,6 +1554,74 @@ if (isset($_GET['mode']) && $_GET['mode'] === 'usage') {
icon.className = theme === 'dark' ? 'fas fa-sun text-warning' : 'fas fa-moon text-secondary';
}
function initWakeLock() {
wakeLockWanted = localStorage.getItem('wakeLock') === 'on';
updateWakeLockButton();
if (wakeLockWanted) {
requestWakeLock();
}
}
function wakeLockSupported() {
return 'wakeLock' in navigator;
}
async function requestWakeLock() {
if (!wakeLockSupported()) {
wakeLockWanted = false;
localStorage.setItem('wakeLock', 'off');
updateWakeLockButton();
return;
}
try {
wakeLockSentinel = await navigator.wakeLock.request('screen');
wakeLockSentinel.addEventListener('release', () => {
wakeLockSentinel = null;
updateWakeLockButton();
});
updateWakeLockButton();
} catch (error) {
wakeLockSentinel = null;
updateWakeLockButton();
}
}
async function releaseWakeLock() {
if (wakeLockSentinel) {
try {
await wakeLockSentinel.release();
} catch (error) {
// Browser may already have released it on visibility or power policy changes.
}
}
wakeLockSentinel = null;
updateWakeLockButton();
}
function toggleWakeLock() {
wakeLockWanted = !wakeLockWanted;
localStorage.setItem('wakeLock', wakeLockWanted ? 'on' : 'off');
if (wakeLockWanted) {
requestWakeLock();
} else {
releaseWakeLock();
}
updateWakeLockButton();
}
function updateWakeLockButton() {
const btn = document.getElementById('wakelock-btn');
if (!btn) return;
const supported = wakeLockSupported();
const active = Boolean(wakeLockSentinel);
btn.classList.toggle('active', active);
btn.disabled = !supported;
btn.title = supported ? t('wakeLockTitle') : t('wakeLockUnsupported');
btn.setAttribute('aria-label', btn.title);
}
function getChartColors() {
const style = getComputedStyle(document.body);
return {