Ein Kreisel ist kein Pausenknopf

Während der Player auf Daten wartete, stand im mittleren Knopf das
Abspieldreieck und der Ladekreis lag dahinter. Das las sich als
„angehalten": man drückte auf Abspielen, und es geschah nichts — es lief
ja bereits, es kam nur nichts an.

Jetzt sitzt der Kreisel **im** Knopf, dort wo sonst das Symbol steht. Der
freistehende Kreisel in der Bildmitte bleibt für den Fall, dass die
Bedienelemente ausgeblendet sind. Zwei übereinander gibt es nicht mehr.

`togglePlayPause` zählt das Warten jetzt zum Laufen. Vorher führte ein
Tipp in diesem Moment zu `play()` auf etwas, das schon spielte.

Dazu auf dem Mac, wie im Browser auch:

- Ein Klick ins Bild hält an, statt erst die Bedienelemente zu holen. Die
  kommen dort von allein, sobald sich der Zeiger regt.
- Leertaste hält an, Pfeil links und rechts springen.

Mit dem Finger bleibt es beim Alten: ohne Zeiger gibt es keine Bewegung
ohne Berührung, und ein Tipp, der sofort anhält, nähme den einzigen Weg
zu Scrubber, Tonspur und Qualität.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-09-15 20:33:24 +02:00
co-authored by Claude Opus 5
parent 3af6c3112f
commit 9a4b6b1e06
6 changed files with 245 additions and 39 deletions
+42 -10
View File
@@ -76,10 +76,16 @@ export function playerOeffnen(item: Item, beimSchliessen?: () => void): void {
/* ---------- Fehler sichtbar machen ---------- */
let hls: HlsTyp | null = null;
/** Ob gerade auf Daten gewartet wird — am Anfang immer. */
let wartet = true;
const scheitern = (satz: string, hinweis?: string, adresse?: string): void => {
ebene.classList.remove('loading');
el('pl-busy').classList.remove('on');
// Sonst dreht sich der Kreisel im Knopf hinter dem Fehlerkasten weiter,
// als käme noch etwas.
wartet = false;
malen();
ebene.querySelector('.pl-error')?.remove();
const kasten = document.createElement('div');
kasten.className = 'pl-error';
@@ -105,7 +111,21 @@ export function playerOeffnen(item: Item, beimSchliessen?: () => void): void {
clearTimeout(ausblenden);
// Solange etwas steht, bleibt die Bedienung: sie auszublenden, während
// niemand spielt, versteckt den einzigen Knopf, der weiterhilft.
if (!v.paused) ausblenden = setTimeout(() => chrome.classList.remove('on'), 3000);
if (!v.paused) {
ausblenden = setTimeout(() => {
chrome.classList.remove('on');
kreisel();
}, 3000);
}
kreisel();
};
/** Der freistehende Kreisel — nur, wenn die Bedienung aus ist.
*
* Sonst stünden zwei übereinander: einer in der Mitte des Bildes und einer
* im Abspielknopf, der genau davor sitzt. Genau so sah es vorher aus. */
const kreisel = (): void => {
el('pl-busy').classList.toggle('on', wartet && !chrome.classList.contains('on'));
};
ebene.addEventListener('mousemove', zeigen);
ebene.addEventListener('touchstart', zeigen, { passive: true });
@@ -117,16 +137,28 @@ export function playerOeffnen(item: Item, beimSchliessen?: () => void): void {
el('pl-fwd').onclick = () => { v.currentTime = Math.min(v.duration || 1e9, v.currentTime + P.skipForward); zeigen(); };
v.addEventListener('click', umschalten);
/** Zeichnet den mittleren Knopf: Kreisel, Dreieck oder Doppelbalken.
*
* Solange auf Daten gewartet wird, steht dort der Kreisel — **kein**
* Dreieck. Ein Dreieck heißt „angehalten, drück mich", und beides stimmte
* nicht: es lief bereits, und der Klick bewirkte nichts. */
const malen = (): void => {
el('pl-toggle').innerHTML = icon(v.paused ? 'play' : 'pause', 52);
el('pl-toggle').setAttribute('aria-label', v.paused ? 'Abspielen' : 'Anhalten');
zeigen();
const knopf = el('pl-toggle');
knopf.innerHTML = wartet ? '<i class="pl-wait"></i>' : icon(v.paused ? 'play' : 'pause', 52);
knopf.setAttribute('aria-label', wartet ? 'Lädt' : v.paused ? 'Abspielen' : 'Anhalten');
};
v.addEventListener('play', malen);
v.addEventListener('pause', malen);
v.addEventListener('waiting', () => el('pl-busy').classList.add('on'));
const warten = (an: boolean): void => {
wartet = an;
malen();
kreisel();
};
v.addEventListener('play', () => { malen(); zeigen(); });
v.addEventListener('pause', () => { warten(false); zeigen(); });
v.addEventListener('waiting', () => warten(true));
v.addEventListener('playing', () => {
el('pl-busy').classList.remove('on');
warten(false);
ebene.classList.remove('loading');
});
@@ -202,7 +234,7 @@ export function playerOeffnen(item: Item, beimSchliessen?: () => void): void {
lauf.stelle = v.currentTime || 0;
ebene.querySelector('.pl-error')?.remove();
ebene.classList.add('loading');
el('pl-busy').classList.add('on');
warten(true);
menueZu();
void strom();
};
@@ -411,7 +443,7 @@ export function playerOeffnen(item: Item, beimSchliessen?: () => void): void {
zeigen();
tonMalen();
ebene.classList.add('loading');
el('pl-busy').classList.add('on');
warten(true);
void strom();
}