import 'dart:async'; import 'package:flutter/material.dart'; import 'package:holo_shiny/holo_shiny.dart'; void main() { runApp(const ExampleApp()); } class ExampleApp extends StatelessWidget { const ExampleApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xFF24A6A8)), ), home: const ExampleHome(), ); } } class ExampleHome extends StatefulWidget { const ExampleHome({super.key}); @override State createState() => _ExampleHomeState(); } class _ExampleHomeState extends State { late final ShinyController _sensorController; late final StreamController _externalTiltController; late final ShinyController _overrideController; double _prismatic = 0.8; double _sparkle = 0.8; double _specular = 0.8; double _diffraction = 0.8; HolographStyle _style = HolographStyle.crackedIce; SparkleShapeSpec _sparkleShape = SparkleShapeSpec.eightPointStar; static const Map _sparkleChoices = { '8-Point Star': SparkleShapeSpec.eightPointStar, '5-Point Star': SparkleShapeSpec.fivePointStar, 'Rectangle': SparkleShapeSpec.rectangle, 'Diamond': SparkleShapeSpec.diamond, 'Hexagon': SparkleShapeSpec.hexagon, 'Random Polygon': SparkleShapeSpec.randomPolygon, 'Confetti': SparkleShapeSpec.confetti, }; @override void initState() { super.initState(); _sensorController = ShinyController(useSensor: true); _externalTiltController = StreamController.broadcast(); _overrideController = ShinyController(tiltStream: _externalTiltController.stream); } @override void dispose() { _sensorController.dispose(); _overrideController.dispose(); _externalTiltController.close(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFF0D121A), appBar: AppBar( title: const Text('holo_shiny example'), ), body: SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const Text('Shiny on Any Widget'), const SizedBox(height: 8), Center( child: SizedBox( width: 320, height: 120, child: Shiny( controller: _sensorController, style: _style, sparkleShape: _sparkleShape, child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: const Color(0xFF18263E), borderRadius: BorderRadius.circular(14), ), child: const Row( children: [ Icon(Icons.auto_awesome, color: Colors.white), SizedBox(width: 12), Expanded( child: Text( 'This can wrap any widget, including app chrome.', style: TextStyle(color: Colors.white), ), ), ], ), ), ), ), ), const SizedBox(height: 24), const Text('ShinyCard (shape + rotation + shine)'), const SizedBox(height: 8), Center( child: ShinyCard( controller: _sensorController, style: _style, sparkleShape: _sparkleShape, background: const _DemoCardBackground(), foreground: const _RareBadge(), prismatic: _prismatic, sparkle: _sparkle, specular: _specular, diffraction: _diffraction, ), ), const SizedBox(height: 16), _StylePicker( selectedStyle: _style, onChanged: (HolographStyle style) { setState(() { _style = style; }); }, ), const SizedBox(height: 8), _SparkleShapePicker( selectedShape: _sparkleShape, choices: _sparkleChoices, onChanged: (SparkleShapeSpec shape) { setState(() { _sparkleShape = shape; }); }, ), const SizedBox(height: 8), _LabeledSlider('Prismatic', _prismatic, (double value) { setState(() { _prismatic = value; }); }), _LabeledSlider('Sparkle', _sparkle, (double value) { setState(() { _sparkle = value; }); }), _LabeledSlider('Specular', _specular, (double value) { setState(() { _specular = value; }); }), _LabeledSlider('Diffraction', _diffraction, (double value) { setState(() { _diffraction = value; }); }), const SizedBox(height: 24), const Text('External Tilt Stream + Custom Shape (card)'), const SizedBox(height: 8), Row( children: [ Expanded( child: ElevatedButton( onPressed: () => _externalTiltController.add(const Offset(0.7, 0.0)), child: const Text('Tilt Right'), ), ), const SizedBox(width: 8), Expanded( child: ElevatedButton( onPressed: () => _externalTiltController.add(const Offset(-0.7, 0.0)), child: const Text('Tilt Left'), ), ), ], ), const SizedBox(height: 8), Center( child: ShinyCard( controller: _overrideController, style: _style, sparkleShape: _sparkleShape, shape: const StadiumBorder(), background: Container( decoration: const BoxDecoration( gradient: LinearGradient( colors: [Color(0xFF1A2A44), Color(0xFF15263D)], ), ), ), foreground: const Center( child: Text( 'EXTERNAL STREAM', style: TextStyle( color: Colors.white, fontWeight: FontWeight.w900, letterSpacing: 1.2, ), ), ), ), ), ], ), ), ); } } class _LabeledSlider extends StatelessWidget { const _LabeledSlider(this.label, this.value, this.onChanged); final String label; final double value; final ValueChanged onChanged; @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(label), Slider( value: value, onChanged: onChanged, ), ], ); } } class _StylePicker extends StatelessWidget { const _StylePicker({ required this.selectedStyle, required this.onChanged, }); final HolographStyle selectedStyle; final ValueChanged onChanged; @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('Style'), const SizedBox(height: 6), Wrap( spacing: 8, runSpacing: 8, children: HolographStyle.values.map((HolographStyle style) { return ChoiceChip( label: Text(_styleLabel(style)), selected: selectedStyle == style, onSelected: (bool selected) { if (!selected) { return; } onChanged(style); }, ); }).toList(), ), ], ); } String _styleLabel(HolographStyle style) { switch (style) { case HolographStyle.holographicSilver: return 'Holographic Silver'; case HolographStyle.crackedIce: return 'Cracked Ice'; case HolographStyle.silverMosaic: return 'Silver Mosaic'; case HolographStyle.superGoldVinyl: return 'Super Gold Vinyl'; } } } class _SparkleShapePicker extends StatelessWidget { const _SparkleShapePicker({ required this.selectedShape, required this.choices, required this.onChanged, }); final SparkleShapeSpec selectedShape; final Map choices; final ValueChanged onChanged; @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('Sparkle Shape'), const SizedBox(height: 6), Wrap( spacing: 8, runSpacing: 8, children: choices.entries.map((MapEntry entry) { return ChoiceChip( label: Text(entry.key), selected: selectedShape == entry.value, onSelected: (bool selected) { if (!selected) { return; } onChanged(entry.value); }, ); }).toList(), ), ], ); } } class _DemoCardBackground extends StatelessWidget { const _DemoCardBackground(); @override Widget build(BuildContext context) { return Stack( fit: StackFit.expand, children: [ Image.asset( 'assets/pokemon.png', fit: BoxFit.cover, alignment: Alignment.topCenter, errorBuilder: (BuildContext context, Object error, StackTrace? stackTrace) { return Container( decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [Color(0xFF2D1B1B), Color(0xFF120D18)], ), ), padding: const EdgeInsets.all(16), child: const Align( alignment: Alignment.bottomLeft, child: Text( 'Demo Card', style: TextStyle( color: Colors.white, fontSize: 22, fontWeight: FontWeight.w900, ), ), ), ); }, ), DecoratedBox( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Colors.black.withValues(alpha: 0.10), Colors.black.withValues(alpha: 0.22), ], ), ), ), ], ); } } class _RareBadge extends StatelessWidget { const _RareBadge(); @override Widget build(BuildContext context) { return Align( alignment: Alignment.topRight, child: Container( margin: const EdgeInsets.all(12), padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), decoration: BoxDecoration( color: Colors.white.withValues(alpha: 0.2), borderRadius: BorderRadius.circular(99), ), child: const Text( 'RARE', style: TextStyle( color: Colors.white, fontWeight: FontWeight.w800, letterSpacing: 1, ), ), ), ); } }