Files
holo_shiny/example/lib/main.dart
T
2026-04-15 00:51:17 +02:00

419 lines
12 KiB
Dart

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<ExampleHome> createState() => _ExampleHomeState();
}
class _ExampleHomeState extends State<ExampleHome> {
late final ShinyController _sensorController;
late final StreamController<Offset> _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<String, SparkleShapeSpec> _sparkleChoices =
<String, SparkleShapeSpec>{
'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<Offset>.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: <Widget>[
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: <Widget>[
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: <Widget>[
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>[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<double> onChanged;
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(label),
Slider(
value: value,
onChanged: onChanged,
),
],
);
}
}
class _StylePicker extends StatelessWidget {
const _StylePicker({
required this.selectedStyle,
required this.onChanged,
});
final HolographStyle selectedStyle;
final ValueChanged<HolographStyle> onChanged;
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
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<String, SparkleShapeSpec> choices;
final ValueChanged<SparkleShapeSpec> onChanged;
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
const Text('Sparkle Shape'),
const SizedBox(height: 6),
Wrap(
spacing: 8,
runSpacing: 8,
children:
choices.entries.map((MapEntry<String, SparkleShapeSpec> 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: <Widget>[
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>[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: <Color>[
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,
),
),
),
);
}
}