feat:更新个人主页模块

This commit is contained in:
2025-11-24 19:56:13 +08:00
parent 97e7a6f44b
commit 8cff5228ae
18 changed files with 443 additions and 197 deletions

View File

@@ -24,6 +24,13 @@ Future<List<Moment>> queryMomentListApi() {
); );
} }
Future<List<Moment>> queryMomentListByUserIdApi(int userId) {
return httpUtil.get<List<Moment>>(
"/moment/$userId",
converter: (data) => convertList<Moment>(data, Moment.fromJson),
);
}
Future<PageMoment> queryMomentByPageApi(int currentPage, int pageSize) { Future<PageMoment> queryMomentByPageApi(int currentPage, int pageSize) {
return httpUtil.get<PageMoment>( return httpUtil.get<PageMoment>(
"/moment/page", "/moment/page",

12
lib/apis/user.dart Normal file
View File

@@ -0,0 +1,12 @@
import 'package:flutter_common/utils/http_utils.dart';
import 'package:food_hub_app/config/app_config.dart';
import 'package:food_hub_app/models/session.dart';
final httpUtil = HttpUtil(baseUrl: AppConfig.baseApiUrl);
Future<User> queryUserApi(int number) {
return httpUtil.get<User>(
"/user/$number",
converter: (data) => User.fromJson(data),
);
}

View File

@@ -5,8 +5,8 @@ class AppConfig {
// http://14.103.235.151:81/food-service // http://14.103.235.151:81/food-service
// static const String baseApiUrl = "http://14.103.235.151:81/food-service"; // static const String baseApiUrl = "http://14.103.235.151:81/food-service";
// static const String baseApiUrl = "http://192.168.1.3:8100"; // static const String baseApiUrl = "http://192.168.1.3:8100";
// static const String baseApiUrl = "https://cxx0822.iepose.cn/food-api"; static const String baseApiUrl = "https://cxx0822.iepose.cn/food-api";
static const String baseApiUrl = "http://192.168.1.4:8083"; // static const String baseApiUrl = "http://192.168.1.4:8083";
// static const String baseApiUrl = "http://192.168.1.103:8083"; // static const String baseApiUrl = "http://192.168.1.103:8083";
static const String rustfsIp = '14.103.235.151'; static const String rustfsIp = '14.103.235.151';
static const String rustfsFileUrl = 'http://14.103.235.151:9100'; static const String rustfsFileUrl = 'http://14.103.235.151:9100';

View File

@@ -3,23 +3,15 @@ import 'package:food_hub_app/provider/food_provider.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class AppActions extends StatefulWidget { class AppActions extends StatefulWidget {
const AppActions({super.key}); final int pageIndex;
const AppActions({super.key, required this.pageIndex});
@override @override
State<StatefulWidget> createState() => AppActionsState(); State<StatefulWidget> createState() => AppActionsState();
} }
class AppActionsState extends State<AppActions> { class AppActionsState extends State<AppActions> {
void _buildBottomSheet(FoodProvider provider) {
showModalBottomSheet(
context: context,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
),
builder: (context) => _buildBottomSheetBody(provider),
);
}
Widget _buildBottomSheetBody(FoodProvider provider) { Widget _buildBottomSheetBody(FoodProvider provider) {
final colors = Theme.of(context).colorScheme; final colors = Theme.of(context).colorScheme;
final provider = context.watch<FoodProvider>(); final provider = context.watch<FoodProvider>();
@@ -33,16 +25,19 @@ class AppActionsState extends State<AppActions> {
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
if (widget.pageIndex == 0)
ListTile( ListTile(
leading: Icon(Icons.book, color: colors.primary), leading: Icon(Icons.book, color: colors.primary),
title: const Text('新增菜谱'), title: const Text('新增菜谱'),
onTap: () => _handleAddRecipe(provider), onTap: () => _handleAddRecipe(provider),
), ),
if (widget.pageIndex == 0)
ListTile( ListTile(
leading: Icon(Icons.note_add, color: colors.primary), leading: Icon(Icons.note_add, color: colors.primary),
title: const Text('新增记录'), title: const Text('新增记录'),
onTap: () => _handleAddRecord(provider), onTap: () => _handleAddRecord(provider),
), ),
if (widget.pageIndex == 2)
ListTile( ListTile(
leading: Icon(Icons.group, color: colors.primary), leading: Icon(Icons.group, color: colors.primary),
title: const Text('发布朋友圈'), title: const Text('发布朋友圈'),
@@ -52,6 +47,22 @@ class AppActionsState extends State<AppActions> {
); );
} }
void _onPressAdd(FoodProvider provider) {
if (widget.pageIndex == 0) {
showModalBottomSheet(
context: context,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
),
builder: (context) => _buildBottomSheetBody(provider),
);
}
if (widget.pageIndex == 2) {
_handleAddMoment(provider);
}
}
void _handleAddRecipe(FoodProvider provider) { void _handleAddRecipe(FoodProvider provider) {
// provider.resetRecordForm(); // provider.resetRecordForm();
// Navigator.pop(context); // Navigator.pop(context);
@@ -68,7 +79,6 @@ class AppActionsState extends State<AppActions> {
void _handleAddMoment(FoodProvider provider) { void _handleAddMoment(FoodProvider provider) {
provider.resetMomentForm(); provider.resetMomentForm();
provider.isEditing = false; provider.isEditing = false;
Navigator.pop(context);
Navigator.pushNamed(context, "/momentForm"); Navigator.pushNamed(context, "/momentForm");
} }
@@ -84,11 +94,10 @@ class AppActionsState extends State<AppActions> {
// 搜索功能 // 搜索功能
}, },
), ),
if (widget.pageIndex == 0 || widget.pageIndex == 2)
IconButton( IconButton(
icon: Icon(Icons.add, color: Colors.white), icon: Icon(Icons.add, color: Colors.white),
onPressed: () { onPressed: () => _onPressAdd(provider),
_buildBottomSheet(provider);
},
), ),
], ],
); );

View File

@@ -3,10 +3,12 @@ import 'package:flutter_common/provider/theme_provider.dart';
import 'package:flutter_common/utils/sp_utils.dart'; import 'package:flutter_common/utils/sp_utils.dart';
import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:food_hub_app/provider/food_provider.dart'; import 'package:food_hub_app/provider/food_provider.dart';
import 'package:food_hub_app/provider/user_provider.dart';
import 'package:food_hub_app/views/home.dart'; import 'package:food_hub_app/views/home.dart';
import 'package:food_hub_app/views/login.dart'; import 'package:food_hub_app/views/login.dart';
import 'package:food_hub_app/views/moment.dart'; import 'package:food_hub_app/views/moment.dart';
import 'package:food_hub_app/views/moment_form.dart'; import 'package:food_hub_app/views/moment_form.dart';
import 'package:food_hub_app/views/moment_user.dart';
import 'package:food_hub_app/views/record_form.dart'; import 'package:food_hub_app/views/record_form.dart';
import 'package:food_hub_app/views/recipe_detail.dart'; import 'package:food_hub_app/views/recipe_detail.dart';
import 'package:form_builder_validators/form_builder_validators.dart'; import 'package:form_builder_validators/form_builder_validators.dart';
@@ -23,6 +25,7 @@ void main() async {
providers: [ providers: [
ChangeNotifierProvider(create: (context) => FoodProvider()), ChangeNotifierProvider(create: (context) => FoodProvider()),
ChangeNotifierProvider(create: (context) => ThemeProvider()), ChangeNotifierProvider(create: (context) => ThemeProvider()),
ChangeNotifierProvider(create: (context) => UserProvider()),
], ],
child: MyApp(), child: MyApp(),
), ),
@@ -65,7 +68,8 @@ class MyApp extends StatelessWidget {
'/recordForm': (context) => RecordFormPage(), '/recordForm': (context) => RecordFormPage(),
'/recipeDetail': (context) => RecipeDetailPage(), '/recipeDetail': (context) => RecipeDetailPage(),
'/momentForm': (context) => MomentFormPage(), '/momentForm': (context) => MomentFormPage(),
'/moment': (context) => MomentPage() '/moment': (context) => MomentPage(),
'/momentUser': (context) => MomentUserPage()
}, },
); );
} }

