From d880431a5afdedd4d50315bf8596955fdce0dcc4 Mon Sep 17 00:00:00 2001 From: x12sa Date: Mon, 6 Jul 2026 09:41:00 +0200 Subject: [PATCH] webpage_generator: success chime on finish + trim mobile empty scroll space - Audio: a normal finish (scanning -> idle) now plays a rising success arpeggio (C5-E5-G5) instead of the falling warning chime, so a completed measurement is audibly distinct from a stop to any other state (which keeps the falling 660->440 warning). startWarning(finished) selects the chime for both the initial tone and the 30s repeats; the Watch LED text reads "Measurement finished" vs "Measurement stopped" accordingly. Help text updated. - Layout: body uses min-height:100dvh (with 100vh fallback) so the page no longer extends below the visible viewport on mobile, where iOS 100vh counts the retracted-toolbar height and leaves empty scroll room at the bottom. --- .../flomni/flomni_webpage_generator.py | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/csaxs_bec/bec_ipython_client/plugins/flomni/flomni_webpage_generator.py b/csaxs_bec/bec_ipython_client/plugins/flomni/flomni_webpage_generator.py index 0802302..4c59eff 100644 --- a/csaxs_bec/bec_ipython_client/plugins/flomni/flomni_webpage_generator.py +++ b/csaxs_bec/bec_ipython_client/plugins/flomni/flomni_webpage_generator.py @@ -1633,7 +1633,11 @@ def _render_html(phone_numbers: list, has_tomo_queue: bool = True, tomo_types: d body {{ background: var(--bg); color: var(--text); font-family: var(--sans); font-weight: 300; - min-height: 100vh; padding: 1.5rem; + min-height: 100vh; /* fallback for browsers without dvh */ + min-height: 100dvh; /* dynamic viewport: avoids extra scroll room + below content on mobile (iOS 100vh counts the + retracted-toolbar height and overshoots) */ + padding: 1.5rem; transition: background 0.4s, color 0.4s; }} body::before {{ @@ -2157,7 +2161,7 @@ def _render_html(phone_numbers: list, has_tomo_queue: bool = True, tomo_types: d

Audio warnings

@@ -2353,6 +2357,7 @@ initDrag(); let audioCtx=null, audioEnabled=false; let audioArmed=false, warningActive=false, warningTimer=null, lastStatus=null; +let warningWasSuccess=false; // true when the active warning is a normal finish (scanning -> idle) let staleActive=false, staleTimer=null, staleConfirmed=false; let blockedSince=null, blockedWarningActive=false, blockedChimeTimer=null; const BLOCKED_WARNING_DELAY_MS=60*60*1000; // first chime after 60 min continuously blocked @@ -2387,6 +2392,13 @@ function beep(freq,dur,vol){{ function warningChime(){{ beep(660,0.3,0.4); setTimeout(()=>beep(440,0.5,0.4),350); }} +function successChime(){{ + // Reverse of warningChime: a rising major arpeggio (C5-E5-G5) so a normal + // finish (scanning -> idle) is audibly a happy "done" rather than an alert. + beep(523,0.22,0.4); + setTimeout(()=>beep(659,0.22,0.4),240); + setTimeout(()=>beep(784,0.45,0.4),480); +}} function staleChime(){{ beep(1200,0.12,0.35); setTimeout(()=>beep(1200,0.12,0.35),180); @@ -2432,12 +2444,14 @@ function confirmWarning(){{ updateAudioUI(); }} -function startWarning(){{ +function startWarning(finished){{ // Not a gesture handler — context already unlocked by Enable button click. if(warningActive) return; warningActive=true; - if(audioEnabled) warningChime(); - warningTimer=setInterval(()=>{{ if(audioEnabled) warningChime(); }},30000); + warningWasSuccess=!!finished; // scanning -> idle == successful finish + const chime = warningWasSuccess ? successChime : warningChime; + if(audioEnabled) chime(); + warningTimer=setInterval(()=>{{ if(audioEnabled) chime(); }},30000); document.getElementById('btn-confirm').style.display='inline-block'; updateAudioUI(); }} @@ -2537,10 +2551,10 @@ function updateAudioUI(){{ txt.textContent='Audio disabled \u2014 enable to receive warnings'; }}else if(warningActive && staleActive){{ ledWatch.className='led led-warning'; - txt.textContent='Measurement stopped & live feed lost \u2014 confirm each'; + txt.textContent=(warningWasSuccess?'Measurement finished':'Measurement stopped')+' & live feed lost \u2014 confirm each'; }}else if(warningActive){{ ledWatch.className='led led-warning'; - txt.textContent='Measurement stopped \u2014 confirm to silence'; + txt.textContent=(warningWasSuccess?'Measurement finished':'Measurement stopped')+' \u2014 confirm to silence'; }}else if(staleActive){{ ledWatch.className='led'; txt.textContent='Live feed lost \u2014 confirm to silence'; @@ -2573,7 +2587,7 @@ function handleAudioForStatus(status, prevStatus){{ }} if(audioArmed && wasScanning && !isScanning){{ - startWarning(); + startWarning(status==='idle'); // idle == finished successfully -> success chime }} if(isScanning && warningActive){{