Files
Bernd Steckmeister 25ed765a03 wip: Sicherungs-Commit aller Änderungen seit April + Arbeitsstruktur (CLAUDE.md, ROADMAP.md, PROGRESS.md, Autopilot)
6 Wochen uncommittete Arbeit (Voice-Channels, LiveKit-Manager, Settings-Modal u.v.m.)
als ein WIP-Commit gesichert, damit nichts verloren geht und der Pi den aktuellen
Stand klonen kann. Thematische Aufarbeitung: siehe ROADMAP M0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CPrAGBxBT6GfPXzeWQ4AXb
2026-07-03 05:47:18 +02:00

137 lines
5.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Pyramid · Media Players (Flutter)
Player-Skelette im Pyramid-Stil — **Audio (4 Varianten)** und **Video (3 Varianten)** als wiederverwendbare Flutter-Widgets. Dies ist ein **UI-Gerüst ohne echte Medienwiedergabe**`position`, `duration`, `buffered`, `playing` sind reine Props. Zum Anschluss an echte Medien siehe „Mit echtem Playback verbinden" weiter unten.
---
## 📁 Dateien
```
flutter_export/
├── pubspec.yaml
└── lib/
├── pyramid_theme.dart ← Farb-, Typo-, Radius-Tokens (Single Source of Truth)
├── pyramid_audio_player.dart ← PyramidAudioPlayer + AudioPlayerVariant
├── pyramid_video_player.dart ← PyramidVideoPlayer + VideoPlayerVariant
└── example_app.dart ← Showcase mit allen Varianten (zum Reinkopieren)
```
Kopiere die drei `pyramid_*.dart` Dateien in dein Projekt (z. B. `lib/widgets/players/`) und importiere sie wie üblich.
---
## 🎨 Theme
Alle Player ziehen Farben/Typo aus `PyramidTheme`. Default ist **Dark + Amber**.
```dart
PyramidTheme.dark = true; // false → Light
PyramidTheme.setAccent(42, 95, 58); // HSL — Default Pyramid Amber
// Weitere Akzente: 280/70/60 (Violet), 160/65/50 (Mint), 0/75/60 (Coral)
```
**Fonts:** Theme erwartet `Geist` und `GeistMono`. Ohne Asset-Einbindung in `pubspec.yaml` fällt Flutter auf System-Sans/Mono zurück (immer noch ok). Die Font-Asset-Konfig ist in `pubspec.yaml` auskommentiert vorbereitet.
---
## 🎧 Audio Player
```dart
PyramidAudioPlayer(
variant: AudioPlayerVariant.gracile,
title: 'test track',
artist: 'pyramid · demo',
duration: const Duration(minutes: 3, seconds: 24),
position: _position, // ValueNotifier oder State
playing: _playing,
onTogglePlay: () => setState(() => _playing = !_playing),
onSeek: (Duration to) => setState(() => _position = to),
onSkipBack: () { /* 15s */ },
onSkipForward: () { /* +15s */ },
onSpeedChange: (double s) { /* 1.0 / 1.5 / 2.0 */ },
)
```
### Wann welche Variante?
| Variante | Wann benutzen | Größe |
|---|---|---|
| **`AudioPlayerVariant.defaultBars`** | Standard-Audio-Anhang in einer Nachricht. Robuste Bar-Waveform — wirkt „solide", für Musik-Snippets. | ≥ 380px breit |
| **`AudioPlayerVariant.gracile`** ⭐ | **Empfehlung für Voice-Notes und längere Audio-Dateien.** Filigrane Hairline-Waveform — passt am besten zum Pyramid-Stil. | ≥ 380px breit |
| **`AudioPlayerVariant.compact`** | **In-Chat Inline-Embed**, wenn Platz knapp ist (Reply-Quote, Thread-Vorschau, Side-Panel). Eine Zeile. | ≥ 320px breit |
| **`AudioPlayerVariant.mono`** | Spezielle Räume mit Terminal-/Editorial-Identität (z. B. `#announce`, „archive", Devs-Spaces). Mono-Font, harte Kanten. Sparsam einsetzen. | ≥ 380px breit |
---
## 🎬 Video Player
```dart
PyramidVideoPlayer(
variant: VideoPlayerVariant.defaultHover,
title: 'test clip',
subtitle: 'pyramid · 1080p',
duration: const Duration(minutes: 4, seconds: 12),
position: _videoPos,
buffered: 0.65, // 0..1
playing: _playing,
onTogglePlay: () => setState(() => _playing = !_playing),
onSeek: (Duration to) => setState(() => _videoPos = to),
onSpeedChange: (double s) { /* 0.5 / 1 / 1.25 / 1.5 / 2 */ },
onQualityChange: (String q) { /* Auto / 1080p / 720p / 480p / 360p */ },
onFullscreen: () { /* Navigator push fullscreen route */ },
)
```
### Wann welche Variante?
| Variante | Wann benutzen | Aspect | Chrome |
|---|---|---|---|
| **`VideoPlayerVariant.defaultHover`** ⭐ | **Standard-Video-Embed im Chat.** Player nimmt volle Breite ein, Controls erscheinen bei Hover/Tap. | 16:10 | hover/auto-hide |
| **`VideoPlayerVariant.minimal`** | **Inline-Vorschau** in dichten Layouts (Reply, Thread-Liste). Controls immer sichtbar, kompakter. | 16:9 | always-on |
| **`VideoPlayerVariant.framed`** | **Galerie-/Karten-Layouts** oder Posts mit Caption darunter. Stage in Card, Controls auf hellem Card-BG außerhalb des schwarzen Stages. | 16:9 + Card | always-on (Card) |
---
## 🔌 Mit echtem Playback verbinden
Diese Widgets sind reine UI-Mockups. Für echte Wiedergabe binde z. B. das offizielle [`video_player`](https://pub.dev/packages/video_player) (Video) oder [`just_audio`](https://pub.dev/packages/just_audio) (Audio) Package an:
```dart
// Video-Beispiel mit video_player
final controller = VideoPlayerController.networkUrl(Uri.parse(url))..initialize();
controller.addListener(() => setState(() {}));
// im build():
PyramidVideoPlayer(
variant: VideoPlayerVariant.defaultHover,
title: 'remote clip',
duration: controller.value.duration,
position: controller.value.position,
buffered: controller.value.buffered.isEmpty ? 0
: controller.value.buffered.last.end.inMilliseconds /
controller.value.duration.inMilliseconds,
playing: controller.value.isPlaying,
onTogglePlay: () => controller.value.isPlaying ? controller.pause() : controller.play(),
onSeek: (to) => controller.seekTo(to),
onSpeedChange: (s) => controller.setPlaybackSpeed(s),
)
```
**Stage rendern:** Aktuell zeigt der Player einen Pyramid-Triangle als Platzhalter. Ersetze in `pyramid_video_player.dart` die `_stage()`-Methode durch dein `VideoPlayer(controller)` Widget.
---
## 🧪 Showcase
`example_app.dart` zeigt alle 7 Player-Varianten in einem scrollbaren Dark-Layout. Direkt ausführbar via `flutter run -t lib/example_app.dart`.
---
## ✅ Checklist beim Einbau
- [ ] `pyramid_theme.dart` + Audio + Video kopiert
- [ ] `PyramidTheme.dark` und `setAccent(...)` in App-State gesetzt
- [ ] (optional) Geist + Geist Mono in `pubspec.yaml` eingebunden
- [ ] Player mit echtem Audio-/Video-Controller verdrahtet
- [ ] Skip-Intervall an Produkt-Konvention angepasst (Material hat `replay_10` / `forward_10` — wenn du wirklich ±15s willst, die Icons mit `Stack(text)` ersetzen)