Platzhalter statt Ratespiel, und zwei Griffe im Player

**Das Raster sagt jetzt, ob noch etwas kommt.** Eine Mediathek lädt
seitenweise nach, und wer unten ankam, sah ein Raster, das aufhört — ohne
unterscheiden zu können, ob das alles war oder gerade nachgeladen wird.
Beides sah gleich aus.

Beide Server nennen die Gesamtzahl (Jellyfin `TotalRecordCount`, Plex
`totalSize`), und wir lesen sie längst. Also stehen die nächsten Kacheln
schon da, in der Form, die sie haben werden — gedeckelt auf ein Dutzend,
weil zweihundert Platzhalter niemandem helfen. Ist wirklich alles da,
steht es am Ende ausdrücklich: „Alle 252 Titel geladen".

Gegen die Attrappe mit 252 Titeln durchgeblättert und nachgesehen: die
Zeile steht da, und alle 252 sind angekommen.

**Herein sanft, hinaus zügig.** Das Einblenden der Bedienung begleitet
eine Bewegung des Zeigers und soll wirken, als käme sie der Hand
entgegen; zwei Zehntel wirkten wie ein Aufblitzen. Das Ausblenden
dagegen ist ein Aufräumen, und dabei muss niemand zusehen.

**Ein Klick ins Schwarze blendet um, statt anzuhalten.** Ein Film füllt
das Fenster fast nie ganz aus — die Balken daneben gehören nicht zum
Film, und dort zu klicken ist die natürliche Geste für „zeig mir die
Bedienung". Wo das Bild aufhört, wird aus `presentationSize` gerechnet,
also aus dem, was wirklich ankommt. Fehlen die Maße, verhält es sich wie
bisher.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-09-27 18:50:26 +02:00
co-authored by Claude Opus 5
parent 279d8e36ae
commit 10caa5fdd1
4 changed files with 190 additions and 5 deletions
@@ -0,0 +1,61 @@
import SwiftUI
/// Eine Kachel, die es gleich geben wird.
///
/// **Warum es das gibt.** Eine Mediathek lädt seitenweise nach. Wer unten
/// ankommt, sieht ein Raster, das aufhört — und kann nicht unterscheiden, ob
/// das alles war oder ob gerade nachgeladen wird. Beides sieht gleich aus, und
/// im Zweifel hält man eine halb geladene Liste für vollständig.
///
/// Diese Kacheln sagen: hier kommt noch etwas. Sie werden nur so oft gezeigt,
/// wie der Server tatsächlich noch Titel gemeldet hat — es ist also keine
/// Beschwichtigung, sondern eine Auskunft.
///
/// Ein Ladekreis täte das nicht: er sagt „es passiert etwas", aber nicht
/// **wo** und nicht **wie viel**. Die Form der Kachel an der Stelle, an der
/// sie erscheinen wird, sagt beides.
public struct PlaceholderCard: View {
/// Womit das Aufleuchten versetzt wird.
///
/// Alle gleichzeitig pulsieren zu lassen sieht nach einem Fehler aus —
/// als blinkte die ganze Seite. Ein Versatz je Kachel macht daraus eine
/// Bewegung, die von links nach rechts läuft.
let index: Int
@State private var isBright = false
@Environment(\.accessibilityReduceMotion) private var reduceMotion
public init(index: Int = 0) {
self.index = index
}
public var body: some View {
VStack(alignment: .leading, spacing: FlixySpacing.snug) {
RoundedRectangle(cornerRadius: FlixyRadius.card)
.fill(Color.flixyElevated)
.aspectRatio(PosterCard.aspectRatio, contentMode: .fit)
// Zwei Balken an der Stelle von Titel und Jahr. Ohne sie springt
// die Zeile, sobald der echte Titel kommt.
RoundedRectangle(cornerRadius: 3)
.fill(Color.flixyElevated)
.frame(height: 10)
RoundedRectangle(cornerRadius: 3)
.fill(Color.flixyElevated)
.frame(width: 32, height: 8)
}
.opacity(isBright ? 0.85 : 0.45)
.animation(
reduceMotion
? nil
: .easeInOut(duration: 0.9)
.repeatForever(autoreverses: true)
.delay(Double(index % 6) * 0.1),
value: isBright
)
.onAppear { isBright = true }
// Für die Sprachausgabe ist eine Kachel ohne Inhalt nichts, worüber
// man wischen möchte.
.accessibilityHidden(true)
}
}