240 lines
7.4 KiB
Dart
240 lines
7.4 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import '../service/app_sounds.dart';
|
|
import '../theme/app_theme.dart';
|
|
|
|
/// مجموعهی ویجتهای گرافیکیِ مشترک برای ظاهرِ بازیِ (Unity-style):
|
|
/// پسزمینهی گرادیانی، پنل براق، دکمهی جواهرگون، و عنوانِ درخشان.
|
|
|
|
/// پسزمینهی گرادیانیِ قرمز/طلایی با وینیت — زیربنای همهی صفحات.
|
|
class GameBackground extends StatelessWidget {
|
|
final Widget child;
|
|
final bool safeArea;
|
|
const GameBackground({super.key, required this.child, this.safeArea = true});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final content = safeArea ? SafeArea(child: child) : child;
|
|
return DecoratedBox(
|
|
decoration: const BoxDecoration(
|
|
gradient: RadialGradient(
|
|
center: Alignment(0, -0.4),
|
|
radius: 1.3,
|
|
colors: [Color(0xFF5A0F1E), Color(0xFF240108)],
|
|
stops: [0.0, 1.0],
|
|
),
|
|
),
|
|
child: Stack(
|
|
children: [
|
|
// درخششِ ملایمِ بالا برای حسِ عمق.
|
|
const Positioned.fill(
|
|
child: DecoratedBox(
|
|
decoration: BoxDecoration(
|
|
gradient: RadialGradient(
|
|
center: Alignment(0, -1.1),
|
|
radius: 1.0,
|
|
colors: [Color(0x33E9B949), Color(0x00000000)],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
content,
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// پنلِ براقِ طلاییحاشیه با گرادیان و سایه.
|
|
class GamePanel extends StatelessWidget {
|
|
final Widget child;
|
|
final EdgeInsetsGeometry padding;
|
|
final double radius;
|
|
const GamePanel({
|
|
super.key,
|
|
required this.child,
|
|
this.padding = const EdgeInsets.all(16),
|
|
this.radius = 18,
|
|
});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Container(
|
|
padding: padding,
|
|
decoration: BoxDecoration(
|
|
gradient: const LinearGradient(
|
|
begin: Alignment.topCenter,
|
|
end: Alignment.bottomCenter,
|
|
colors: [Color(0xFF6E1322), Color(0xFF3A0A12)],
|
|
),
|
|
borderRadius: BorderRadius.circular(radius),
|
|
border: Border.all(color: AppColors.gold, width: 2),
|
|
boxShadow: const [
|
|
BoxShadow(color: Colors.black54, blurRadius: 14, offset: Offset(0, 6)),
|
|
BoxShadow(color: Color(0x22E9B949), blurRadius: 2, spreadRadius: 1),
|
|
],
|
|
),
|
|
child: child,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// دکمهی جواهرگون با گرادیان، بِوِل، سایه و انیمیشنِ فشار.
|
|
class GameButton extends StatefulWidget {
|
|
final String label;
|
|
final IconData? icon;
|
|
final VoidCallback? onTap;
|
|
final List<Color> colors; // گرادیان (روشن بالا → تیره پایین)
|
|
final double height;
|
|
final double? width;
|
|
|
|
const GameButton({
|
|
super.key,
|
|
required this.label,
|
|
this.icon,
|
|
this.onTap,
|
|
this.colors = const [Color(0xFFD83A4A), Color(0xFF8E0E1B)],
|
|
this.height = 56,
|
|
this.width,
|
|
});
|
|
|
|
@override
|
|
State<GameButton> createState() => _GameButtonState();
|
|
}
|
|
|
|
class _GameButtonState extends State<GameButton> {
|
|
bool _down = false;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final enabled = widget.onTap != null;
|
|
return GestureDetector(
|
|
onTapDown: enabled ? (_) => setState(() => _down = true) : null,
|
|
onTapUp: enabled ? (_) => setState(() => _down = false) : null,
|
|
onTapCancel: enabled ? () => setState(() => _down = false) : null,
|
|
onTap: enabled
|
|
? () {
|
|
AppSounds.button();
|
|
widget.onTap!();
|
|
}
|
|
: null,
|
|
child: AnimatedScale(
|
|
scale: _down ? 0.96 : 1.0,
|
|
duration: const Duration(milliseconds: 90),
|
|
child: Opacity(
|
|
opacity: enabled ? 1 : 0.5,
|
|
child: Container(
|
|
width: widget.width,
|
|
height: widget.height,
|
|
alignment: Alignment.center,
|
|
decoration: BoxDecoration(
|
|
gradient: LinearGradient(
|
|
begin: Alignment.topCenter,
|
|
end: Alignment.bottomCenter,
|
|
colors: widget.colors,
|
|
),
|
|
borderRadius: BorderRadius.circular(16),
|
|
border: Border.all(color: AppColors.gold, width: 1.6),
|
|
boxShadow: _down
|
|
? const []
|
|
: const [
|
|
BoxShadow(
|
|
color: Colors.black54,
|
|
blurRadius: 8,
|
|
offset: Offset(0, 5)),
|
|
],
|
|
),
|
|
foregroundDecoration: BoxDecoration(
|
|
borderRadius: BorderRadius.circular(16),
|
|
// هایلایتِ بالا برای حسِ شیشهای/بِوِل.
|
|
gradient: const LinearGradient(
|
|
begin: Alignment.topCenter,
|
|
end: Alignment.center,
|
|
colors: [Color(0x40FFFFFF), Color(0x00FFFFFF)],
|
|
),
|
|
),
|
|
child: Row(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
if (widget.icon != null) ...[
|
|
Icon(widget.icon, color: AppColors.gold, size: 22),
|
|
const SizedBox(width: 10),
|
|
],
|
|
Text(
|
|
widget.label,
|
|
style: const TextStyle(
|
|
color: Colors.white,
|
|
fontSize: 18,
|
|
fontWeight: FontWeight.bold,
|
|
shadows: [Shadow(color: Colors.black54, blurRadius: 3)],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// عنوانِ درخشان (هالهی طلایی).
|
|
class GlowText extends StatelessWidget {
|
|
final String text;
|
|
final double size;
|
|
const GlowText(this.text, {super.key, this.size = 34});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Text(
|
|
text,
|
|
textAlign: TextAlign.center,
|
|
style: TextStyle(
|
|
fontFamily: 'Dana',
|
|
fontSize: size,
|
|
fontWeight: FontWeight.bold,
|
|
color: AppColors.gold,
|
|
shadows: const [
|
|
Shadow(color: Color(0xCCE9B949), blurRadius: 18),
|
|
Shadow(color: Color(0x88E9B949), blurRadius: 36),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// چیپِ آماری براق (سکه/بلیط) با آیکن و مقدار.
|
|
class StatChip extends StatelessWidget {
|
|
final IconData icon;
|
|
final String value;
|
|
final Color iconColor;
|
|
const StatChip({
|
|
super.key,
|
|
required this.icon,
|
|
required this.value,
|
|
this.iconColor = AppColors.gold,
|
|
});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
|
decoration: BoxDecoration(
|
|
gradient: const LinearGradient(
|
|
begin: Alignment.topCenter,
|
|
end: Alignment.bottomCenter,
|
|
colors: [Color(0xFF2A0610), Color(0xFF14040A)],
|
|
),
|
|
borderRadius: BorderRadius.circular(20),
|
|
border: Border.all(color: AppColors.goldDark),
|
|
boxShadow: const [BoxShadow(color: Colors.black54, blurRadius: 4)],
|
|
),
|
|
child: Row(mainAxisSize: MainAxisSize.min, children: [
|
|
Icon(icon, color: iconColor, size: 18),
|
|
const SizedBox(width: 6),
|
|
Text(value, style: const TextStyle(color: AppColors.text, fontWeight: FontWeight.bold)),
|
|
]),
|
|
);
|
|
}
|
|
}
|