import 'package:flutter/material.dart'; import 'package:flutter_common/widget/common_widget.dart'; import 'package:food_hub_app/apis/recipe.dart'; import 'package:food_hub_app/models/recipe.dart'; import 'package:food_hub_app/provider/food_provider.dart'; import 'package:food_hub_app/utils/screenshot_util.dart'; import 'package:food_hub_app/views/recipe_form.dart'; import 'package:food_hub_app/widgets/common/index.dart'; import 'package:provider/provider.dart'; class RecipeDetailPage extends StatefulWidget { const RecipeDetailPage({super.key}); @override State createState() => _RecipeDetailState(); } class _RecipeDetailState extends State { Recipe recipe = Recipe.getEmpty(); final GlobalKey _recipeDetailKey = GlobalKey(); bool _isSharing = false; List materialList = []; @override void didChangeDependencies() { super.didChangeDependencies(); refreshRecipeDetail(); } Future refreshRecipeDetail() async { // 获取参数 final args = ModalRoute.of(context)?.settings.arguments as Map; final result = await queryRecipeByIdApi(args['id']); setState(() { recipe = result; getRecipeMaterial(); }); } void getRecipeMaterial() { materialList.clear(); for (var material in recipe.materialList) { materialList.add(material); } } void _handleEditRecipe(FoodProvider provider) { provider.initRecipeForm(recipe); provider.isEditing = true; showModalBottomSheet( context: context, constraints: BoxConstraints(minHeight: 600), backgroundColor: Theme.of(context).scaffoldBackgroundColor, isScrollControlled: true, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(16)), ), builder: (context) => RecipeForm(), ); } // 分享图片 Future _shareRecipeAsImage() async { if (_isSharing) return; setState(() { _isSharing = true; }); final timestamp = DateTime.now().millisecondsSinceEpoch; final imageName = '${recipe.name}_$timestamp.png'; await ScreenshotUtil.captureAndShare( globalKey: _recipeDetailKey, fileName: imageName, shareText: '分享菜谱: ${recipe.name}', ); setState(() { _isSharing = false; }); } @override Widget build(BuildContext context) { final colors = Theme.of(context).colorScheme; final provider = context.watch(); return Scaffold( appBar: AppBar( title: Text('菜谱信息', style: Theme.of(context).textTheme.titleLarge), backgroundColor: Theme.of(context).scaffoldBackgroundColor, leading: IconButton( icon: Icon(Icons.arrow_back, color: colors.primary), onPressed: () => Navigator.pop(context), ), ), body: SingleChildScrollView( child: Column( children: [ // 用RepaintBoundary包裹要截图的部分 RepaintBoundary( key: _recipeDetailKey, child: Padding( padding: EdgeInsets.all(10), child: _buildRecipeDetail(), ), ), _buildButtons(provider), ], ), ), ); } Widget _buildRecipeDetail() { return Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ _buildTitleSection(), SizedBox(height: 8), _buildInfoCard( context, icon: Icons.info, title: "基础信息", content: Text(recipe.category), ), SizedBox(height: 8), _buildInfoCard( context, icon: Icons.star, title: "推荐指数", content: Row( mainAxisSize: MainAxisSize.min, children: List.generate(5, (index) { return Icon( index < recipe.recommendRate ? Icons.star : Icons.star_border, color: Theme.of(context).primaryColor, size: 20, ); }), ), ), SizedBox(height: 8), _buildInfoCard( context, icon: Icons.shopping_cart, title: "食材信息", content: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [_buildMaterialSection(materialList)], ), ), SizedBox(height: 8), _buildInfoCard( context, icon: Icons.list, title: "步骤信息", content: Column(children: [_buildStepSection(recipe.stepList)]), ), SizedBox(height: 8), _buildInfoCard( context, icon: Icons.note, title: "其他信息", content: Text( '备注:${recipe.remark.isEmpty ? '无' : recipe.remark}', style: const TextStyle(height: 1.5), ), ), ], ); } Widget _buildTitleSection() { return Text( recipe.name, style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold), ); } Widget _buildMaterialSection(List materials) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (materials.isEmpty) buildTag(context, '无') else Column( crossAxisAlignment: CrossAxisAlignment.start, spacing: 8.0, children: materials.map((m) => _buildMaterialItem(m)).toList(), ), ], ); } Widget _buildMaterialItem(RecipeMaterial material) { return Text('${material.name} ${material.amount}'); } Widget _buildStepSection(List steps) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (steps.isEmpty) buildTag(context, '无') else Column( crossAxisAlignment: CrossAxisAlignment.start, spacing: 8.0, children: steps.map((m) => _buildStepItem(m)).toList(), ), ], ); } Widget _buildStepItem(RecipeStep step) { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("第${step.sort + 1}步"), SizedBox(width: 10), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( step.content, style: const TextStyle( height: 1.4, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 8), ], ), ), ], ); } Widget _buildInfoCard( BuildContext context, { required IconData icon, required String title, required Widget content, }) { return CommonCard( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(icon, color: Theme.of(context).colorScheme.primary), const SizedBox(width: 5), Text( title, style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), ], ), SizedBox(height: 5), content, ], ), ); } Widget _buildButtons(FoodProvider provider) { return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ circleIconButton( context: context, icon: Icons.edit, onPressed: () => _handleEditRecipe(provider), ), SizedBox(width: 8), circleIconButton( context: context, icon: _isSharing ? Icons.hourglass_top : Icons.share, onPressed: _shareRecipeAsImage, ), ], ); } }