View File

@@ -30,14 +30,16 @@ class SaTokenInfo {
this.tag, this.tag,
}); });
factory SaTokenInfo.fromJson(Map<String, dynamic> json) => _$SaTokenInfoFromJson(json); factory SaTokenInfo.fromJson(Map<String, dynamic> json) =>
_$SaTokenInfoFromJson(json);
Map<String, dynamic> toJson() => _$SaTokenInfoToJson(this); Map<String, dynamic> toJson() => _$SaTokenInfoToJson(this);
} }
@JsonSerializable() @JsonSerializable()
class User { class User {
int? id; int? id;
String? username; String username;
int? gender; int? gender;
String? phoneNumber; String? phoneNumber;
String? email; String? email;
@@ -51,7 +53,7 @@ class User {
User({ User({
this.id, this.id,
this.username, required this.username,
this.gender, this.gender,
this.phoneNumber, this.phoneNumber,
this.email, this.email,
@@ -65,7 +67,24 @@ class User {
}); });
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json); factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this); Map<String, dynamic> toJson() => _$UserToJson(this);
static User getEmpty() {
return User(
username: '',
gender: 0,
phoneNumber: '',
email: '',
birthDate: null,
avatar: '',
area: [],
address: '',
job: '',
tags: [],
description: '',
);
}
} }
@JsonSerializable() @JsonSerializable()
@@ -75,6 +94,8 @@ class Session {
Session({required this.saToken, required this.userInfo}); Session({required this.saToken, required this.userInfo});
factory Session.fromJson(Map<String, dynamic> json) => _$SessionFromJson(json); factory Session.fromJson(Map<String, dynamic> json) =>
_$SessionFromJson(json);
Map<String, dynamic> toJson() => _$SessionToJson(this); Map<String, dynamic> toJson() => _$SessionToJson(this);
} }

