273 lines
8.4 KiB
Dart
273 lines
8.4 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
|
|
import '../service/app_sounds.dart';
|
|
import '../theme/app_theme.dart';
|
|
|
|
/// دکمهی بازگشتِ سراسری: قابِ طلایی هماهنگ با تمِ بازی. اگر [onTap] داده نشود،
|
|
/// بهصورت پیشفرض یک صفحه به عقب میرود (context.pop()).
|
|
class AppBackButton extends StatelessWidget {
|
|
final VoidCallback? onTap;
|
|
final double size;
|
|
const AppBackButton({super.key, this.onTap, this.size = 46});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return GestureDetector(
|
|
onTap: () {
|
|
AppSounds.button();
|
|
if (onTap != null) {
|
|
onTap!();
|
|
} else {
|
|
context.pop();
|
|
}
|
|
},
|
|
child: Container(
|
|
width: size,
|
|
height: size,
|
|
decoration: BoxDecoration(
|
|
color: AppColors.panel,
|
|
borderRadius: BorderRadius.circular(12),
|
|
border: Border.all(color: AppColors.gold, width: 1.5),
|
|
),
|
|
child: const Icon(Icons.arrow_back, color: AppColors.gold),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// مجموعهی ویجتهای گرافیکیِ مشترک برای ظاهرِ بازیِ (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: [AppColors.lapisMid, AppColors.bgDark],
|
|
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: [AppColors.goldFaint, 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: [AppColors.lapisMid, AppColors.bg],
|
|
),
|
|
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: [AppColors.lapisLo, AppColors.lapisNight],
|
|
),
|
|
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)),
|
|
]),
|
|
);
|
|
}
|
|
}
|