feat:重构模块
This commit is contained in:
@@ -43,15 +43,17 @@ Widget buildScrollToTop({
|
||||
required BuildContext context,
|
||||
required VoidCallback scrollToTop,
|
||||
}) {
|
||||
final colors = Theme.of(context).colorScheme;
|
||||
|
||||
return Positioned(
|
||||
right: 0,
|
||||
bottom: 20,
|
||||
bottom: 80,
|
||||
child: FloatingActionButton(
|
||||
onPressed: scrollToTop,
|
||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||
backgroundColor: colors.primary,
|
||||
elevation: 2,
|
||||
mini: true,
|
||||
child: const Icon(Icons.arrow_upward, color: Colors.white),
|
||||
child: Icon(Icons.arrow_upward, color: colors.surface),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,26 +12,26 @@ InputDecoration buildInputDecoration({
|
||||
|
||||
return InputDecoration(
|
||||
hintText: hintText,
|
||||
hintStyle: TextStyle(color: colors.onSurface.withAlpha(100)),
|
||||
hintStyle: Theme.of(context).textTheme.bodyMedium,
|
||||
filled: true,
|
||||
fillColor: colors.surface,
|
||||
border: OutlineInputBorder(
|
||||
borderSide: const BorderSide(color: Color(0xFFE5E7EB)),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide.none,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(color: colors.primary, width: 2),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
errorBorder: OutlineInputBorder(
|
||||
borderSide: const BorderSide(color: Colors.red, width: 2),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 15, vertical: 14),
|
||||
errorStyle: const TextStyle(fontSize: 12, height: 1, color: Colors.red),
|
||||
prefixIcon:
|
||||
prefixIcon != null
|
||||
? Icon(prefixIcon, size: 20, color: Color(0xFF86909C))
|
||||
? Icon(prefixIcon, size: 20, color: colors.primary)
|
||||
: null,
|
||||
prefixIconConstraints: const BoxConstraints(minWidth: 40),
|
||||
isDense: true,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:food_hub_app/config/app_config.dart';
|
||||
import 'package:photo_view/photo_view.dart';
|
||||
@@ -53,6 +54,8 @@ class _ImagePreviewPageState extends State<ImagePreviewPage> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final index = '${_currentIndex + 1}/${widget.images.length}';
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.black,
|
||||
appBar: AppBar(
|
||||
@@ -63,10 +66,7 @@ class _ImagePreviewPageState extends State<ImagePreviewPage> {
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
// 显示实时更新的页码(当前索引+1 / 总数量)
|
||||
title: Text(
|
||||
'${_currentIndex + 1}/${widget.images.length}',
|
||||
style: const TextStyle(color: Colors.white),
|
||||
),
|
||||
title: Text(index, style: const TextStyle(color: Colors.white)),
|
||||
centerTitle: true,
|
||||
),
|
||||
body: PhotoViewGallery(
|
||||
@@ -95,21 +95,6 @@ class CommonImage extends StatelessWidget {
|
||||
|
||||
const CommonImage({super.key, required this.imageUrls, required this.index});
|
||||
|
||||
Widget _buildImageLoadingIndicator(ImageChunkEvent? progress) {
|
||||
final value =
|
||||
progress?.expectedTotalBytes != null
|
||||
? progress!.cumulativeBytesLoaded / progress.expectedTotalBytes!
|
||||
: null;
|
||||
|
||||
return Center(
|
||||
child: SizedBox(
|
||||
width: 30,
|
||||
height: 30,
|
||||
child: CircularProgressIndicator(value: value),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildErrorImage() {
|
||||
return Container(
|
||||
color: Colors.grey[200],
|
||||
@@ -140,14 +125,16 @@ class CommonImage extends StatelessWidget {
|
||||
onTap: () {
|
||||
_navigateToImagePreview(context, imageUrls, index);
|
||||
},
|
||||
child: Image.network(
|
||||
'${AppConfig.imageBaseUrl}${imageUrls[index]}',
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: '${AppConfig.imageBaseUrl}${imageUrls[index]}',
|
||||
fit: BoxFit.cover,
|
||||
loadingBuilder: (context, child, loadingProgress) {
|
||||
if (loadingProgress == null) return child;
|
||||
return _buildImageLoadingIndicator(loadingProgress);
|
||||
},
|
||||
errorBuilder: (context, error, stackTrace) => _buildErrorImage(),
|
||||
progressIndicatorBuilder:
|
||||
(context, url, downloadProgress) => CircularProgressIndicator(
|
||||
strokeWidth: 1.5,
|
||||
padding: EdgeInsetsGeometry.all(20),
|
||||
value: downloadProgress.progress,
|
||||
),
|
||||
errorWidget: (context, error, stackTrace) => _buildErrorImage(),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -213,19 +200,19 @@ Widget buildImageUploadButton({
|
||||
onTap: onTap,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Container(
|
||||
width: 96,
|
||||
height: 96,
|
||||
width: double.infinity,
|
||||
height: 250,
|
||||
decoration: BoxDecoration(
|
||||
color: colors.surface,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: Colors.black),
|
||||
border: Border.all(color: colors.surface),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(Icons.add, color: colors.onSurface.withAlpha(100)),
|
||||
Icon(Icons.camera_alt, color: colors.onSurface.withAlpha(100)),
|
||||
SizedBox(height: 6),
|
||||
Text('添加图片', style: TextStyle(color: colors.onSurface.withAlpha(100))),
|
||||
Text('点击上传美食图片', style: Theme.of(context).textTheme.bodyMedium),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -43,8 +43,8 @@ Widget buildToggleSwitch<T extends Enum>({
|
||||
totalSwitches: tabValues.length,
|
||||
labels: labels,
|
||||
activeBgColor: [colors.primary],
|
||||
activeFgColor: Colors.white,
|
||||
inactiveBgColor: colors.surfaceContainer,
|
||||
activeFgColor: colors.surface,
|
||||
inactiveBgColor: colors.surface,
|
||||
inactiveFgColor: colors.onSurface,
|
||||
cornerRadius: 12.0,
|
||||
customTextStyles: [TextStyle(fontSize: 12, fontWeight: FontWeight.w500)],
|
||||
@@ -85,10 +85,10 @@ Widget buildTag(BuildContext context, String title) {
|
||||
return Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: colors.primary.withAlpha(60),
|
||||
color: colors.primary,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Text(title, style: TextStyle(color: colors.primary)),
|
||||
child: Text(title, style: TextStyle(color: colors.surface)),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -135,24 +135,10 @@ Widget buildInfoButton({
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
||||
elevation: 0,
|
||||
),
|
||||
child: Text(text, style: TextStyle(color: Colors.white)),
|
||||
child: Text(text),
|
||||
);
|
||||
}
|
||||
|
||||
/// 取消按钮样式
|
||||
ButtonStyle cancelButtonStyle() {
|
||||
return ButtonStyle(
|
||||
backgroundColor: WidgetStateProperty.all(Colors.grey),
|
||||
shape: WidgetStateProperty.all(
|
||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Text buttonText({required String text}) {
|
||||
return Text(text, style: TextStyle(color: Colors.white));
|
||||
}
|
||||
|
||||
/// 图片错误显示
|
||||
Widget errorImageContainer(double height) {
|
||||
return Container(
|
||||
|
||||
@@ -7,7 +7,6 @@ import 'package:food_hub_app/provider/food_provider.dart';
|
||||
import 'package:food_hub_app/provider/user_provider.dart';
|
||||
import 'package:food_hub_app/widgets/common/image.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:tdesign_flutter/tdesign_flutter.dart';
|
||||
|
||||
class MomentCard extends StatefulWidget {
|
||||
final Moment moment;
|
||||
@@ -26,21 +25,24 @@ class MomentCardState extends State<MomentCard> {
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
InkWell(onTap: () => _onTapUser(context), child: _buildAvatar()),
|
||||
InkWell(
|
||||
onTap: () => _onTapUser(context),
|
||||
child: _buildAvatar(context),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildNickname(),
|
||||
_buildNickname(context),
|
||||
const SizedBox(height: 5),
|
||||
_buildContent(),
|
||||
_buildContent(context),
|
||||
if (widget.moment.imageList.isNotEmpty) ...[
|
||||
const SizedBox(height: 8),
|
||||
_buildPostImages(),
|
||||
],
|
||||
const SizedBox(height: 10),
|
||||
_buildTime(),
|
||||
_buildTime(context),
|
||||
const SizedBox(height: 5),
|
||||
_buildActionButtons(),
|
||||
if (widget.moment.commentList!.isNotEmpty) ...[
|
||||
@@ -69,38 +71,35 @@ class MomentCardState extends State<MomentCard> {
|
||||
}
|
||||
|
||||
// 构建头像组件
|
||||
Widget _buildAvatar() {
|
||||
Widget _buildAvatar(BuildContext context) {
|
||||
if (widget.moment.avatar!.isEmpty) {
|
||||
return TDAvatar(
|
||||
size: TDAvatarSize.medium,
|
||||
type: TDAvatarType.customText,
|
||||
shape: TDAvatarShape.circle,
|
||||
return CircleAvatar(
|
||||
radius: 18,
|
||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||
text: widget.moment.username?[0],
|
||||
foregroundColor: Theme.of(context).colorScheme.surface,
|
||||
child: Text(widget.moment.username![0], style: TextStyle(fontSize: 14)),
|
||||
);
|
||||
} else {
|
||||
return TDAvatar(
|
||||
size: TDAvatarSize.medium,
|
||||
type: TDAvatarType.normal,
|
||||
fit: BoxFit.contain,
|
||||
avatarUrl: '${AppConfig.imageBaseUrl}/${widget.moment.avatar}',
|
||||
return CircleAvatar(
|
||||
radius: 18,
|
||||
backgroundImage: NetworkImage('${AppConfig.imageBaseUrl}/${widget.moment.avatar}')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 构建昵称组件
|
||||
Widget _buildNickname() {
|
||||
Widget _buildNickname(BuildContext context) {
|
||||
return Text(
|
||||
widget.moment.username ?? "",
|
||||
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
);
|
||||
}
|
||||
|
||||
// 构建内容组件
|
||||
Widget _buildContent() {
|
||||
Widget _buildContent(BuildContext context) {
|
||||
return Text(
|
||||
widget.moment.content,
|
||||
style: const TextStyle(fontSize: 15, height: 1.3),
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -142,10 +141,10 @@ class MomentCardState extends State<MomentCard> {
|
||||
}
|
||||
|
||||
// 构建时间组件
|
||||
Widget _buildTime() {
|
||||
Widget _buildTime(BuildContext context) {
|
||||
return Text(
|
||||
widget.moment.date ?? "",
|
||||
style: TextStyle(fontSize: 12, color: Colors.grey[500]),
|
||||
style: Theme.of(context).textTheme.bodySmall,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -178,14 +177,14 @@ class MomentCardState extends State<MomentCard> {
|
||||
alignment: Alignment.bottomLeft,
|
||||
children: [
|
||||
Icon(Icons.thumb_up_alt_outlined),
|
||||
Positioned(
|
||||
left: 20,
|
||||
bottom: 15,
|
||||
child: TDBadge(
|
||||
TDBadgeType.message,
|
||||
count: (widget.moment.likeList?.length ?? 0).toString(),
|
||||
),
|
||||
),
|
||||
// Positioned(
|
||||
// left: 20,
|
||||
// bottom: 15,
|
||||
// child: TDBadge(
|
||||
// TDBadgeType.message,
|
||||
// count: (widget.moment.likeList?.length ?? 0).toString(),
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -196,14 +195,14 @@ class MomentCardState extends State<MomentCard> {
|
||||
alignment: Alignment.bottomLeft,
|
||||
children: [
|
||||
Icon(Icons.comment_outlined),
|
||||
Positioned(
|
||||
left: 20,
|
||||
bottom: 15,
|
||||
child: TDBadge(
|
||||
TDBadgeType.message,
|
||||
count: (widget.moment.commentList?.length ?? 0).toString(),
|
||||
),
|
||||
),
|
||||
// Positioned(
|
||||
// left: 20,
|
||||
// bottom: 15,
|
||||
// child: TDBadge(
|
||||
// TDBadgeType.message,
|
||||
// count: (widget.moment.commentList?.length ?? 0).toString(),
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -4,7 +4,8 @@ import 'package:flutter_common/widget/common_widget.dart';
|
||||
import 'package:food_hub_app/config/app_config.dart';
|
||||
import 'package:food_hub_app/models/session.dart';
|
||||
import 'package:food_hub_app/widgets/common/index.dart';
|
||||
import 'package:tdesign_flutter/tdesign_flutter.dart';
|
||||
import 'package:liquid_glass_widgets/liquid_glass_widgets.dart';
|
||||
import 'package:liquid_glass_widgets/widgets/containers/glass_card.dart';
|
||||
|
||||
class ProfileInfo extends StatelessWidget {
|
||||
final User user;
|
||||
@@ -13,19 +14,21 @@ class ProfileInfo extends StatelessWidget {
|
||||
|
||||
Widget _buildAvatar(BuildContext context, User user) {
|
||||
if (user.avatar == null) {
|
||||
return TDAvatar(
|
||||
size: TDAvatarSize.large,
|
||||
type: TDAvatarType.customText,
|
||||
shape: TDAvatarShape.circle,
|
||||
return CircleAvatar(
|
||||
radius: 24,
|
||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||
text: user.username.isNotEmpty ? user.username[0] : '?',
|
||||
foregroundColor: Theme.of(context).colorScheme.surface,
|
||||
child: Text(
|
||||
user.username.isNotEmpty ? user.username[0] : '?',
|
||||
style: TextStyle(fontSize: 14),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return TDAvatar(
|
||||
size: TDAvatarSize.large,
|
||||
type: TDAvatarType.normal,
|
||||
fit: BoxFit.contain,
|
||||
avatarUrl: '${AppConfig.imageBaseUrl}/${user.avatar}',
|
||||
return CircleAvatar(
|
||||
radius: 24,
|
||||
backgroundImage: NetworkImage(
|
||||
'${AppConfig.imageBaseUrl}/${user.avatar}',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -41,22 +44,24 @@ class ProfileInfo extends StatelessWidget {
|
||||
children: [
|
||||
Icon(icon, size: 16, color: colors.primary),
|
||||
const SizedBox(width: 6),
|
||||
Text(text),
|
||||
Text(text, style: Theme.of(context).textTheme.bodyMedium),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CommonCard(
|
||||
final colors = Theme.of(context).colorScheme;
|
||||
|
||||
return GlassCard(
|
||||
padding: EdgeInsetsGeometry.all(10),
|
||||
useOwnLayer: true,
|
||||
settings: LiquidGlassSettings(glassColor: colors.surface),
|
||||
child: Column(
|
||||
children: [
|
||||
_buildAvatar(context, user),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
user.username,
|
||||
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
),
|
||||
Text(user.username, style: Theme.of(context).textTheme.titleMedium),
|
||||
const SizedBox(height: 8),
|
||||
if (user.tags != null && user.tags!.isNotEmpty)
|
||||
Row(
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:flutter_common/widget/common_widget.dart';
|
||||
import 'package:food_hub_app/models/recipe.dart';
|
||||
import 'package:food_hub_app/provider/food_provider.dart';
|
||||
import 'package:food_hub_app/utils/index.dart';
|
||||
import 'package:food_hub_app/views/record_form.dart';
|
||||
import 'package:food_hub_app/widgets/common/index.dart';
|
||||
import 'package:table_calendar/table_calendar.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
@@ -62,19 +63,16 @@ class _RecipeCalendarState extends State<RecipeCalendar> {
|
||||
Text(formatDateTime(provider.selectedDay, 'MM月dd日 EEEE')),
|
||||
SizedBox(height: 4),
|
||||
if (provider.selectRecordList.isEmpty)
|
||||
buildEmptyData()
|
||||
SizedBox(height: 100, child: buildEmptyData())
|
||||
else
|
||||
Expanded(
|
||||
child: ListView.separated(
|
||||
itemCount: provider.selectRecordList.length,
|
||||
separatorBuilder: (context, index) => SizedBox(height: 8),
|
||||
itemBuilder: (context, index) {
|
||||
return _buildRecordItem(
|
||||
context,
|
||||
provider.selectRecordList[index],
|
||||
);
|
||||
},
|
||||
),
|
||||
Column(
|
||||
children:
|
||||
provider.selectRecordList.map((record) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8),
|
||||
child: _buildRecordItem(context, record),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
],
|
||||
);
|
||||
@@ -112,7 +110,15 @@ class _RecipeCalendarState extends State<RecipeCalendar> {
|
||||
|
||||
provider.initRecordForm(record);
|
||||
provider.isEditing = true;
|
||||
Navigator.pushNamed(context, "/recordForm");
|
||||
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
|
||||
),
|
||||
builder: (context) => RecordForm(),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildRecordItem(BuildContext context, FoodRecord record) {
|
||||
@@ -195,12 +201,15 @@ class _RecipeCalendarState extends State<RecipeCalendar> {
|
||||
}
|
||||
|
||||
Widget _buildContent(FoodProvider provider) {
|
||||
return Column(
|
||||
children: [
|
||||
CommonCard(child: _recipeCalendar(provider)),
|
||||
SizedBox(height: 8),
|
||||
Expanded(child: CommonCard(child: _dailyItem(context, provider))),
|
||||
],
|
||||
return SingleChildScrollView(
|
||||
padding: const EdgeInsets.only(bottom: 80),
|
||||
child: Column(
|
||||
children: [
|
||||
CommonCard(child: _recipeCalendar(provider)),
|
||||
const SizedBox(height: 8),
|
||||
CommonCard(child: _dailyItem(context, provider)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -208,13 +217,10 @@ class _RecipeCalendarState extends State<RecipeCalendar> {
|
||||
Widget build(BuildContext context) {
|
||||
final provider = context.watch<FoodProvider>();
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
if (provider.isLoading)
|
||||
buildLoadingIndicator()
|
||||
else
|
||||
_buildContent(provider),
|
||||
],
|
||||
);
|
||||
if (provider.isLoading) {
|
||||
return buildLoadingIndicator();
|
||||
}
|
||||
|
||||
return _buildContent(provider);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_common/widget/common_widget.dart';
|
||||
import 'package:food_hub_app/models/recipe.dart';
|
||||
import 'package:food_hub_app/widgets/common/image.dart';
|
||||
import 'package:liquid_glass_widgets/liquid_glass_widgets.dart';
|
||||
|
||||
class RecipeCard extends StatelessWidget {
|
||||
final RecipeSummary recipe;
|
||||
@@ -17,14 +18,22 @@ class RecipeCard extends StatelessWidget {
|
||||
final List<String> imageUrls =
|
||||
recipe.recordList.reversed.map((record) => record.imageUrl).toList();
|
||||
|
||||
return CommonCard(
|
||||
final colors = Theme.of(context).colorScheme;
|
||||
|
||||
return GlassCard(
|
||||
padding: EdgeInsetsGeometry.all(10),
|
||||
useOwnLayer: true,
|
||||
settings: LiquidGlassSettings(glassColor: colors.surface),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
CommonImage(imageUrls: imageUrls, index: 0),
|
||||
SizedBox(height: 8),
|
||||
_buildRecipeContent(context),
|
||||
InkWell(
|
||||
onTap: () => navigatorToRecipeDetail(context),
|
||||
child: _buildRecipeContent(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -32,6 +41,7 @@ class RecipeCard extends StatelessWidget {
|
||||
|
||||
Widget _buildRecipeContent(BuildContext context) {
|
||||
final colors = Theme.of(context).colorScheme;
|
||||
final textTheme = Theme.of(context).textTheme;
|
||||
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
@@ -42,17 +52,10 @@ class RecipeCard extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
recipe.name,
|
||||
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
||||
style: textTheme.titleMedium,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
InkWell(
|
||||
onTap: () => navigatorToRecipeDetail(context),
|
||||
child: Icon(
|
||||
Icons.arrow_circle_right_sharp,
|
||||
color: colors.secondary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
@@ -62,19 +65,13 @@ class RecipeCard extends StatelessWidget {
|
||||
_buildIconText(
|
||||
icon: Icons.food_bank,
|
||||
text: recipe.category,
|
||||
color: Color(0xFF6A5ACD),
|
||||
color: colors.primary,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
_buildIconText(
|
||||
icon: Icons.thumb_up_alt_outlined,
|
||||
text: recipe.likeCount.toString(),
|
||||
color: Color(0xFFDC143C),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
_buildIconText(
|
||||
icon: Icons.star_outline,
|
||||
text: recipe.favouriteCount.toString(),
|
||||
color: Color(0xFF20B2AA),
|
||||
icon: Icons.note_add,
|
||||
text: recipe.recordList.length.toString(),
|
||||
color: colors.primary,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -22,56 +22,10 @@ class _RecipeListState extends State<RecipeList> {
|
||||
context.read<FoodProvider>().queryCategoryList();
|
||||
});
|
||||
}
|
||||
|
||||
Widget _buildSelectCategory(FoodProvider provider) {
|
||||
final colors = Theme.of(context).colorScheme;
|
||||
|
||||
return Container(
|
||||
width: 140,
|
||||
decoration: BoxDecoration(
|
||||
color: colors.surfaceContainer,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
child: DropdownButton<String>(
|
||||
value: provider.queryCategory,
|
||||
isExpanded: true,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
dropdownColor: colors.surfaceContainer,
|
||||
elevation: 6,
|
||||
underline: Container(),
|
||||
items:
|
||||
provider.categoryList.map((String value) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: value,
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 8,
|
||||
height: 8,
|
||||
decoration: BoxDecoration(
|
||||
color: colors.primary,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(value, style: TextStyle(fontSize: 14)),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: (value) {
|
||||
provider.queryCategory = value!;
|
||||
provider.refreshRecipeList();
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Widget _buildRecipeList(FoodProvider provider) {
|
||||
return GridView.builder(
|
||||
padding: const EdgeInsets.only(bottom: 80),
|
||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 2,
|
||||
crossAxisSpacing: 8,
|
||||
@@ -91,8 +45,6 @@ class _RecipeListState extends State<RecipeList> {
|
||||
} else {
|
||||
return Column(
|
||||
children: [
|
||||
_buildSelectCategory(provider),
|
||||
SizedBox(height: 5),
|
||||
Expanded(child: _buildRecipeList(provider)),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -28,26 +28,24 @@ class _RecipeTimeline extends State<RecipeTimeline> {
|
||||
SizedBox(width: 5),
|
||||
Text(
|
||||
record.date,
|
||||
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 6),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 0),
|
||||
child: CommonCard(
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
record.name,
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
CommonImage(imageUrls: [record.imageUrl], index: 0),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
CommonCard(
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
record.name,
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
CommonImage(imageUrls: [record.imageUrl], index: 0),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 20)
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -59,6 +57,7 @@ class _RecipeTimeline extends State<RecipeTimeline> {
|
||||
final colors = Theme.of(context).colorScheme;
|
||||
|
||||
return Timeline.tileBuilder(
|
||||
padding: const EdgeInsets.only(bottom: 80),
|
||||
theme: TimelineThemeData(nodePosition: 0, indicatorPosition: 0),
|
||||
builder: TimelineTileBuilder.connected(
|
||||
itemCount: recordList.length,
|
||||
|
||||
Reference in New Issue
Block a user