View File

@@ -37,7 +37,7 @@ Map<String, dynamic> _$SaTokenInfoToJson(SaTokenInfo instance) =>
User _$UserFromJson(Map<String, dynamic> json) => User( User _$UserFromJson(Map<String, dynamic> json) => User(
id: (json['id'] as num?)?.toInt(), id: (json['id'] as num?)?.toInt(),
username: json['username'] as String?, username: json['username'] as String,
gender: (json['gender'] as num?)?.toInt(), gender: (json['gender'] as num?)?.toInt(),
phoneNumber: json['phoneNumber'] as String?, phoneNumber: json['phoneNumber'] as String?,
email: json['email'] as String?, email: json['email'] as String?,

View File

@@ -306,6 +306,26 @@ class FoodProvider with ChangeNotifier {
} }
} }
Future<void> queryMomentByUserId(int userId) async {
if (isLoading) return;
try {
isLoading = true;
error = null;
notifyListeners();
final result = await queryMomentListByUserIdApi(userId);
momentList = result;
notifyListeners();
} catch (e) {
error = '加载数据失败: $e';
debugPrint('加载数据失败: $e');
} finally {
isLoading = false;
notifyListeners();
}
}
Future<void> loadMoreMomentList() async { Future<void> loadMoreMomentList() async {
if (hasMore && !isLoading) { if (hasMore && !isLoading) {
await queryMomentByPage(isRefresh: false); await queryMomentByPage(isRefresh: false);

View File

@@ -0,0 +1,28 @@
import 'package:flutter/material.dart';
import 'package:food_hub_app/apis/user.dart';
import 'package:food_hub_app/models/session.dart';
class UserProvider with ChangeNotifier {
late User currentUser = User.getEmpty();
bool isLoading = false;
String error = '';
Future<void> refreshUser(int id) async {
if (isLoading) return;
try {
isLoading = true;
error = '';
notifyListeners();
final result = await queryUserApi(id);
currentUser = result;
} catch (e) {
error = '加载数据失败: $e';
debugPrint('加载数据失败: $e');
} finally {
isLoading = false;
notifyListeners();
}
}
}

View File

@@ -30,7 +30,7 @@ class _HomePage extends State<HomePage> {
); );
}, },
), ),
actions: [AppActions()], actions: [AppActions(pageIndex: _currentIndex)],
), ),
// backgroundColor: Color(0xFFF5F5F5), // backgroundColor: Color(0xFFF5F5F5),
drawer: AppDrawer(), drawer: AppDrawer(),

