Skip to content

Instantly share code, notes, and snippets.

@chooyan-eng
Created October 19, 2025 14:51
Show Gist options
  • Select an option

  • Save chooyan-eng/8107da5f912516709a29b610bbe7c81b to your computer and use it in GitHub Desktop.

Select an option

Save chooyan-eng/8107da5f912516709a29b610bbe7c81b to your computer and use it in GitHub Desktop.
Flutter Alliance demo 3
import 'dart:async';
import 'dart:math';
import 'package:animated_to/animated_to.dart';
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(home: GraphDemoPage()));
class GraphDemoPage extends StatefulWidget {
const GraphDemoPage({super.key});
@override
State<GraphDemoPage> createState() => _GraphDemoPageState();
}
class _GraphDemoPageState extends State<GraphDemoPage> {
static const _items = 8;
final List<_Item> data = List.generate(
_items,
(index) => _Item(
key: GlobalObjectKey(index),
value: _items - index,
color: Colors.primaries[index % Colors.primaries.length],
),
);
Timer? _timer;
void _startSimulation() {
_timer = Timer.periodic(const Duration(milliseconds: 100), (timer) {
final target = Random().nextInt(_items);
final item = data.firstWhere((e) => e.key == GlobalObjectKey(target));
setState(() {
item.value += Random().nextInt(3) + 1;
data.sort((a, b) => b.value.compareTo(a.value));
});
});
}
void _stopSimulation() {
_timer?.cancel();
_timer = null;
}
int get _maxValue => data.map((e) => e.value).reduce((a, b) => max(a, b));
@override
Widget build(BuildContext context) {
return Theme(
data: ThemeData.dark().copyWith(
scaffoldBackgroundColor: const Color(0xFF1A1A2E),
appBarTheme: const AppBarTheme(
backgroundColor: Color(0xFF16213E),
elevation: 0,
),
),
child: Scaffold(
body: Stack(
children: [
// Grid background
CustomPaint(size: Size.infinite, painter: GridPainter()),
// Graph content
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 32,
vertical: 16,
),
child: Center(
child: SizedBox(
width: MediaQuery.of(context).size.width * 2 / 3,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Stats panel
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: const Color(0xFF0F3460).withAlpha(128),
borderRadius: BorderRadius.circular(16),
border: Border.all(
color: Colors.blue[400]!.withAlpha(128),
),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
_StatItem(
label: 'Max Value',
value: _maxValue.toString(),
icon: Icons.arrow_upward_rounded,
),
const SizedBox(width: 24),
_StatItem(
label: 'Items',
value: _items.toString(),
icon: Icons.bar_chart_rounded,
),
],
),
),
const SizedBox(height: 40),
// Graph
Expanded(
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
// Y-axis
Container(
width: 2,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.blue[400]!,
Colors.blue[400]!.withAlpha(128),
],
),
),
),
const SizedBox(width: 24),
// Bars
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
spacing: 10,
children: [
...data.map(
(e) => AnimatedTo.spring(
globalKey: e.key,
child: _Bar(
value: e.value,
maxValue: _maxValue,
color: e.color,
),
),
),
],
),
),
],
),
),
],
),
),
),
),
],
),
floatingActionButton: FloatingActionButton(
onPressed: () {
if (_timer != null) {
_stopSimulation();
} else {
_startSimulation();
}
},
child: Icon(
_timer != null ? Icons.stop_rounded : Icons.play_arrow_rounded,
color: Colors.white,
),
),
),
);
}
}
class _Bar extends StatelessWidget {
const _Bar({
required this.value,
required this.maxValue,
required this.color,
});
final int value;
final int maxValue;
final Color color;
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
final width = (constraints.maxWidth * value / maxValue).clamp(
0.0,
constraints.maxWidth,
);
return AnimatedContainer(
duration: const Duration(milliseconds: 100),
height: 30,
width: width,
decoration: BoxDecoration(
gradient: LinearGradient(colors: [color.withAlpha(200), color]),
borderRadius: BorderRadius.circular(8),
),
child: Center(
child: Text(
value.toString(),
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
),
);
},
);
}
}
class _StatItem extends StatelessWidget {
const _StatItem({
required this.label,
required this.value,
required this.icon,
});
final String label;
final String value;
final IconData icon;
@override
Widget build(BuildContext context) {
return Row(
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.blue[400]!.withAlpha(128),
borderRadius: BorderRadius.circular(8),
),
child: Icon(icon, color: Colors.blue[300], size: 20),
),
const SizedBox(width: 12),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: TextStyle(
color: Colors.blue[300],
fontSize: 12,
fontWeight: FontWeight.w500,
),
),
Text(
value,
style: const TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
],
),
],
);
}
}
class _Item {
_Item({required this.key, required this.value, required this.color});
final GlobalKey key;
int value;
final Color color;
}
class GridPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = Colors.blue[900]!.withAlpha(128)
..strokeWidth = 1;
const spacing = 30;
for (var i = 0; i < size.width; i += spacing) {
canvas.drawLine(
Offset(i.toDouble(), 0),
Offset(i.toDouble(), size.height),
paint,
);
}
for (var i = 0; i < size.height; i += spacing) {
canvas.drawLine(
Offset(0, i.toDouble()),
Offset(size.width, i.toDouble()),
paint,
);
}
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment