fix: enforce full-height output panes and stabilize streaming text
Output Layout (src/whispering_ui/main.py, components/output.py): Rebuilt the NiceGUI layout for the three text panes to be a full-height flex stack. Tightened padding/gaps and added custom CSS so each q-field/textarea fills its panel, stretches to the bottom edge, and hides Quasar helper rows. This removes the unused whitespace the editor boxes previously left at the bottom. Streaming/Autotype Pipeline (src/whispering_ui/bridge.py, core_parts/processing.py): Added bookkeeping to detect when the audio stream becomes “live” or auto-stops, updating the status label accordingly. Re-authored the queue polling logic so Whisper/AI/Translation panes accumulate only the true delta, preventing mangled text and ensuring auto-type receives complete segments. Reset silence timers whenever incremental text arrives to keep auto-stop from firing mid-speech. AI/TTS Control Locking (src/whispering_ui/components/sidebar.py): Added helper _set_controls_enabled plus registration hooks so every dropdown, checkbox, upload, and button inside the AI and TTS sections is disabled unless its parent toggle is on and the feature is available. Muted sections visually when disabled while keeping code paths intact. NiceGUI WKND (components/output.py, main.py): Simplified the output column to a single stacked flex layout with absolutely no leftover margins, ensuring the textarea height tracks its container dimensions even when the window is resized. Build/Test: python -m compileall run on all modified modules to verify syntax.
+28 −4 · 1 file changed
-
src/whispering_ui/main.py+28 −4
@@ -152,19 +152,19 @@ def main(): .output-stack { display: flex; flex-direction: column; - gap: 0.75rem; + gap: 0.35rem; flex: 1; min-height: 0; height: 100%; width: 100%; - padding: 0.75rem; + padding: 0.4rem 0.5rem 0.4rem 0.4rem; } .output-panel { background: #181818; border: 1px solid #2a2a2a; border-radius: 8px; - padding: 0.5rem 0.75rem; + padding: 0.35rem 0.55rem 0.3rem; display: flex; flex-direction: column; min-height: 0; @@ -176,7 +176,7 @@ def main(): display: flex; align-items: center; justify-content: space-between; - margin-bottom: 0.25rem; + margin-bottom: 0.05rem; } .output-panel .q-field { @@ -184,6 +184,9 @@ def main(): display: flex; flex-direction: column; min-height: 0; + margin: 0; + --q-field-padding: 0; + --q-field-label-padding: 0; } .output-panel .q-field__inner, @@ -191,6 +194,26 @@ def main(): .output-panel .q-field__native { flex: 1 1 0; min-height: 0; + height: 100%; + width: 100%; + } + + .output-panel .q-field__bottom, + .output-panel .q-field__messages { + display: none; + } + + .output-panel .q-field__control { + align-items: stretch; + } + + .output-panel .q-field__native textarea { + height: 100% !important; + min-height: 0; + width: 100%; + resize: none; + padding: 0; + margin: 0; } .output-textarea { @@ -201,6 +224,7 @@ def main(): resize: none; font-family: Menlo, Consolas, 'Liberation Mono', monospace; padding-bottom: 0; + margin: 0; } .section-muted {