25ed765a03
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
160 lines
6.3 KiB
Dart
160 lines
6.3 KiB
Dart
// example_app.dart
|
|
// Pyramid Players · Showcase / Test-Harness
|
|
//
|
|
// Zeigt alle Player-Varianten in einem scrollbaren Dark-Layout.
|
|
// Drop-in-fähig: füge die drei Pyramid-Dateien (theme + audio + video)
|
|
// in dein Projekt und referenziere sie wie unten.
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'pyramid_theme.dart';
|
|
import 'pyramid_audio_player.dart';
|
|
import 'pyramid_video_player.dart';
|
|
|
|
void main() => runApp(const PyramidShowcaseApp());
|
|
|
|
class PyramidShowcaseApp extends StatelessWidget {
|
|
const PyramidShowcaseApp({super.key});
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return MaterialApp(
|
|
debugShowCheckedModeBanner: false,
|
|
title: 'Pyramid · Players',
|
|
theme: ThemeData(
|
|
scaffoldBackgroundColor: PyramidTheme.bg0,
|
|
fontFamily: PyramidTheme.fontSans,
|
|
useMaterial3: true,
|
|
),
|
|
home: const _Showcase(),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _Showcase extends StatefulWidget {
|
|
const _Showcase();
|
|
@override
|
|
State<_Showcase> createState() => _ShowcaseState();
|
|
}
|
|
|
|
class _ShowcaseState extends State<_Showcase> {
|
|
bool _playing = true;
|
|
Duration _audioPos = const Duration(minutes: 1, seconds: 11);
|
|
final _audioDur = const Duration(minutes: 3, seconds: 24);
|
|
Duration _videoPos = const Duration(minutes: 1, seconds: 28);
|
|
final _videoDur = const Duration(minutes: 4, seconds: 12);
|
|
|
|
void _toggle() => setState(() => _playing = !_playing);
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
body: SafeArea(
|
|
child: SingleChildScrollView(
|
|
padding: const EdgeInsets.fromLTRB(48, 48, 48, 120),
|
|
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
|
Text('PYRAMID · MEDIA PLAYERS',
|
|
style: TextStyle(fontFamily: PyramidTheme.fontMono, fontSize: 10, letterSpacing: 1.4, color: PyramidTheme.fgDim)),
|
|
const SizedBox(height: 6),
|
|
Text('Audio + Video — Flutter', style: TextStyle(color: PyramidTheme.fg, fontSize: 28, fontWeight: FontWeight.w500)),
|
|
const SizedBox(height: 40),
|
|
|
|
_section('AUDIO'),
|
|
_grid([
|
|
_frame('01 · Default', 'chunky bars',
|
|
PyramidAudioPlayer(
|
|
variant: AudioPlayerVariant.defaultBars,
|
|
title: 'test track', artist: 'pyramid · demo',
|
|
duration: _audioDur, position: _audioPos,
|
|
playing: _playing, onTogglePlay: _toggle,
|
|
onSeek: (p) => setState(() => _audioPos = p),
|
|
)),
|
|
_frame('02 · Gracile', 'hairline wave',
|
|
PyramidAudioPlayer(
|
|
variant: AudioPlayerVariant.gracile,
|
|
title: 'test track', artist: 'pyramid · demo',
|
|
duration: _audioDur, position: _audioPos,
|
|
playing: _playing, onTogglePlay: _toggle,
|
|
onSeek: (p) => setState(() => _audioPos = p),
|
|
)),
|
|
_frame('03 · Compact', 'in-chat',
|
|
PyramidAudioPlayer(
|
|
variant: AudioPlayerVariant.compact,
|
|
title: 'test track', artist: 'pyramid · demo',
|
|
duration: _audioDur, position: _audioPos,
|
|
playing: _playing, onTogglePlay: _toggle,
|
|
onSeek: (p) => setState(() => _audioPos = p),
|
|
)),
|
|
_frame('04 · Mono', 'terminal',
|
|
PyramidAudioPlayer(
|
|
variant: AudioPlayerVariant.mono,
|
|
title: 'test.wav', artist: 'pyramid · demo',
|
|
duration: _audioDur, position: _audioPos,
|
|
playing: _playing, onTogglePlay: _toggle,
|
|
onSeek: (p) => setState(() => _audioPos = p),
|
|
)),
|
|
]),
|
|
const SizedBox(height: 40),
|
|
|
|
_section('VIDEO'),
|
|
_grid([
|
|
_frame('01 · Default', 'hover-chrome',
|
|
PyramidVideoPlayer(
|
|
variant: VideoPlayerVariant.defaultHover,
|
|
title: 'test clip', subtitle: 'pyramid · 1080p',
|
|
duration: _videoDur, position: _videoPos, buffered: 0.65,
|
|
playing: _playing, onTogglePlay: _toggle,
|
|
onSeek: (p) => setState(() => _videoPos = p),
|
|
)),
|
|
_frame('02 · Minimal', 'always-visible',
|
|
PyramidVideoPlayer(
|
|
variant: VideoPlayerVariant.minimal,
|
|
title: 'test clip', subtitle: 'pyramid · 1080p',
|
|
duration: _videoDur, position: _videoPos, buffered: 0.65,
|
|
playing: _playing, onTogglePlay: _toggle,
|
|
onSeek: (p) => setState(() => _videoPos = p),
|
|
)),
|
|
_frame('03 · Framed', 'editorial',
|
|
PyramidVideoPlayer(
|
|
variant: VideoPlayerVariant.framed,
|
|
title: 'test clip', subtitle: 'pyramid · 1080p',
|
|
duration: _videoDur, position: _videoPos, buffered: 0.65,
|
|
playing: _playing, onTogglePlay: _toggle,
|
|
onSeek: (p) => setState(() => _videoPos = p),
|
|
)),
|
|
]),
|
|
]),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _section(String label) => Padding(
|
|
padding: const EdgeInsets.only(bottom: 20),
|
|
child: Container(
|
|
padding: const EdgeInsets.only(bottom: 8),
|
|
decoration: BoxDecoration(border: Border(bottom: BorderSide(color: PyramidTheme.border))),
|
|
child: Text(label,
|
|
style: TextStyle(fontFamily: PyramidTheme.fontMono, fontSize: 10, letterSpacing: 1.8, color: PyramidTheme.fgDim)),
|
|
),
|
|
);
|
|
|
|
Widget _frame(String label, String sub, Widget child) => Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Padding(
|
|
padding: const EdgeInsets.only(bottom: 14),
|
|
child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
|
|
Text(label, style: TextStyle(fontFamily: PyramidTheme.fontMono, fontSize: 10, letterSpacing: 1.4, color: PyramidTheme.fgMuted)),
|
|
Text(sub, style: TextStyle(fontFamily: PyramidTheme.fontMono, fontSize: 10, letterSpacing: 1.4, color: PyramidTheme.fgDim)),
|
|
]),
|
|
),
|
|
child,
|
|
],
|
|
);
|
|
|
|
Widget _grid(List<Widget> items) => Wrap(
|
|
spacing: 28, runSpacing: 28,
|
|
children: items.map((i) => SizedBox(width: 420, child: i)).toList(),
|
|
);
|
|
}
|