feat: phase 1 of improve

This commit is contained in:
2026-07-08 00:17:46 +03:30
parent 0bd2b4a18a
commit ffd2646eea
6 changed files with 461 additions and 135 deletions
@@ -0,0 +1,119 @@
import 'dart:math' as math;
import 'package:flutter/material.dart';
/// بارشِ کاغذرنگی (کانفتی) سبک و بدونِ وابستگی — برای صفحه‌ی بردِ بازی.
class Confetti extends StatefulWidget {
final int count;
const Confetti({super.key, this.count = 60});
@override
State<Confetti> createState() => _ConfettiState();
}
class _ConfettiState extends State<Confetti> with SingleTickerProviderStateMixin {
late final AnimationController _c;
late final List<_Piece> _pieces;
static const _colors = [
Color(0xFFE9B949), // طلایی
Color(0xFF1E5FA8), // لاجوردی
Color(0xFFB81D2A), // شنگرف
Color(0xFF3FA34D), // سبز
Color(0xFFFFFFFF),
];
@override
void initState() {
super.initState();
final r = math.Random();
_pieces = List.generate(widget.count, (_) {
return _Piece(
x: r.nextDouble(),
delay: r.nextDouble() * 0.5,
speed: 0.7 + r.nextDouble() * 0.6,
drift: (r.nextDouble() - 0.5) * 0.4,
size: 6 + r.nextDouble() * 7,
color: _colors[r.nextInt(_colors.length)],
rot: r.nextDouble() * math.pi,
rotSpeed: (r.nextDouble() - 0.5) * 12,
round: r.nextBool(),
);
});
_c = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 2600),
)..forward();
}
@override
void dispose() {
_c.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return IgnorePointer(
child: AnimatedBuilder(
animation: _c,
builder: (_, __) => CustomPaint(
size: Size.infinite,
painter: _ConfettiPainter(_pieces, _c.value),
),
),
);
}
}
class _Piece {
final double x, delay, speed, drift, size, rot, rotSpeed;
final Color color;
final bool round;
_Piece({
required this.x,
required this.delay,
required this.speed,
required this.drift,
required this.size,
required this.color,
required this.rot,
required this.rotSpeed,
required this.round,
});
}
class _ConfettiPainter extends CustomPainter {
final List<_Piece> pieces;
final double t; // ۰..۱
_ConfettiPainter(this.pieces, this.t);
@override
void paint(Canvas canvas, Size size) {
for (final p in pieces) {
final local = ((t - p.delay) * p.speed).clamp(0.0, 1.0);
if (local <= 0) continue;
final y = -0.1 + local * 1.25;
final x = (p.x + p.drift * local) * size.width;
final py = y * size.height;
final opacity = (1.0 - local).clamp(0.0, 1.0);
final paint = Paint()..color = p.color.withValues(alpha: opacity);
canvas.save();
canvas.translate(x, py);
canvas.rotate(p.rot + p.rotSpeed * local);
if (p.round) {
canvas.drawCircle(Offset.zero, p.size / 2, paint);
} else {
canvas.drawRect(
Rect.fromCenter(center: Offset.zero, width: p.size, height: p.size * 0.6),
paint,
);
}
canvas.restore();
}
}
@override
bool shouldRepaint(covariant _ConfettiPainter old) => old.t != t;
}