import 'dart:math'; import 'package:flutter/material.dart'; import 'package:puzzleweave/audio/jc_audio_controller.dart'; import 'package:puzzleweave/l10n/app_localizations.dart'; import 'package:puzzleweave/models/items.dart'; import 'package:puzzleweave/play/board_play.dart'; import 'package:puzzleweave/settings/settings_controller.dart'; import 'package:puzzleweave/skin/skin.dart'; import 'package:puzzleweave/utils/mybutton.dart'; import 'package:provider/provider.dart'; class SettingsDialog extends StatefulWidget { final ListItem? item; final bool showReturn; final bool showRestart; const SettingsDialog({super.key, required this.showReturn, required this.showRestart, required this.item}); @override State createState() => _SettingDialogState(); static PageRouteBuilder buildRoute({bool showReturn = false, bool showRestart = false, ListItem? item}) { return PageRouteBuilder( opaque: false, // 不遮盖原来的图层 pageBuilder: (context, animation, secondaryAnimation) { return SettingsDialog(showReturn: showReturn, showRestart: showRestart, item: item); }, transitionsBuilder: (context, animation, secondaryAnimation, child) { return FadeTransition(opacity: animation, child: child); }, ); } } class _SettingDialogState extends State { @override Widget build(BuildContext context) { final settings = context.watch(); final audio = context.read(); Widget gap = const SizedBox(height: 10); // 背景色(开启/关闭状态) const activeBgColor = Colors.white; const inactiveBgColor = Color.fromARGB(255, 205, 195, 195); // 图标颜色(固定,与背景形成对比) final iconColor = SkinHelper.slotBorderColor; return Scaffold( // backgroundColor: SkinHelper.coreBgColor, backgroundColor: Colors.black.withAlpha(128), body: Center( child: LayoutBuilder( builder: (context, constraints) { const double maxContainerWidth = 500; // 设定一个对话框最大宽度,避免在pad上显示过宽过大不好看 final containerWidth = min(constraints.biggest.shortestSide * 0.75, maxContainerWidth); final buttonWidth = containerWidth * 0.8; return Container( width: containerWidth, decoration: BoxDecoration(color: SkinHelper.coreBgColor, borderRadius: const BorderRadius.all(Radius.circular(16))), child: Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ // 标题栏(关闭按钮 + 标题) Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ IconButton( icon: const Icon(Icons.close_rounded, color: Colors.white), onPressed: () { audio.playSfx(SfxType.click); Navigator.pop(context); }, ), Text( AppLocalizations.of(context)!.setting, style: TextStyle(color: Colors.white, fontSize: 20, fontWeight: FontWeight.bold), ), const SizedBox(width: 48), // 占位,与左侧关闭按钮平衡 ], ), gap, gap, // 重新开始按钮 if (widget.showRestart) MyElevatedButton( onPressed: () { audio.playSfx(SfxType.click); PageRouteBuilder? pageRouteBuilder = BoardPlay.buildRoute(widget.item!); Navigator.pop(context); Navigator.pushReplacement(context, pageRouteBuilder); }, width: buttonWidth, borderRadius: BorderRadius.circular(20), gradient: const LinearGradient(colors: [Colors.white, Colors.white]), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.restart_alt_rounded, size: 24, weight: 600, color: SkinHelper.slotBorderColor), const SizedBox(width: 5), Text(AppLocalizations.of(context)!.restart, style: TextStyle(color: SkinHelper.slotBorderColor, fontSize: 18)), ], ), ), if (widget.showReturn) gap, if (widget.showReturn) gap, // 回到主页按钮 if (widget.showReturn) MyElevatedButton( onPressed: () { audio.playSfx(SfxType.click); Navigator.pop(context); Navigator.pop(context); }, width: buttonWidth, borderRadius: BorderRadius.circular(20), gradient: const LinearGradient(colors: [Colors.white, Colors.white]), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.arrow_back, size: 24, weight: 600, color: SkinHelper.slotBorderColor), const SizedBox(width: 5), Text(AppLocalizations.of(context)!.backToHome, style: TextStyle(color: SkinHelper.slotBorderColor, fontSize: 18)), ], ), ), gap, gap, gap, // 三个设置项(用ValueListenableBuilder监听状态变化) Padding( padding: const EdgeInsets.symmetric(horizontal: 20), child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ // 1. 背景音乐设置(监听music状态) ValueListenableBuilder( valueListenable: settings.music, // 监听music的变化 builder: (context, isMusicOn, child) { // 状态变化时,自动重建此按钮 return _buildSettingButton( icon: isMusicOn ? Icons.music_note : Icons.music_off, bgColor: isMusicOn ? activeBgColor : inactiveBgColor, iconColor: iconColor, onPressed: () { audio.playSfx(SfxType.click); settings.toggleMusic(); }, ); }, ), // 2. 音效设置(监听sound状态) ValueListenableBuilder( valueListenable: settings.sound, // 监听sound的变化 builder: (context, isSoundOn, child) { return _buildSettingButton( icon: isSoundOn ? Icons.volume_up : Icons.volume_off, bgColor: isSoundOn ? activeBgColor : inactiveBgColor, iconColor: iconColor, onPressed: () { audio.playSfx(SfxType.click); settings.toggleSound(); }, ); }, ), // 3. 震动设置(监听vibrate状态) ValueListenableBuilder( valueListenable: settings.vibrate, // 监听vibrate的变化 builder: (context, isVibrateOn, child) { return _buildSettingButton( icon: isVibrateOn ? Icons.vibration : Icons.crop_portrait, bgColor: isVibrateOn ? activeBgColor : inactiveBgColor, iconColor: iconColor, onPressed: () { audio.playSfx(SfxType.click); settings.toggleVibrate(); }, ); }, ), ], ), ), gap, gap, gap, ], ), ); }, ), ), ); } // 封装设置项按钮(无需额外key,由ValueListenableBuilder保证重绘) Widget _buildSettingButton({required IconData icon, required Color bgColor, required Color iconColor, required VoidCallback onPressed}) { return InkWell( // 圆形点击区域 borderRadius: BorderRadius.circular(30), onTap: onPressed, child: Container( width: 56, height: 56, decoration: BoxDecoration(color: bgColor, shape: BoxShape.circle), child: Icon(icon, size: 28, color: iconColor), ), ); } }