feat: settings interactions (theme/mask/brightness/server-url), svg icons, seconds display, page transition
This commit is contained in:
@@ -1,26 +1,112 @@
|
||||
// 设置页:Miuix Preference 分组 + 玻璃条目(通知使用权为可用交互项)
|
||||
// Settings page: Miuix Preference groups + glass items (notification access is interactive)
|
||||
// 设置页:Miuix Preference 分组 + 玻璃条目,含主题/遮罩/亮度/权限/网络交互
|
||||
// Settings page: Miuix Preference groups + glass items with interactions for
|
||||
// theme / mask / brightness / permission / network
|
||||
window.loadSettings = function () {
|
||||
const page = document.querySelector('[data-page="settings"]');
|
||||
if (page.dataset.loaded) return; page.dataset.loaded = '1';
|
||||
page.innerHTML = `<div class="st-wrap">
|
||||
<div class="st-group">显示</div>
|
||||
<div class="st-item"><span class="lbl">跟随系统主题</span><span class="sw on"><i></i></span></div>
|
||||
<div class="st-item"><span class="lbl">屏幕亮度</span><span class="slider"><i></i></span></div>
|
||||
<div class="st-item" id="theme-item">
|
||||
<span class="lbl">主题</span>
|
||||
<span class="arrow" id="theme-state">跟随系统</span>
|
||||
</div>
|
||||
<div class="st-item" id="brightness-item">
|
||||
<span class="lbl">屏幕亮度</span>
|
||||
<span class="arrow" id="brightness-state">›</span>
|
||||
</div>
|
||||
<div class="st-group" id="mask-group" style="display:none">背景遮罩</div>
|
||||
<div class="st-item" id="mask-item" style="display:none">
|
||||
<span class="lbl">启用背景遮罩</span>
|
||||
<span class="sw" id="mask-sw"><i></i></span>
|
||||
</div>
|
||||
<div class="st-item" id="mask-alpha-item" style="display:none">
|
||||
<span class="lbl">遮罩明暗度</span>
|
||||
<span class="slider" id="mask-slider"><i></i></span>
|
||||
</div>
|
||||
<div class="st-group">权限</div>
|
||||
<div class="st-item" id="notif-access">
|
||||
<span class="lbl">通知使用权(媒体卡)</span>
|
||||
<span class="arrow" id="notif-access-state">›</span>
|
||||
</div>
|
||||
<div class="st-group">网络</div>
|
||||
<div class="st-item"><span class="lbl">webAPP 服务器地址</span><span class="arrow">›</span></div>
|
||||
<div class="st-item"><span class="lbl">检查更新</span><span class="arrow">›</span></div>
|
||||
<div class="st-item" id="server-url-item">
|
||||
<span class="lbl">webAPP 服务器地址</span>
|
||||
<span class="arrow" id="server-url-state">›</span>
|
||||
</div>
|
||||
<div class="st-item" id="check-update-item">
|
||||
<span class="lbl">检查更新</span>
|
||||
<span class="arrow" id="check-update-state">›</span>
|
||||
</div>
|
||||
<div class="st-group">关于</div>
|
||||
<div class="st-item"><span class="lbl">版本 0.1.0</span><span class="arrow">›</span></div>
|
||||
</div>`;
|
||||
setupTheme(page);
|
||||
setupMask(page);
|
||||
setupNotificationAccess(page);
|
||||
setupBrightness(page);
|
||||
setupServerUrl(page);
|
||||
setupCheckUpdate(page);
|
||||
};
|
||||
|
||||
// 判断当前是否深色主题(与 mask.js 逻辑一致)
|
||||
// Whether the current theme is dark (same logic as mask.js)
|
||||
function isDarkTheme() {
|
||||
const t = theme.get();
|
||||
if (t === 'dark') return true;
|
||||
if (t === 'light') return false;
|
||||
return matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
}
|
||||
|
||||
// 主题三态循环:跟随系统 → 浅色 → 深色
|
||||
// Theme tri-state cycle: system → light → dark
|
||||
function setupTheme(page) {
|
||||
const state = page.querySelector('#theme-state');
|
||||
const refresh = () => { state.textContent = theme.label(theme.get()); };
|
||||
refresh();
|
||||
page.querySelector('#theme-item').onclick = () => {
|
||||
theme.cycle();
|
||||
refresh();
|
||||
window.mask.apply();
|
||||
setupMask(page); // 主题切换后重算遮罩项的显示与状态
|
||||
};
|
||||
}
|
||||
|
||||
// 背景遮罩:开关 + 明暗度(仅夜间主题显示)
|
||||
// Wallpaper dim: toggle + opacity (shown only under dark theme)
|
||||
function setupMask(page) {
|
||||
const group = page.querySelector('#mask-group');
|
||||
const maskItem = page.querySelector('#mask-item');
|
||||
const alphaItem = page.querySelector('#mask-alpha-item');
|
||||
const sw = page.querySelector('#mask-sw');
|
||||
const slider = page.querySelector('#mask-slider');
|
||||
const thumb = slider.querySelector('i');
|
||||
|
||||
const dark = isDarkTheme();
|
||||
const show = dark;
|
||||
group.style.display = show ? '' : 'none';
|
||||
maskItem.style.display = show ? '' : 'none';
|
||||
alphaItem.style.display = show ? '' : 'none';
|
||||
|
||||
const refresh = () => {
|
||||
sw.classList.toggle('on', window.mask.enabled());
|
||||
const a = window.mask.alpha();
|
||||
thumb.style.left = (a * 100) + '%';
|
||||
slider.style.setProperty('--fill', (a * 100) + '%');
|
||||
};
|
||||
refresh();
|
||||
|
||||
sw.onclick = () => {
|
||||
window.mask.setEnabled(!window.mask.enabled());
|
||||
refresh();
|
||||
};
|
||||
slider.onclick = (e) => {
|
||||
const rect = slider.getBoundingClientRect();
|
||||
const a = Math.min(1, Math.max(0, (e.clientX - rect.left) / rect.width));
|
||||
window.mask.setAlpha(Math.round(a * 100) / 100);
|
||||
refresh();
|
||||
};
|
||||
}
|
||||
|
||||
// 通知使用权授权项:异步查状态,未授权点击跳转系统授权页
|
||||
// Notification-access item: async state check, tap to open the system grant page
|
||||
function setupNotificationAccess(page) {
|
||||
@@ -34,3 +120,103 @@ function setupNotificationAccess(page) {
|
||||
bridge.call('requestNotificationAccess').catch(() => {});
|
||||
};
|
||||
}
|
||||
|
||||
// 屏幕亮度:未授权「修改系统设置」时跳授权页,已授权点击滑块调整系统亮度
|
||||
// Screen brightness: jump to grant page when lacking WRITE_SETTINGS; adjust via
|
||||
// slider click once granted
|
||||
function setupBrightness(page) {
|
||||
const item = page.querySelector('#brightness-item');
|
||||
const state = page.querySelector('#brightness-state');
|
||||
let sliderEl = null;
|
||||
|
||||
const renderSlider = (value) => {
|
||||
if (sliderEl) sliderEl.remove();
|
||||
sliderEl = document.createElement('span');
|
||||
sliderEl.className = 'slider brightness-slider';
|
||||
sliderEl.innerHTML = '<i></i>';
|
||||
sliderEl.style.width = '160px';
|
||||
const pct = value / 255 * 100;
|
||||
sliderEl.style.setProperty('--fill', pct + '%');
|
||||
sliderEl.querySelector('i').style.left = pct + '%';
|
||||
sliderEl.onclick = (e) => {
|
||||
e.stopPropagation();
|
||||
const rect = sliderEl.getBoundingClientRect();
|
||||
const v = Math.round(Math.min(255, Math.max(0, (e.clientX - rect.left) / rect.width)) * 255);
|
||||
bridge.call('setSystemBrightness', v).then(() => renderSlider(v)).catch(() => {});
|
||||
};
|
||||
item.appendChild(sliderEl);
|
||||
};
|
||||
|
||||
const refresh = () => {
|
||||
bridge.call('canWriteSettings').then(canWrite => {
|
||||
if (!canWrite) {
|
||||
state.textContent = '去授权 ›';
|
||||
if (sliderEl) { sliderEl.remove(); sliderEl = null; }
|
||||
} else {
|
||||
bridge.call('getSystemBrightness').then(v => {
|
||||
state.textContent = '';
|
||||
renderSlider(v);
|
||||
}).catch(() => {});
|
||||
}
|
||||
}).catch(() => {});
|
||||
};
|
||||
refresh();
|
||||
|
||||
item.onclick = () => {
|
||||
bridge.call('canWriteSettings').then(canWrite => {
|
||||
if (!canWrite) bridge.call('requestWriteSettings');
|
||||
}).catch(() => {});
|
||||
};
|
||||
}
|
||||
|
||||
// webAPP 服务器地址:点击展开输入框,保存后重新拉取清单
|
||||
// webAPP server URL: expand an input on tap, re-fetch manifest after saving
|
||||
function setupServerUrl(page) {
|
||||
const item = page.querySelector('#server-url-item');
|
||||
const state = page.querySelector('#server-url-state');
|
||||
let editing = false;
|
||||
|
||||
const startEdit = (current) => {
|
||||
editing = true;
|
||||
item.innerHTML = '<input class="url-input" id="server-url-input" value="' + (current || '').replace(/"/g, '"') + '">';
|
||||
const input = item.querySelector('#server-url-input');
|
||||
input.focus();
|
||||
const save = () => {
|
||||
bridge.call('setServerUrl', input.value.trim()).then(() => {
|
||||
editing = false;
|
||||
refresh();
|
||||
}).catch(() => {});
|
||||
};
|
||||
input.onkeydown = (e) => { if (e.key === 'Enter') save(); };
|
||||
input.onblur = () => { save(); };
|
||||
};
|
||||
|
||||
const refresh = () => {
|
||||
bridge.call('getServerUrl').then(url => {
|
||||
state.textContent = (url || '未设置') + ' ›';
|
||||
}).catch(() => {});
|
||||
};
|
||||
refresh();
|
||||
|
||||
item.onclick = () => {
|
||||
if (editing) return;
|
||||
bridge.call('getServerUrl').then(startEdit).catch(() => startEdit(''));
|
||||
};
|
||||
}
|
||||
|
||||
// 检查更新:触发重新拉取 webAPP 清单 + 卡片目录,完成后提示
|
||||
// Check update: re-fetch the webAPP manifest + card catalog, then show a hint
|
||||
function setupCheckUpdate(page) {
|
||||
const item = page.querySelector('#check-update-item');
|
||||
const state = page.querySelector('#check-update-state');
|
||||
item.onclick = () => {
|
||||
state.textContent = '检查中…';
|
||||
bridge.call('refreshManifest').then(result => {
|
||||
let n = 0;
|
||||
try { n = JSON.parse(result).count || 0; } catch (e) {}
|
||||
state.textContent = n > 0 ? '已更新 ' + n + ' 个 ›' : '无更新 ›';
|
||||
}).catch(() => {
|
||||
state.textContent = '失败 ›';
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user