Ambient: Sleep-Timer zählt und stoppt Drift (Browser und App), ☾ im Ambient-Tab; sw v74
- app.js: __dioraAmbientCmd, meldet Start/Stopp an die App (DioraNative.ambientState, sie hält Drift bei ausgeschaltetem Bildschirm am Laufen) und an den Browser-Host - podcasts-web.js: der Sleep-Timer zählt auch, solange Ambient spielt, stoppt es beim Ablauf; Nachtautomatik auch beim Ambient-Start Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
b7a81f3e26
commit
794dbadbf5
5 changed files with 70 additions and 17 deletions
|
|
@ -1268,17 +1268,26 @@ function _ambientSize() {
|
|||
}
|
||||
window.addEventListener('resize', () => requestAnimationFrame(_ambientSize));
|
||||
|
||||
// A command for Drift ('start' | 'stop'): the app's notification, the sleep timer.
|
||||
window.__dioraAmbientCmd = function (cmd) {
|
||||
const f = _ambientFrame();
|
||||
if (f && f.contentWindow && f.getAttribute('src')) f.contentWindow.postMessage({type: 'ambient', cmd}, '*');
|
||||
};
|
||||
|
||||
// The radio or a podcast starts: Ambient stops.
|
||||
window.__dioraAmbientStop = function () {
|
||||
const f = _ambientFrame();
|
||||
if (_ambientPlaying && f && f.contentWindow) f.contentWindow.postMessage({type: 'ambient', cmd: 'stop'}, '*');
|
||||
if (_ambientPlaying) window.__dioraAmbientCmd('stop');
|
||||
};
|
||||
window.__dioraAmbientPlaying = () => _ambientPlaying;
|
||||
|
||||
window.addEventListener('message', e => {
|
||||
const f = _ambientFrame();
|
||||
const d = e.data;
|
||||
if (!f || e.source !== f.contentWindow || !d || d.type !== 'ambient' || !d.state) return;
|
||||
_ambientPlaying = d.state === 'playing';
|
||||
// The app keeps it going with the screen off (AmbientService); the browser's sleep timer counts it.
|
||||
if (window.DioraNative && DioraNative.ambientState) DioraNative.ambientState(_ambientPlaying);
|
||||
if (window.__dioraOnAmbient) window.__dioraOnAmbient(_ambientPlaying);
|
||||
if (!_ambientPlaying) return;
|
||||
// Ambient starts: the radio and a podcast here stop.
|
||||
if (typeof isPlaying !== 'undefined' && isPlaying) stopPlayback(false);
|
||||
|
|
|
|||
|
|
@ -544,6 +544,7 @@
|
|||
setFade(1);
|
||||
pause();
|
||||
stopRadio(); // the radio sleeps too (it plays in app.js's element)
|
||||
if (window.__dioraAmbientStop) window.__dioraAmbientStop(); // and Ambient
|
||||
sleepChanged();
|
||||
return;
|
||||
}
|
||||
|
|
@ -574,6 +575,14 @@
|
|||
},
|
||||
};
|
||||
|
||||
const ambientPlaying = () => !!(window.__dioraAmbientPlaying && window.__dioraAmbientPlaying());
|
||||
|
||||
// Ambient starts or stops (app.js): at night the timer may switch itself on; the page shows it.
|
||||
window.__dioraOnAmbient = function (on) {
|
||||
if (on) sleep.maybeAutoEnable();
|
||||
setTimeout(report, 100);
|
||||
};
|
||||
|
||||
// Set, changed or done here: the other devices show it (when this one is the active one).
|
||||
function sleepChanged() {
|
||||
if (typeof sync !== 'undefined' && sync.state && sync.state.device_id === DEVICE_ID) syncSoon();
|
||||
|
|
@ -924,8 +933,8 @@
|
|||
if (playing && Date.now() - lastSaved > 10000) saveNow(id, true);
|
||||
if (playing) skipOutro(id);
|
||||
}
|
||||
// The sleep timer counts while either plays (radio and podcasts share the player).
|
||||
sleep.tick(playing || radioPlaying());
|
||||
// The sleep timer counts while any of them plays (radio and podcasts share the player; Ambient).
|
||||
sleep.tick(playing || radioPlaying() || ambientPlaying());
|
||||
// While playing, the shared player hears from us every 10 s (its place, and that we're alive).
|
||||
if ((playing || radioPlaying()) && Date.now() - sync.lastSent >= REPORT_EVERY_MS && !busy()) syncReport();
|
||||
// Another device's place moves on in the bar too.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
* diora service worker — caches the app shell for offline use.
|
||||
*/
|
||||
|
||||
const CACHE = 'diora-v73';
|
||||
const CACHE = 'diora-v74';
|
||||
const SHELL = [
|
||||
'/static/css/app.css',
|
||||
'/static/js/app.js',
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copied from diora-android d323614 2026-10-03: web-native/static/native-podcast.js
|
||||
// Copied from diora-android 67a915e 2026-10-03: web-native/static/native-podcast.js
|
||||
// by tools/sync_podcast_ui.py. Do not edit here: change it in diora-android
|
||||
// and copy again. The browser host is static/js/podcasts-web.js.
|
||||
|
||||
|
|
@ -2825,6 +2825,22 @@
|
|||
}
|
||||
}
|
||||
|
||||
// Ambient (app.js's #tab-ambient): its sleep timer, a ☾ at the frame's top right corner.
|
||||
function ambientSleepButton() {
|
||||
const tab = $id('tab-ambient');
|
||||
if (!tab || !N.podcastSleep || $id('nui-amb-sleep')) return;
|
||||
const b = button('☾', 'Sleep-Timer', () => sleepMenu(true, true), 'nui-pod-sleep');
|
||||
b.id = 'nui-amb-sleep';
|
||||
tab.append(b);
|
||||
}
|
||||
|
||||
function renderAmbientSleep() {
|
||||
const b = $id('nui-amb-sleep');
|
||||
if (!b) return;
|
||||
b.textContent = sleepLabel(true) || '☾';
|
||||
b.classList.toggle('on', !!sleepLabel(true));
|
||||
}
|
||||
|
||||
// The bar names a running sleep timer: "… · ☾ 12 min".
|
||||
function sleepSuffix() {
|
||||
const l = sleepLabel();
|
||||
|
|
@ -2854,6 +2870,7 @@
|
|||
}
|
||||
|
||||
function renderMini() {
|
||||
renderAmbientSleep();
|
||||
const r = remote();
|
||||
const isPod = player.kind === 'podcast';
|
||||
document.documentElement.classList.toggle('nui-pod-playing', isPod || !!r);
|
||||
|
|
@ -3516,14 +3533,15 @@
|
|||
|
||||
// ---- sleep timer (runs in the app, also with the screen off; episodes and the radio) ----
|
||||
|
||||
// The timer that counts: the other device's while that one is the active one, else ours.
|
||||
function sleepState() {
|
||||
const r = remote();
|
||||
// The timer that counts: the other device's while that one is the active one, else ours
|
||||
// (`local`: ours anyway — Ambient's button, Ambient plays here).
|
||||
function sleepState(local) {
|
||||
const r = local ? null : remote();
|
||||
return (r ? r.sleep : player.sleep) || {};
|
||||
}
|
||||
|
||||
function sleepLabel() {
|
||||
const t = sleepState();
|
||||
function sleepLabel(local) {
|
||||
const t = sleepState(local);
|
||||
if (t.episodes > 0) return t.episodes === 1 ? '☾ Folgenende' : `☾ ${t.episodes} Folgen`;
|
||||
if (t.leftMs > 0) return `☾ ${Math.max(1, Math.ceil(t.leftMs / 60000))} min`;
|
||||
return '';
|
||||
|
|
@ -3562,18 +3580,18 @@
|
|||
|
||||
// Minutes count only while playing; shaking the phone starts them over. With another
|
||||
// device playing, the timer is that device's (set there by the player sync).
|
||||
function sleepMenu(radio) {
|
||||
const r = remote();
|
||||
function sleepMenu(radio, local) {
|
||||
const r = local ? null : remote();
|
||||
const set = r ? (m => remoteCmd('sleep', m)) : N.podcastSleep ? (m => N.podcastSleep(m)) : null;
|
||||
if (!set) return;
|
||||
const onRadio = r ? r.kind === 'radio' : radio === true;
|
||||
const t = sleepState();
|
||||
const t = sleepState(local);
|
||||
const own = player.sleep || {};
|
||||
const on = !!sleepLabel();
|
||||
const on = !!sleepLabel(local);
|
||||
const items = [];
|
||||
if (r) items.push({custom: el('div', 'nui-pod-meta nui-pod-devnote', `Der Sleep-Timer gilt für ${remoteName(r)}.`)});
|
||||
if (on) {
|
||||
items.push({icon: '✕', label: 'Ausschalten', hint: sleepLabel().replace('☾ ', 'läuft: '), action: () => set(0)});
|
||||
items.push({icon: '✕', label: 'Ausschalten', hint: sleepLabel(local).replace('☾ ', 'läuft: '), action: () => set(0)});
|
||||
if (t.leftMs > 0) {
|
||||
for (const m of [5, 10]) {
|
||||
items.push({icon: '+', label: `${m} Minuten länger`, action: () => (!r && N.podcastSleepExtend
|
||||
|
|
@ -4322,6 +4340,7 @@
|
|||
window.refreshAllFeeds = async function () {};
|
||||
build();
|
||||
buildMini();
|
||||
ambientSleepButton();
|
||||
player = parse(N.playerState(), {kind: null});
|
||||
moveFeedListsToServer();
|
||||
render();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copied from diora-android abda34a 2026-10-03: the podcast parts of web-native/static/native.css
|
||||
/* Copied from diora-android 67a915e 2026-10-03: the podcast parts of web-native/static/native.css
|
||||
(bottom sheet, podcasts) by tools/sync_podcast_ui.py. Do not edit here.
|
||||
The web's own additions are in podcasts-web.css. */
|
||||
|
||||
|
|
@ -780,3 +780,19 @@ body.eink .nui-pod-facts a { text-decoration-color: #000; }
|
|||
sheet comes above both (app.css has it at 500/501, under them). */
|
||||
.modal-overlay { z-index: 990; }
|
||||
.modal-dialog { z-index: 991; }
|
||||
|
||||
/* Ambient's sleep timer: a ☾ on the synthesizer's frame, top right (native-podcast.js). */
|
||||
#tab-ambient { position: relative; }
|
||||
#nui-amb-sleep {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
z-index: 2;
|
||||
min-width: 44px;
|
||||
height: 36px;
|
||||
padding: 0 12px;
|
||||
border-radius: 18px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.18);
|
||||
background: rgba(0, 0, 0, 0.55);
|
||||
color: #ddd;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue