Volle Höhe, eine Kante statt eines Streifens

Der Aufmacher nimmt jetzt achtundachtzig Prozent der sichtbaren Höhe, statt
sich seine Höhe aus 16:9 auszurechnen. Ein Aufmacher, der ein Drittel hoch ist,
sieht aus wie ein breites Vorschaubild; die zwölf Prozent Rest sind Absicht,
dort lugt die erste Reihe herein und sagt, dass es weitergeht. Auf schmalen
Geräten bleibt es beim Hochformat.

`FlixyArtwork` kann dafür den Rahmen ausfüllen, den es bekommt. Das
Seitenverhältnis bleibt trotzdem wichtig — danach werden die Bilder beim Server
angefordert.

Und `glassEffect` ist raus. Er zeichnet an seiner Kante einen Lichtsaum, und
über einem hellen Aufmacher wurde daraus ein heller Balken von mehreren Punkten
Breite neben der Leiste — kein Rand, sondern ein Streifen. Von einer Kante war
gleichzeitig nichts zu erkennen.

Von Hand sind es drei Lagen: ein trübes Material, ein Schleier gegen die
durchziehende Startseite, und ein Haarstrich, der oben links aufhellt und unten
rechts nachlässt. Dazu ein Schatten — was schwebt, wirft einen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-09-13 20:12:42 +02:00
co-authored by Claude Opus 5
parent d0f732402c
commit 873b8a4405
5 changed files with 98 additions and 22 deletions
@@ -10,6 +10,13 @@ import SwiftUI
public struct FlixyArtwork: View {
private let url: URL?
private let aspectRatio: CGFloat
/// Ob das Bild den Rahmen einnimmt, den es bekommt, statt sich seine Höhe
/// aus dem Seitenverhältnis auszurechnen.
///
/// Für den Aufmacher: der soll so hoch sein wie das Fenster und nicht so
/// hoch, wie 16:9 es vorgibt. Das Seitenverhältnis bleibt trotzdem
/// wichtig — danach werden die Bilder beim Server angefordert.
private let fillsFrame: Bool
private let fallbackSymbol: String
private let contentMode: ContentMode
@@ -22,11 +29,13 @@ public struct FlixyArtwork: View {
public init(
url: URL?,
aspectRatio: CGFloat,
fillsFrame: Bool = false,
fallbackSymbol: String = "film",
contentMode: ContentMode = .fill
) {
self.url = url
self.aspectRatio = aspectRatio
self.fillsFrame = fillsFrame
self.fallbackSymbol = fallbackSymbol
self.contentMode = contentMode
}
@@ -35,9 +44,7 @@ public struct FlixyArtwork: View {
@State private var hasFailed = false
public var body: some View {
Rectangle()
.fill(Color.flixyPlaceholder)
.aspectRatio(aspectRatio, contentMode: .fit)
placeholder
.overlay {
content
}
@@ -45,6 +52,15 @@ public struct FlixyArtwork: View {
.task(id: url) { await load() }
}
@ViewBuilder
private var placeholder: some View {
if fillsFrame {
Rectangle().fill(Color.flixyPlaceholder)
} else {
Rectangle().fill(Color.flixyPlaceholder).aspectRatio(aspectRatio, contentMode: .fit)
}
}
/// Das Bild, das jetzt gezeigt werden kann.
///
/// Der Blick in den Speicher steht **hier**, nicht in `load()`: eine
@@ -15,6 +15,8 @@ public struct HeroBanner<Actions: View>: View {
/// eigenen Schrift ist wiedererkennbar, eine Systemschrift nicht.
private let logoURL: URL?
private let aspectRatio: CGFloat
/// Ob der Aufmacher den Platz einnimmt, den er bekommt.
private let fillsAvailableSpace: Bool
private let actions: Actions
@State private var logo: PlatformImage?
@@ -38,6 +40,7 @@ public struct HeroBanner<Actions: View>: View {
// kräftig beschnitten, und vom Aufmacher war nur ein Ausschnitt zu
// sehen.
aspectRatio: CGFloat = FlixyAspectRatio.hero,
fillsAvailableSpace: Bool = false,
@ViewBuilder actions: () -> Actions
) {
self.title = title
@@ -46,6 +49,7 @@ public struct HeroBanner<Actions: View>: View {
self.artworkURL = artworkURL
self.logoURL = logoURL
self.aspectRatio = aspectRatio
self.fillsAvailableSpace = fillsAvailableSpace
self.actions = actions()
}
@@ -121,7 +125,7 @@ public struct HeroBanner<Actions: View>: View {
}
public var body: some View {
FlixyArtwork(url: artworkURL, aspectRatio: aspectRatio)
FlixyArtwork(url: artworkURL, aspectRatio: aspectRatio, fillsFrame: fillsAvailableSpace)
// Bis unter die Leiste und an den Fensterrand.
//
// Hier stand `backgroundExtensionEffect()`. Der spiegelt den