View File

@@ -63,6 +63,10 @@ class _LoginPage extends State<LoginPage> {
SPUtil.set('token', token); SPUtil.set('token', token);
} }
void handleUserInfo(User user) {
SPUtil.set('userId', user.id);
}
void loginClick() async { void loginClick() async {
setState(() { setState(() {
_isLoading = true; _isLoading = true;
@@ -78,6 +82,7 @@ class _LoginPage extends State<LoginPage> {
ToastUtil.success('登录成功'); ToastUtil.success('登录成功');
handleRememberState(); handleRememberState();
handleTokenState(session.saToken.tokenValue); handleTokenState(session.saToken.tokenValue);
handleUserInfo(session.userInfo);
LoadingDialog.hide(context); LoadingDialog.hide(context);
Navigator.pushNamed(context, '/home'); Navigator.pushNamed(context, '/home');

View File

@@ -84,7 +84,7 @@ class _MomentPageState extends State<MomentPage> {
itemCount: provider.momentList.length, itemCount: provider.momentList.length,
separatorBuilder: (context, index) => SizedBox(height: 8), separatorBuilder: (context, index) => SizedBox(height: 8),
itemBuilder: (context, index) { itemBuilder: (context, index) {
return MomentCard(moment: provider.momentList[index]); return MomentCard(moment: provider.momentList[index], isUser: false);
}, },
); );
} }

View File

@@ -32,6 +32,7 @@ class _MomentFormPageState extends State<MomentFormPage> {
return FormBuilderTextField( return FormBuilderTextField(
name: _contentField, name: _contentField,
initialValue: provider.momentFormItem.content,
focusNode: _focusNode, focusNode: _focusNode,
maxLines: 5, maxLines: 5,
minLines: 3, minLines: 3,
@@ -110,7 +111,7 @@ class _MomentFormPageState extends State<MomentFormPage> {
_buildContentField(provider), _buildContentField(provider),
const SizedBox(height: 8), const SizedBox(height: 8),
buildFormLabel(context: context, text: '上传图片', isRequired: false), buildFormLabel(context: context, text: '上传图片最多9张', isRequired: false),
const SizedBox(height: 8), const SizedBox(height: 8),
_buildImageField(provider), _buildImageField(provider),
const SizedBox(height: 8), const SizedBox(height: 8),
@@ -218,7 +219,6 @@ class _MomentFormPageState extends State<MomentFormPage> {
onPressed: () => Navigator.pop(context), onPressed: () => Navigator.pop(context),
), ),
), ),
backgroundColor: const Color(0xFFF5F5F5),
body: SingleChildScrollView( body: SingleChildScrollView(
child: Padding( child: Padding(
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),

View File

@@ -0,0 +1,64 @@
import 'package:flutter/material.dart';
import 'package:flutter_common/utils/sp_utils.dart';
import 'package:flutter_common/widget/common_widget.dart';
import 'package:food_hub_app/provider/food_provider.dart';
import 'package:food_hub_app/widgets/moment/card.dart';
import 'package:provider/provider.dart';
class MomentUserPage extends StatefulWidget {
const MomentUserPage({super.key});
@override
State<MomentUserPage> createState() => _MomentUserPageState();
}
class _MomentUserPageState extends State<MomentUserPage> {
@override
void initState() {
super.initState();
// 初始化加载数据
WidgetsBinding.instance.addPostFrameCallback((_) {
context.read<FoodProvider>().queryMomentByUserId(SPUtil.getInt('userId'));
});
}
Widget _buildMomentList(FoodProvider provider) {
return ListView.separated(
itemCount: provider.momentList.length,
separatorBuilder: (context, index) => SizedBox(height: 8),
itemBuilder: (context, index) {
return MomentCard(moment: provider.momentList[index], isUser: true);
},
);
}
@override
Widget build(BuildContext context) {
final provider = context.watch<FoodProvider>();
// 空状态显示
if (provider.momentList.isEmpty) {
return buildEmptyData();
}
return Scaffold(
appBar: AppBar(
title: Text('我的朋友圈', style: const TextStyle(color: Colors.white)),
backgroundColor: Theme.of(context).colorScheme.primary,
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.white),
onPressed: () => Navigator.pop(context),
),
),
backgroundColor: const Color(0xFFF5F5F5),
body:
provider.isLoading
? buildLoadingIndicator()
: Padding(
padding: const EdgeInsets.all(10),
child: CommonCard(child: _buildMomentList(provider)),
),
);
}
}

View File

@@ -1,15 +1,209 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_common/utils/date_utils.dart';
import 'package:flutter_common/utils/sp_utils.dart';
import 'package:flutter_common/widget/common_widget.dart';
import 'package:flutter_common/widget/dialog_widget.dart';
import 'package:food_hub_app/config/app_config.dart';
import 'package:food_hub_app/models/session.dart';
import 'package:food_hub_app/provider/user_provider.dart';
import 'package:food_hub_app/widgets/common/index.dart';
import 'package:provider/provider.dart';
import 'package:tdesign_flutter/tdesign_flutter.dart';
class ProfilePage extends StatefulWidget { class ProfilePage extends StatefulWidget {
const ProfilePage({super.key}); const ProfilePage({super.key});
@override @override
State<ProfilePage> createState() => _ProfilePage(); State<ProfilePage> createState() => ProfilePageState();
} }
class _ProfilePage extends State<ProfilePage>{ class ProfilePageState extends State<ProfilePage> {
@override
void initState() {
super.initState();
// 初始化加载数据
WidgetsBinding.instance.addPostFrameCallback((_) {
context.read<UserProvider>().refreshUser(SPUtil.getInt('userId'));
});
}
Widget _buildAvatar(User user) {
if (user.avatar!.isEmpty) {
return TDAvatar(
size: TDAvatarSize.large,
type: TDAvatarType.customText,
shape: TDAvatarShape.circle,
backgroundColor: Theme.of(context).colorScheme.primary,
text: user.username.isNotEmpty ? user.username[0] : '?',
);
} else {
return TDAvatar(
size: TDAvatarSize.large,
type: TDAvatarType.normal,
fit: BoxFit.contain,
avatarUrl: '${AppConfig.imageBaseUrl}/${user.avatar}',
);
}
}
Widget _buildInfoItem({required IconData icon, required String text}) {
final colors = Theme.of(context).colorScheme;
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, size: 16, color: colors.primary),
const SizedBox(width: 6),
Text(text),
],
);
}
Widget _buildFunctionButton({
required IconData icon,
required String text,
required VoidCallback onTap,
}) {
final colors = Theme.of(context).colorScheme;
return ListTile(
contentPadding: EdgeInsets.zero,
leading: Icon(icon, color: colors.primary),
title: Text(text),
trailing: Icon(Icons.arrow_forward_ios, size: 16, color: colors.primary),
onTap: onTap,
);
}
Widget _buildBasicInfo(User user) {
return CommonCard(
child: Column(
children: [
_buildAvatar(user),
const SizedBox(height: 8),
Text(
user.username,
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
if (user.tags != null && user.tags!.isNotEmpty)
Row(
mainAxisAlignment: MainAxisAlignment.center,
children:
user.tags!.map((tag) => buildTag(context, tag)).toList(),
),
if (user.tags != null && user.tags!.isNotEmpty)
const SizedBox(height: 8),
Wrap(
spacing: 8,
runSpacing: 8,
children: [
if (user.area != null && user.area!.length >= 2)
_buildInfoItem(
icon: Icons.location_on,
text: '${user.area![0]}-${user.area![1]}',
),
if (user.birthDate != null)
_buildInfoItem(
icon: Icons.cake,
text: formatDate(user.birthDate!),
),
if (user.job != null && user.job!.isNotEmpty)
_buildInfoItem(icon: Icons.work, text: user.job!),
if (user.phoneNumber != null && user.phoneNumber!.isNotEmpty)
_buildInfoItem(
icon: Icons.phone_android,
text: user.phoneNumber!,
),
if (user.email != null && user.email!.isNotEmpty)
_buildInfoItem(icon: Icons.email, text: user.email!),
],
),
if (user.description != null && user.description!.isNotEmpty)
const SizedBox(height: 8),
if (user.description != null && user.description!.isNotEmpty)
Text(user.description!),
],
),
);
}
void _onTapMoment() {
Navigator.pushNamed(context, '/momentUser');
}
Widget _buildFunctionButtons() {
return CommonCard(
child: Column(
children: [
_buildFunctionButton(
icon: Icons.account_circle,
text: '基本资料',
onTap: () {
// 跳转到编辑资料页面
// LogUtils.i('点击编辑资料');
},
),
const Divider(height: 1),
_buildFunctionButton(
icon: Icons.group_outlined,
text: '朋友圈',
onTap: _onTapMoment,
),
const Divider(height: 1),
_buildFunctionButton(
icon: Icons.favorite,
text: '我的收藏',
onTap: () {
// 跳转到浏览历史页面
// LogUtils.i('点击浏览历史');
},
),
const Divider(height: 1),
_buildFunctionButton(
icon: Icons.lock,
text: '更改密码',
onTap: () {
// 跳转到帮助与反馈页面
// LogUtils.i('点击帮助与反馈');
},
),
const Divider(height: 1),
_buildFunctionButton(
icon: Icons.exit_to_app,
text: '退出登录',
onTap: () {
showConfirmDialog(context, '确认要退出吗?');
},
),
],
),
);
}
Widget _buildContent(UserProvider provider) {
final user = provider.currentUser;
return Column(
children: [
SizedBox(width: double.infinity, child: _buildBasicInfo(user)),
const SizedBox(height: 16),
_buildFunctionButtons(),
],
);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return const Center(child: Text("个人主页")); final provider = context.watch<UserProvider>();
return Stack(
children: [
if (provider.isLoading)
buildLoadingIndicator()
else if (provider.error.isNotEmpty)
Text(provider.error)
else
_buildContent(provider),
],
);
} }
} }

View File

@@ -2,13 +2,16 @@ import 'package:flutter/material.dart';
import 'package:flutter_common/widget/common_widget.dart'; import 'package:flutter_common/widget/common_widget.dart';
import 'package:food_hub_app/config/app_config.dart'; import 'package:food_hub_app/config/app_config.dart';
import 'package:food_hub_app/models/moment.dart'; import 'package:food_hub_app/models/moment.dart';
import 'package:food_hub_app/provider/food_provider.dart';
import 'package:food_hub_app/widgets/common/image.dart'; import 'package:food_hub_app/widgets/common/image.dart';
import 'package:provider/provider.dart';
import 'package:tdesign_flutter/tdesign_flutter.dart'; import 'package:tdesign_flutter/tdesign_flutter.dart';
class MomentCard extends StatelessWidget { class MomentCard extends StatelessWidget {
final Moment moment; final Moment moment;
final bool isUser;
const MomentCard({super.key, required this.moment}); const MomentCard({super.key, required this.moment, required this.isUser});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -32,7 +35,7 @@ class MomentCard extends StatelessWidget {
const SizedBox(height: 10), const SizedBox(height: 10),
_buildTime(), _buildTime(),
const SizedBox(height: 5), const SizedBox(height: 5),
_buildActionButtons(), _buildActionButtons(context),
if (moment.commentList!.isNotEmpty) ...[ if (moment.commentList!.isNotEmpty) ...[
const SizedBox(height: 8), const SizedBox(height: 8),
_buildCommentList(), _buildCommentList(),
@@ -52,7 +55,7 @@ class MomentCard extends StatelessWidget {
size: TDAvatarSize.medium, size: TDAvatarSize.medium,
type: TDAvatarType.customText, type: TDAvatarType.customText,
shape: TDAvatarShape.circle, shape: TDAvatarShape.circle,
backgroundColor: Theme.of(context).primaryColor, backgroundColor: Theme.of(context).colorScheme.primary,
text: moment.username?[0], text: moment.username?[0],
); );
} else { } else {
@@ -126,10 +129,31 @@ class MomentCard extends StatelessWidget {
); );
} }
void _onTapEdit(BuildContext context) {
final provider = Provider.of<FoodProvider>(context, listen: false);
provider.isEditing = true;
provider.momentFormItem = moment;
Navigator.pushNamed(context, '/momentForm');
}
// 构建点赞和评论按钮 // 构建点赞和评论按钮
Widget _buildActionButtons() { Widget _buildActionButtons(BuildContext context) {
return Row( return Row(
children: [ children: [
if (isUser)
SizedBox(
width: 42,
height: 36,
child: Stack(
alignment: Alignment.bottomLeft,
children: [
InkWell(
onTap: () => _onTapEdit(context),
child: Icon(Icons.edit),
),
],
),
),
SizedBox( SizedBox(
width: 42, width: 42,
height: 36, height: 36,
@@ -166,30 +190,6 @@ class MomentCard extends StatelessWidget {
], ],
), ),
), ),
// _buildActionButton(
// icon: Icons.thumb_up_alt_outlined,
// count: moment.likeList?.length ?? 0,
// ),
// const SizedBox(width: 20),
// _buildActionButton(
// icon: Icons.comment_outlined,
// count: moment.commentList?.length ?? 0,
// ),
],
);
}
// 构建带数字标记的动作按钮
Widget _buildActionButton({required IconData icon, required int count}) {
return Row(
children: [
Icon(icon, color: Colors.grey[500], size: 18),
const SizedBox(width: 4),
if (count > 0)
Text(
count.toString(),
style: TextStyle(fontSize: 12, color: Colors.grey[500]),
),
], ],
); );
} }

View File

@@ -321,8 +321,8 @@ packages:
flutter_common: flutter_common:
dependency: "direct main" dependency: "direct main"
description: description:
path: "D:\\Projects\\FlutterProjects\\flutter_common" path: "../flutter_common"
relative: false relative: true
source: path source: path
version: "1.0.0+1" version: "1.0.0+1"
flutter_form_builder: flutter_form_builder:

View File

@@ -1,119 +1 @@
name: food_hub_app name: food_hub_app
description: "A new Flutter project."
# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# In Android, build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 1.0.0+1
environment:
sdk: ^3.7.0
# Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions
# consider running `flutter pub upgrade --major-versions`. Alternatively,
# dependencies can be manually updated by changing the version numbers below to
# the latest version available on pub.dev. To see which dependencies have newer
# versions available, run `flutter pub outdated`.
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
# The following adds the Cupertino Icons fonts to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.8
provider: ^6.1.1
timelines_plus: ^1.0.7
table_calendar: ^3.1.3
toggle_switch: ^2.3.0
flutter_form_builder: ^10.0.0
form_builder_validators: ^11.1.2
intl: ^0.19.0
tdesign_flutter: ^0.2.3
json_annotation: ^4.9.0
logger: ^2.6.0
photo_view: ^0.15.0
flutter_carousel_widget: ^3.1.0
easy_refresh: ^3.4.0
file_picker: ^10.3.3
share_plus: ^11.0.0
path_provider: ^2.1.5
flutter_common:
path: ..\flutter_common
dependency_overrides:
tdesign_flutter_adaptation: 3.16.0
image_picker: 1.0.8
dev_dependencies:
flutter_test:
sdk: flutter
# The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is
# activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint
# rules and activating additional ones.
flutter_lints: ^5.0.0
# flutter pub run build_runner build
build_runner: ^2.4.5
json_serializable: ^6.7.1
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter packages.
flutter:
# The following line ensures that the Material Icons fonts is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/to/resolution-aware-images
# For details regarding adding assets from package dependencies, see
# https://flutter.dev/to/asset-from-package
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the fonts family name, and a "fonts" key with a
# list giving the asset and other descriptors for the fonts. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/to/font-from-package
fonts:
- family: CustomFont
fonts:
- asset: fonts/custom.ttf