feat:增加用户信息编辑功能
This commit is contained in:
@@ -10,3 +10,7 @@ Future<User> queryUserApi(int number) {
|
|||||||
converter: (data) => User.fromJson(data),
|
converter: (data) => User.fromJson(data),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<bool> updateUserApi(int id, User user) {
|
||||||
|
return httpUtil.put<bool>("/user/$id", data: user);
|
||||||
|
}
|
||||||
|
|||||||
@@ -126,7 +126,6 @@ class Recipe {
|
|||||||
bool isShare;
|
bool isShare;
|
||||||
int userId;
|
int userId;
|
||||||
String username;
|
String username;
|
||||||
String avatar;
|
|
||||||
List<RecipeMaterial> materialList;
|
List<RecipeMaterial> materialList;
|
||||||
List<RecipeStep> stepList;
|
List<RecipeStep> stepList;
|
||||||
List<FoodRecord> recordList;
|
List<FoodRecord> recordList;
|
||||||
@@ -143,7 +142,6 @@ class Recipe {
|
|||||||
required this.isShare,
|
required this.isShare,
|
||||||
required this.userId,
|
required this.userId,
|
||||||
required this.username,
|
required this.username,
|
||||||
required this.avatar,
|
|
||||||
required this.materialList,
|
required this.materialList,
|
||||||
required this.stepList,
|
required this.stepList,
|
||||||
required this.recordList,
|
required this.recordList,
|
||||||
@@ -166,7 +164,6 @@ class Recipe {
|
|||||||
isShare: true,
|
isShare: true,
|
||||||
userId: 0,
|
userId: 0,
|
||||||
username: '',
|
username: '',
|
||||||
avatar: '',
|
|
||||||
materialList: [],
|
materialList: [],
|
||||||
stepList: [],
|
stepList: [],
|
||||||
recordList: [],
|
recordList: [],
|
||||||
|
|||||||
@@ -89,7 +89,6 @@ Recipe _$RecipeFromJson(Map<String, dynamic> json) => Recipe(
|
|||||||
isShare: json['isShare'] as bool,
|
isShare: json['isShare'] as bool,
|
||||||
userId: (json['userId'] as num).toInt(),
|
userId: (json['userId'] as num).toInt(),
|
||||||
username: json['username'] as String,
|
username: json['username'] as String,
|
||||||
avatar: json['avatar'] as String,
|
|
||||||
materialList:
|
materialList:
|
||||||
(json['materialList'] as List<dynamic>)
|
(json['materialList'] as List<dynamic>)
|
||||||
.map((e) => RecipeMaterial.fromJson(e as Map<String, dynamic>))
|
.map((e) => RecipeMaterial.fromJson(e as Map<String, dynamic>))
|
||||||
@@ -125,7 +124,6 @@ Map<String, dynamic> _$RecipeToJson(Recipe instance) => <String, dynamic>{
|
|||||||
'isShare': instance.isShare,
|
'isShare': instance.isShare,
|
||||||
'userId': instance.userId,
|
'userId': instance.userId,
|
||||||
'username': instance.username,
|
'username': instance.username,
|
||||||
'avatar': instance.avatar,
|
|
||||||
'materialList': instance.materialList,
|
'materialList': instance.materialList,
|
||||||
'stepList': instance.stepList,
|
'stepList': instance.stepList,
|
||||||
'recordList': instance.recordList,
|
'recordList': instance.recordList,
|
||||||
|
|||||||
@@ -384,7 +384,7 @@ class FoodProvider with ChangeNotifier {
|
|||||||
summaryStats = statsResult;
|
summaryStats = statsResult;
|
||||||
recordStats = recordStatsResult;
|
recordStats = recordStatsResult;
|
||||||
categoryStats = categoryStatsResult;
|
categoryStats = categoryStatsResult;
|
||||||
rankStats = rankStatsResult;
|
rankStats = rankStatsResult.take(15).toList();
|
||||||
|
|
||||||
if (recordStats.isNotEmpty) {
|
if (recordStats.isNotEmpty) {
|
||||||
double sumValue = recordStats.fold(
|
double sumValue = recordStats.fold(
|
||||||
|
|||||||
@@ -7,8 +7,9 @@ import 'package:food_hub_app/models/session.dart';
|
|||||||
class UserProvider with ChangeNotifier {
|
class UserProvider with ChangeNotifier {
|
||||||
late User currentUser = User.getEmpty();
|
late User currentUser = User.getEmpty();
|
||||||
bool isLoading = false;
|
bool isLoading = false;
|
||||||
String error = '';
|
String? error = '';
|
||||||
List<Moment> momentList = [];
|
List<Moment> momentList = [];
|
||||||
|
late User userFormItem;
|
||||||
|
|
||||||
Future<void> refreshUser(int id) async {
|
Future<void> refreshUser(int id) async {
|
||||||
if (isLoading) return;
|
if (isLoading) return;
|
||||||
@@ -48,4 +49,56 @@ class UserProvider with ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void initUserForm(User user) {
|
||||||
|
userFormItem = user;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateUserFormItem({
|
||||||
|
String? username,
|
||||||
|
int? gender,
|
||||||
|
String? phoneNumber,
|
||||||
|
String? email,
|
||||||
|
DateTime? birthDate,
|
||||||
|
String? avatar,
|
||||||
|
List<String>? area,
|
||||||
|
String? address,
|
||||||
|
String? job,
|
||||||
|
List<String>? tags,
|
||||||
|
String? description
|
||||||
|
}) {
|
||||||
|
if (username != null) userFormItem.username = username;
|
||||||
|
if (gender != null) userFormItem.gender = gender;
|
||||||
|
if (phoneNumber != null) userFormItem.phoneNumber = phoneNumber;
|
||||||
|
if (email != null) userFormItem.email = email;
|
||||||
|
if (birthDate != null) userFormItem.birthDate = birthDate;
|
||||||
|
if (avatar != null) userFormItem.avatar = avatar;
|
||||||
|
if (area != null) userFormItem.area = area;
|
||||||
|
if (address != null) userFormItem.address = address;
|
||||||
|
if (job != null) userFormItem.job = job;
|
||||||
|
if (tags != null) userFormItem.tags = tags;
|
||||||
|
if (description != null) userFormItem.description = description;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> handleUser() async {
|
||||||
|
if (isLoading) return true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
isLoading = true;
|
||||||
|
error = null;
|
||||||
|
notifyListeners();
|
||||||
|
|
||||||
|
await updateUserApi(userFormItem.id!, userFormItem);
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
error = '处理数据失败: $e';
|
||||||
|
debugPrint('处理数据失败: $e');
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
isLoading = false;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,12 +38,21 @@ class _LoginPage extends State<LoginPage> {
|
|||||||
|
|
||||||
Future<void> _loadRememberState() async {
|
Future<void> _loadRememberState() async {
|
||||||
bool? isRemember = SPUtil.getBool('isRemember');
|
bool? isRemember = SPUtil.getBool('isRemember');
|
||||||
if (isRemember) {
|
if (isRemember == true) {
|
||||||
setState(() {
|
final username = SPUtil.getString('username');
|
||||||
_isRemember = true;
|
final password = SPUtil.getString('password');
|
||||||
_username = SPUtil.getString('username');
|
|
||||||
_password = SPUtil.getString('password');
|
if (username.isNotEmpty && password.isNotEmpty) {
|
||||||
});
|
setState(() {
|
||||||
|
_isRemember = true;
|
||||||
|
_username = username;
|
||||||
|
_password = password;
|
||||||
|
});
|
||||||
|
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
loginClick();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ class _MomentPageState extends State<MomentPage> {
|
|||||||
|
|
||||||
Widget _buildMomentList(FoodProvider provider) {
|
Widget _buildMomentList(FoodProvider provider) {
|
||||||
return ListView.separated(
|
return ListView.separated(
|
||||||
|
padding: const EdgeInsets.only(bottom: 80),
|
||||||
controller: _scrollController,
|
controller: _scrollController,
|
||||||
itemCount: provider.momentList.length,
|
itemCount: provider.momentList.length,
|
||||||
separatorBuilder: (context, index) => SizedBox(height: 8),
|
separatorBuilder: (context, index) => SizedBox(height: 8),
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ import 'package:food_hub_app/provider/food_provider.dart';
|
|||||||
import 'package:food_hub_app/utils/minio_utils.dart';
|
import 'package:food_hub_app/utils/minio_utils.dart';
|
||||||
import 'package:food_hub_app/widgets/common/form.dart';
|
import 'package:food_hub_app/widgets/common/form.dart';
|
||||||
import 'package:food_hub_app/widgets/common/image.dart';
|
import 'package:food_hub_app/widgets/common/image.dart';
|
||||||
import 'package:liquid_glass_widgets/liquid_glass_widgets.dart';
|
|
||||||
import 'package:liquid_glass_widgets/widgets/containers/glass_card.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class MomentForm extends StatefulWidget {
|
class MomentForm extends StatefulWidget {
|
||||||
@@ -215,14 +213,12 @@ class _MomentFormState extends State<MomentForm> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final provider = context.watch<FoodProvider>();
|
final provider = context.watch<FoodProvider>();
|
||||||
|
|
||||||
return SingleChildScrollView(
|
return AnimatedPadding(
|
||||||
child: Padding(
|
duration: const Duration(milliseconds: 200),
|
||||||
padding: EdgeInsets.all(10),
|
padding: MediaQuery.of(context).viewInsets,
|
||||||
child: GlassCard(
|
child: SingleChildScrollView(
|
||||||
useOwnLayer: true,
|
child: Padding(
|
||||||
settings: LiquidGlassSettings(
|
padding: EdgeInsets.all(16),
|
||||||
glassColor: Theme.of(context).scaffoldBackgroundColor,
|
|
||||||
),
|
|
||||||
child: _buildFormBuilder(provider),
|
child: _buildFormBuilder(provider),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -33,11 +33,14 @@ class _MomentUserPageState extends State<MomentUserPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text('我的朋友圈', style: const TextStyle(color: Colors.white)),
|
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
||||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
title: Text('我的朋友圈', style: Theme.of(context).textTheme.titleLarge),
|
||||||
|
centerTitle: true,
|
||||||
|
automaticallyImplyLeading: false,
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
icon: const Icon(Icons.arrow_back, color: Colors.white),
|
icon: const Icon(Icons.arrow_back),
|
||||||
onPressed: () => Navigator.pop(context),
|
onPressed: () => Navigator.pop(context),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import 'package:flutter_common/widget/common_widget.dart';
|
|||||||
import 'package:flutter_common/widget/dialog_widget.dart';
|
import 'package:flutter_common/widget/dialog_widget.dart';
|
||||||
import 'package:food_hub_app/provider/app_provider.dart';
|
import 'package:food_hub_app/provider/app_provider.dart';
|
||||||
import 'package:food_hub_app/provider/user_provider.dart';
|
import 'package:food_hub_app/provider/user_provider.dart';
|
||||||
|
import 'package:food_hub_app/views/profile_form.dart';
|
||||||
import 'package:food_hub_app/widgets/profile/basic_info.dart';
|
import 'package:food_hub_app/widgets/profile/basic_info.dart';
|
||||||
import 'package:liquid_glass_widgets/liquid_glass_widgets.dart';
|
import 'package:liquid_glass_widgets/liquid_glass_widgets.dart';
|
||||||
import 'package:liquid_glass_widgets/widgets/containers/glass_card.dart';
|
import 'package:liquid_glass_widgets/widgets/containers/glass_card.dart';
|
||||||
@@ -42,11 +43,26 @@ class ProfilePageState extends State<ProfilePage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _onTapInfo(UserProvider provider) {
|
||||||
|
provider.initUserForm(provider.currentUser);
|
||||||
|
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
||||||
|
isScrollControlled: true,
|
||||||
|
shape: const RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
|
||||||
|
),
|
||||||
|
builder: (context) => ProfileForm(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void _onTapMoment() {
|
void _onTapMoment() {
|
||||||
Navigator.pushNamed(context, '/momentUser');
|
Navigator.pushNamed(context, '/momentUser');
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildFunctionButtons(BuildContext context) {
|
Widget _buildFunctionButtons(BuildContext context) {
|
||||||
|
final provider = context.watch<UserProvider>();
|
||||||
final colors = Theme.of(context).colorScheme;
|
final colors = Theme.of(context).colorScheme;
|
||||||
|
|
||||||
return GlassCard(
|
return GlassCard(
|
||||||
@@ -58,10 +74,7 @@ class ProfilePageState extends State<ProfilePage> {
|
|||||||
_buildFunctionButton(
|
_buildFunctionButton(
|
||||||
icon: Icons.account_circle,
|
icon: Icons.account_circle,
|
||||||
text: '基本资料',
|
text: '基本资料',
|
||||||
onTap: () {
|
onTap: () => _onTapInfo(provider),
|
||||||
// 跳转到编辑资料页面
|
|
||||||
// LogUtils.i('点击编辑资料');
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
const Divider(height: 1, thickness: 0.2),
|
const Divider(height: 1, thickness: 0.2),
|
||||||
_buildFunctionButton(
|
_buildFunctionButton(
|
||||||
@@ -155,8 +168,6 @@ class ProfilePageState extends State<ProfilePage> {
|
|||||||
children: [
|
children: [
|
||||||
if (provider.isLoading)
|
if (provider.isLoading)
|
||||||
buildLoadingIndicator()
|
buildLoadingIndicator()
|
||||||
else if (provider.error.isNotEmpty)
|
|
||||||
Text(provider.error)
|
|
||||||
else
|
else
|
||||||
SingleChildScrollView(
|
SingleChildScrollView(
|
||||||
padding: const EdgeInsets.only(bottom: 90),
|
padding: const EdgeInsets.only(bottom: 90),
|
||||||
|
|||||||
251
lib/views/profile_form.dart
Normal file
251
lib/views/profile_form.dart
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_common/widget/dialog_widget.dart';
|
||||||
|
import 'package:flutter_common/widget/loading_widget.dart';
|
||||||
|
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
||||||
|
import 'package:flutter_input_chips/flutter_input_chips.dart';
|
||||||
|
import 'package:form_builder_validators/form_builder_validators.dart';
|
||||||
|
import 'package:food_hub_app/provider/user_provider.dart';
|
||||||
|
import 'package:food_hub_app/widgets/common/form.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class ProfileForm extends StatefulWidget {
|
||||||
|
const ProfileForm({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ProfileForm> createState() => _ProfileFormState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ProfileFormState extends State<ProfileForm> {
|
||||||
|
final _formKey = GlobalKey<FormBuilderState>();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildFormBuilder(UserProvider provider) {
|
||||||
|
final double sizeBoxHeight = 8;
|
||||||
|
|
||||||
|
return FormBuilder(
|
||||||
|
key: _formKey,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
buildFormLabel(context: context, text: '用户名', isRequired: true),
|
||||||
|
SizedBox(height: sizeBoxHeight),
|
||||||
|
FormBuilderTextField(
|
||||||
|
name: 'username',
|
||||||
|
initialValue: provider.userFormItem.username,
|
||||||
|
onChanged: (value) {
|
||||||
|
provider.updateUserFormItem(username: value);
|
||||||
|
},
|
||||||
|
decoration: buildInputDecoration(
|
||||||
|
context: context,
|
||||||
|
hintText: '请输入用户名',
|
||||||
|
),
|
||||||
|
validator: FormBuilderValidators.required(errorText: '请输入用户名'),
|
||||||
|
),
|
||||||
|
SizedBox(height: sizeBoxHeight),
|
||||||
|
|
||||||
|
buildFormLabel(context: context, text: '性别', isRequired: true),
|
||||||
|
SizedBox(height: sizeBoxHeight),
|
||||||
|
FormBuilderDropdown<int>(
|
||||||
|
name: 'gender',
|
||||||
|
initialValue: provider.userFormItem.gender,
|
||||||
|
decoration: buildInputDecoration(
|
||||||
|
context: context,
|
||||||
|
hintText: '请选择性别',
|
||||||
|
),
|
||||||
|
items: const [
|
||||||
|
DropdownMenuItem(value: 1, child: Text('男')),
|
||||||
|
DropdownMenuItem(value: 2, child: Text('女')),
|
||||||
|
],
|
||||||
|
onChanged: (value) {
|
||||||
|
provider.updateUserFormItem(gender: value);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
SizedBox(height: sizeBoxHeight),
|
||||||
|
|
||||||
|
buildFormLabel(context: context, text: '手机号', isRequired: true),
|
||||||
|
SizedBox(height: sizeBoxHeight),
|
||||||
|
FormBuilderTextField(
|
||||||
|
name: 'phoneNumber',
|
||||||
|
initialValue: provider.userFormItem.phoneNumber,
|
||||||
|
keyboardType: TextInputType.phone,
|
||||||
|
decoration: buildInputDecoration(
|
||||||
|
context: context,
|
||||||
|
hintText: '请输入手机号',
|
||||||
|
),
|
||||||
|
onChanged: (value) {
|
||||||
|
provider.updateUserFormItem(phoneNumber: value);
|
||||||
|
},
|
||||||
|
validator: FormBuilderValidators.compose([
|
||||||
|
FormBuilderValidators.required(errorText: '请输入手机号'),
|
||||||
|
FormBuilderValidators.match(
|
||||||
|
RegExp(r'^1[3-9]\d{9}$'),
|
||||||
|
errorText: '请输入正确的11位手机号',
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
SizedBox(height: sizeBoxHeight),
|
||||||
|
|
||||||
|
buildFormLabel(context: context, text: '邮箱', isRequired: true),
|
||||||
|
SizedBox(height: sizeBoxHeight),
|
||||||
|
FormBuilderTextField(
|
||||||
|
name: 'email',
|
||||||
|
initialValue: provider.userFormItem.email,
|
||||||
|
keyboardType: TextInputType.emailAddress,
|
||||||
|
decoration: buildInputDecoration(
|
||||||
|
context: context,
|
||||||
|
hintText: '请输入邮箱',
|
||||||
|
),
|
||||||
|
onChanged: (value) {
|
||||||
|
provider.updateUserFormItem(email: value);
|
||||||
|
},
|
||||||
|
validator: FormBuilderValidators.compose([
|
||||||
|
FormBuilderValidators.email(errorText: '邮箱格式不正确'),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
SizedBox(height: sizeBoxHeight),
|
||||||
|
|
||||||
|
buildFormLabel(context: context, text: '出生日期', isRequired: true),
|
||||||
|
SizedBox(height: sizeBoxHeight),
|
||||||
|
FormBuilderDateTimePicker(
|
||||||
|
name: 'birthDate',
|
||||||
|
initialValue: provider.userFormItem.birthDate,
|
||||||
|
inputType: InputType.date,
|
||||||
|
format: DateFormat('yyyy-MM-dd'),
|
||||||
|
firstDate: DateTime(1900),
|
||||||
|
lastDate: DateTime.now(),
|
||||||
|
decoration: buildInputDecoration(
|
||||||
|
context: context,
|
||||||
|
hintText: '请选择出生日期',
|
||||||
|
),
|
||||||
|
onChanged: (value) {
|
||||||
|
provider.updateUserFormItem(birthDate: value);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
SizedBox(height: sizeBoxHeight),
|
||||||
|
|
||||||
|
buildFormLabel(context: context, text: '详细地址', isRequired: false),
|
||||||
|
SizedBox(height: sizeBoxHeight),
|
||||||
|
FormBuilderTextField(
|
||||||
|
name: 'address',
|
||||||
|
initialValue: provider.userFormItem.address,
|
||||||
|
decoration: buildInputDecoration(
|
||||||
|
context: context,
|
||||||
|
hintText: '请输入详细地址',
|
||||||
|
),
|
||||||
|
onChanged: (value) {
|
||||||
|
provider.updateUserFormItem(address: value);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
SizedBox(height: sizeBoxHeight),
|
||||||
|
|
||||||
|
buildFormLabel(context: context, text: '职业', isRequired: false),
|
||||||
|
SizedBox(height: sizeBoxHeight),
|
||||||
|
FormBuilderTextField(
|
||||||
|
name: 'job',
|
||||||
|
initialValue: provider.userFormItem.job,
|
||||||
|
decoration: buildInputDecoration(
|
||||||
|
context: context,
|
||||||
|
hintText: '请输入职业',
|
||||||
|
),
|
||||||
|
onChanged: (value) {
|
||||||
|
provider.updateUserFormItem(job: value);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
SizedBox(height: sizeBoxHeight),
|
||||||
|
|
||||||
|
buildFormLabel(context: context, text: '标签', isRequired: false),
|
||||||
|
SizedBox(height: sizeBoxHeight),
|
||||||
|
FormBuilderField<List<String>>(
|
||||||
|
name: 'tags',
|
||||||
|
initialValue: provider.userFormItem.tags,
|
||||||
|
validator: FormBuilderValidators.minLength(
|
||||||
|
1,
|
||||||
|
errorText: '至少添加一个标签',
|
||||||
|
),
|
||||||
|
builder: (FormFieldState<List<String>> field) {
|
||||||
|
return FlutterInputChips(
|
||||||
|
padding: EdgeInsets.all(0),
|
||||||
|
initialValue: field.value ?? [],
|
||||||
|
onChanged: (value) {
|
||||||
|
provider.updateUserFormItem(tags: value);
|
||||||
|
},
|
||||||
|
inputDecoration: buildInputDecoration(
|
||||||
|
context: context,
|
||||||
|
hintText: '请输入标签,多个标签用回车键隔开',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
SizedBox(height: sizeBoxHeight),
|
||||||
|
|
||||||
|
buildFormLabel(context: context, text: '简介', isRequired: false),
|
||||||
|
SizedBox(height: sizeBoxHeight),
|
||||||
|
FormBuilderTextField(
|
||||||
|
name: 'description',
|
||||||
|
initialValue: provider.userFormItem.description,
|
||||||
|
decoration: buildInputDecoration(
|
||||||
|
context: context,
|
||||||
|
hintText: '请输入简介',
|
||||||
|
),
|
||||||
|
onChanged: (value) {
|
||||||
|
provider.updateUserFormItem(description: value);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
SizedBox(height: sizeBoxHeight),
|
||||||
|
|
||||||
|
buildFormButtonGroup(
|
||||||
|
context: context,
|
||||||
|
isShowDelete: false,
|
||||||
|
onConfirm: () => _submitForm(provider),
|
||||||
|
onDelete: () => {},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 提交表单
|
||||||
|
void _submitForm(UserProvider provider) async {
|
||||||
|
if (_formKey.currentState?.saveAndValidate() ?? false) {
|
||||||
|
LoadingDialog.show(context, message: '提交中');
|
||||||
|
|
||||||
|
final result = await provider.handleUser();
|
||||||
|
if (result == true) {
|
||||||
|
LoadingDialog.hide(context);
|
||||||
|
|
||||||
|
showSuccessTip(context, '更新信息成功');
|
||||||
|
|
||||||
|
Future.delayed(Duration(milliseconds: 1500), () {
|
||||||
|
if (mounted) {
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
LoadingDialog.hide(context);
|
||||||
|
showErrorTip(context, '更新信息失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final provider = context.watch<UserProvider>();
|
||||||
|
|
||||||
|
return AnimatedPadding(
|
||||||
|
duration: const Duration(milliseconds: 200),
|
||||||
|
padding: MediaQuery.of(context).viewInsets,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(16),
|
||||||
|
child: _buildFormBuilder(provider),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -99,8 +99,6 @@ class ProfileUserPageState extends State<ProfileUserPage> {
|
|||||||
children: [
|
children: [
|
||||||
if (provider.isLoading)
|
if (provider.isLoading)
|
||||||
buildLoadingIndicator()
|
buildLoadingIndicator()
|
||||||
else if (provider.error.isNotEmpty)
|
|
||||||
Text(provider.error)
|
|
||||||
else
|
else
|
||||||
_buildContent(provider),
|
_buildContent(provider),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ import 'package:food_hub_app/widgets/common/index.dart';
|
|||||||
import 'package:form_builder_validators/form_builder_validators.dart';
|
import 'package:form_builder_validators/form_builder_validators.dart';
|
||||||
import 'package:flutter_common/utils/toast_util.dart';
|
import 'package:flutter_common/utils/toast_util.dart';
|
||||||
import 'package:flutter_common/widget/loading_widget.dart';
|
import 'package:flutter_common/widget/loading_widget.dart';
|
||||||
import 'package:liquid_glass_widgets/liquid_glass_widgets.dart';
|
|
||||||
import 'package:liquid_glass_widgets/widgets/containers/glass_card.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class RecipeForm extends StatefulWidget {
|
class RecipeForm extends StatefulWidget {
|
||||||
@@ -551,14 +549,12 @@ class _RecipeFormState extends State<RecipeForm> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final provider = context.watch<FoodProvider>();
|
final provider = context.watch<FoodProvider>();
|
||||||
|
|
||||||
return SingleChildScrollView(
|
return AnimatedPadding(
|
||||||
child: Padding(
|
duration: const Duration(milliseconds: 200),
|
||||||
padding: EdgeInsets.all(10),
|
padding: MediaQuery.of(context).viewInsets,
|
||||||
child: GlassCard(
|
child: SingleChildScrollView(
|
||||||
useOwnLayer: true,
|
child: Padding(
|
||||||
settings: LiquidGlassSettings(
|
padding: EdgeInsets.all(16),
|
||||||
glassColor: Theme.of(context).scaffoldBackgroundColor,
|
|
||||||
),
|
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
_buildStepIndicator(),
|
_buildStepIndicator(),
|
||||||
|
|||||||
@@ -88,9 +88,6 @@ class _RecordPageState extends State<RecordPage> {
|
|||||||
|
|
||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
constraints: BoxConstraints(
|
|
||||||
minHeight: 600,
|
|
||||||
),
|
|
||||||
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
||||||
isScrollControlled: true,
|
isScrollControlled: true,
|
||||||
shape: const RoundedRectangleBorder(
|
shape: const RoundedRectangleBorder(
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import 'package:food_hub_app/utils/minio_utils.dart';
|
|||||||
import 'package:food_hub_app/widgets/common/form.dart';
|
import 'package:food_hub_app/widgets/common/form.dart';
|
||||||
import 'package:food_hub_app/widgets/common/image.dart';
|
import 'package:food_hub_app/widgets/common/image.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:liquid_glass_widgets/liquid_glass_widgets.dart';
|
|
||||||
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
@@ -333,14 +332,12 @@ class _RecordFormState extends State<RecordForm> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final provider = context.watch<FoodProvider>();
|
final provider = context.watch<FoodProvider>();
|
||||||
|
|
||||||
return SingleChildScrollView(
|
return AnimatedPadding(
|
||||||
child: Padding(
|
duration: const Duration(milliseconds: 200),
|
||||||
padding: EdgeInsets.all(10),
|
padding: MediaQuery.of(context).viewInsets,
|
||||||
child: GlassCard(
|
child: SingleChildScrollView(
|
||||||
useOwnLayer: true,
|
child: Padding(
|
||||||
settings: LiquidGlassSettings(
|
padding: EdgeInsets.all(16),
|
||||||
glassColor: Theme.of(context).scaffoldBackgroundColor,
|
|
||||||
),
|
|
||||||
child: _buildFormBuilder(provider),
|
child: _buildFormBuilder(provider),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ Widget buildImageUploadButton({
|
|||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
child: Container(
|
child: Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
height: 250,
|
height: 180,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: colors.surface,
|
color: colors.surface,
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
|||||||
@@ -421,6 +421,14 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.5"
|
version: "0.1.5"
|
||||||
|
flutter_input_chips:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_input_chips
|
||||||
|
sha256: "4b45df0c8b80a23db86850d8f892144dc796f3f6eb13ebd8bcb2d242ec921e22"
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
flutter_lints:
|
flutter_lints:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
name: food_hub_app
|
name: food_hub_app
|
||||||
Reference in New Issue
Block a user