game_action_bar.dart 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import 'package:flutter/material.dart';
  2. import 'package:flutter_screenutil/flutter_screenutil.dart';
  3. import 'package:get/get.dart';
  4. import 'package:gobang/controllers/game_controller.dart';
  5. import 'package:gobang/themes/app_colors.dart';
  6. /// 悔棋 / 投降 / 重开
  7. class GameActionBar extends StatelessWidget {
  8. const GameActionBar({super.key});
  9. @override
  10. Widget build(BuildContext context) {
  11. final c = Get.find<GameController>();
  12. final isDark = c.themeFactory.value.getTheme().isDark;
  13. return Row(
  14. children: [
  15. Expanded(
  16. child: _ActionChip(
  17. label: '悔棋',
  18. icon: Icons.undo_rounded,
  19. foreground: isDark ? AppColors.ivory : AppColors.ink,
  20. background: isDark ? AppColors.darkCard : Colors.white,
  21. onTap: c.undo,
  22. ),
  23. ),
  24. SizedBox(width: 12.w),
  25. Expanded(
  26. child: _ActionChip(
  27. label: '投降',
  28. icon: Icons.flag_rounded,
  29. foreground: AppColors.pumpkin,
  30. background: isDark ? AppColors.darkCard : Colors.white,
  31. onTap: c.surrender,
  32. ),
  33. ),
  34. SizedBox(width: 12.w),
  35. Expanded(
  36. child: _ActionChip(
  37. label: '重开',
  38. icon: Icons.refresh_rounded,
  39. foreground: AppColors.ivory,
  40. background: AppColors.ink,
  41. onTap: c.restart,
  42. elevated: true,
  43. ),
  44. ),
  45. ],
  46. );
  47. }
  48. }
  49. class _ActionChip extends StatefulWidget {
  50. const _ActionChip({
  51. required this.label,
  52. required this.icon,
  53. required this.foreground,
  54. required this.background,
  55. required this.onTap,
  56. this.elevated = false,
  57. });
  58. final String label;
  59. final IconData icon;
  60. final Color foreground;
  61. final Color background;
  62. final VoidCallback onTap;
  63. final bool elevated;
  64. @override
  65. State<_ActionChip> createState() => _ActionChipState();
  66. }
  67. class _ActionChipState extends State<_ActionChip> {
  68. bool _pressed = false;
  69. @override
  70. Widget build(BuildContext context) {
  71. return GestureDetector(
  72. onTapDown: (_) => setState(() => _pressed = true),
  73. onTapUp: (_) => setState(() => _pressed = false),
  74. onTapCancel: () => setState(() => _pressed = false),
  75. onTap: widget.onTap,
  76. child: AnimatedScale(
  77. scale: _pressed ? 0.96 : 1,
  78. duration: const Duration(milliseconds: 120),
  79. child: Container(
  80. padding: EdgeInsets.symmetric(vertical: 14.h),
  81. decoration: BoxDecoration(
  82. color: widget.background,
  83. borderRadius: BorderRadius.circular(16.r),
  84. boxShadow: [
  85. BoxShadow(
  86. color: AppColors.ink.withValues(
  87. alpha: widget.elevated ? 0.28 : 0.12,
  88. ),
  89. blurRadius: 12,
  90. offset: const Offset(0, 4),
  91. ),
  92. ],
  93. ),
  94. child: Column(
  95. children: [
  96. Icon(widget.icon, color: widget.foreground, size: 24.sp),
  97. SizedBox(height: 4.h),
  98. Text(
  99. widget.label,
  100. style: TextStyle(
  101. color: widget.foreground,
  102. fontSize: 12.sp,
  103. fontWeight: FontWeight.w600,
  104. ),
  105. ),
  106. ],
  107. ),
  108. ),
  109. ),
  110. );
  111. }
  112. }