292 lines
7.7 KiB
Dart
292 lines
7.7 KiB
Dart
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<RecipeDetailPage> createState() => _RecipeDetailState();
|
|
}
|
|
|
|
class _RecipeDetailState extends State<RecipeDetailPage> {
|
|
Recipe recipe = Recipe.getEmpty();
|
|
final GlobalKey _recipeDetailKey = GlobalKey();
|
|
bool _isSharing = false;
|
|
|
|
List<RecipeMaterial> materialList = [];
|
|
|
|
@override
|
|
void didChangeDependencies() {
|
|
super.didChangeDependencies();
|
|
refreshRecipeDetail();
|
|
}
|
|
|
|
Future<void> 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<void> _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<FoodProvider>();
|
|
|
|
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<RecipeMaterial> 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<RecipeStep> 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,
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|