基本完成
This commit is contained in:
155
lib/page/profile/my/my_page.dart
Normal file
155
lib/page/profile/my/my_page.dart
Normal file
@@ -0,0 +1,155 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:food_health/api/dto/user_profile_dto.dart';
|
||||
import 'package:food_health/api/endpoints/profile_api.dart';
|
||||
import 'package:food_health/config/theme/custom_colors.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:remixicon/remixicon.dart';
|
||||
|
||||
import '../../../router/config/route_paths.dart';
|
||||
import 'widget/title_card.dart';
|
||||
import 'widget/user_card.dart';
|
||||
|
||||
class MyPage extends StatefulWidget {
|
||||
const MyPage({super.key});
|
||||
|
||||
@override
|
||||
State<MyPage> createState() => _MyPageState();
|
||||
}
|
||||
|
||||
class _MyPageState extends State<MyPage> with AutomaticKeepAliveClientMixin {
|
||||
UserProfileDto _userProfile = UserProfileDto();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_init();
|
||||
}
|
||||
|
||||
void _init() async {
|
||||
var res = await getUserProfileApi();
|
||||
setState(() {
|
||||
_userProfile = res;
|
||||
});
|
||||
}
|
||||
|
||||
void _goEdit() async {
|
||||
await context.push(RoutePaths.myEdit, extra: _userProfile);
|
||||
_init();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SafeArea(
|
||||
child: ListView(
|
||||
padding: EdgeInsets.all(15),
|
||||
children: [
|
||||
UserCard(
|
||||
detail: _userProfile,
|
||||
onEdit: _goEdit,
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
TitleCard(
|
||||
title: "Food Allergies",
|
||||
icon: Icon(
|
||||
RemixIcons.shield_line,
|
||||
color: Theme.of(context).colorScheme.danger,
|
||||
),
|
||||
child: buildTagList(
|
||||
emptyText: "No food allergies reported",
|
||||
tags: _userProfile.foodAllergiesList,
|
||||
color: Theme.of(context).colorScheme.danger,
|
||||
),
|
||||
),
|
||||
TitleCard(
|
||||
title: "No preferences",
|
||||
icon: Icon(
|
||||
RemixIcons.heart_line,
|
||||
color: Theme.of(context).colorScheme.success,
|
||||
),
|
||||
child: buildTagList(
|
||||
emptyText: "No dietary preferences reported",
|
||||
tags: _userProfile.dietaryPreferencesList,
|
||||
color: Theme.of(context).colorScheme.success,
|
||||
),
|
||||
),
|
||||
TitleCard(
|
||||
title: "Medical Information",
|
||||
icon: Icon(
|
||||
RemixIcons.user_line,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
margin: EdgeInsets.only(bottom: 10),
|
||||
child: Text("Medical Conditions"),
|
||||
),
|
||||
Container(
|
||||
margin: EdgeInsets.only(bottom: 10),
|
||||
child: buildTagList(
|
||||
emptyText: "No medical conditions reported",
|
||||
tags: _userProfile.medicalInformationList,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
margin: EdgeInsets.only(bottom: 10),
|
||||
child: Text("Current Medications"),
|
||||
),
|
||||
buildTagList(
|
||||
emptyText: "No medications reported",
|
||||
tags: _userProfile.currentMedicationsList,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildTagList({
|
||||
required String emptyText,
|
||||
required List<String> tags,
|
||||
required Color color,
|
||||
}) {
|
||||
if (tags.isEmpty) {
|
||||
return Text(
|
||||
emptyText,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.success,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Wrap(
|
||||
spacing: 15,
|
||||
runSpacing: 15,
|
||||
children: tags.map((item) {
|
||||
return Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
||||
decoration: BoxDecoration(
|
||||
color: color.withValues(alpha: 0.2),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: Text(
|
||||
item,
|
||||
style: TextStyle(
|
||||
color: color,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool get wantKeepAlive => true;
|
||||
}
|
||||
50
lib/page/profile/my/widget/title_card.dart
Normal file
50
lib/page/profile/my/widget/title_card.dart
Normal file
@@ -0,0 +1,50 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class TitleCard extends StatelessWidget {
|
||||
final String title;
|
||||
final Widget icon;
|
||||
final Widget child;
|
||||
|
||||
const TitleCard({
|
||||
super.key,
|
||||
required this.title,
|
||||
required this.icon,
|
||||
required this.child,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: EdgeInsets.all(15),
|
||||
margin: EdgeInsets.only(top: 15),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
boxShadow: [
|
||||
BoxShadow(color: Theme.of(context).colorScheme.shadow, blurRadius: 7),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
margin: EdgeInsets.only(bottom: 10),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
spacing: 10,
|
||||
children: [
|
||||
icon,
|
||||
Text(
|
||||
title,
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
child,
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
180
lib/page/profile/my/widget/user_card.dart
Normal file
180
lib/page/profile/my/widget/user_card.dart
Normal file
@@ -0,0 +1,180 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:food_health/api/dto/user_profile_dto.dart';
|
||||
import 'package:food_health/config/theme/custom_colors.dart';
|
||||
import 'package:food_health/providers/app_store.dart';
|
||||
import 'package:food_health/router/config/route_paths.dart';
|
||||
import 'package:food_health/utils/common.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:remixicon/remixicon.dart';
|
||||
|
||||
class UserCard extends StatefulWidget {
|
||||
final UserProfileDto detail;
|
||||
final Function() onEdit;
|
||||
|
||||
const UserCard({
|
||||
super.key,
|
||||
required this.detail,
|
||||
required this.onEdit,
|
||||
});
|
||||
|
||||
@override
|
||||
State<UserCard> createState() => _UserCardState();
|
||||
}
|
||||
|
||||
class _UserCardState extends State<UserCard> {
|
||||
void _goEdit() {
|
||||
widget.onEdit();
|
||||
}
|
||||
|
||||
void _handLogout() {
|
||||
var appStore = context.read<AppStore>();
|
||||
appStore.logout();
|
||||
context.go(RoutePaths.login);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Theme.of(context).colorScheme.shadow,
|
||||
blurRadius: 7,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
avatarWidget(),
|
||||
Container(
|
||||
margin: const EdgeInsets.only(top: 12),
|
||||
child: Text(getNotEmpty(widget.detail.name) ?? "user", style: Theme.of(context).textTheme.titleMedium),
|
||||
),
|
||||
Container(
|
||||
margin: const EdgeInsets.only(top: 5),
|
||||
child: Text(widget.detail.email ?? "", style: Theme.of(context).textTheme.labelMedium),
|
||||
),
|
||||
buildTitledTags(
|
||||
title: "Age Range",
|
||||
tag: getNotEmpty(widget.detail.ageRange),
|
||||
),
|
||||
buildTitledTags(
|
||||
title: "Activity Level",
|
||||
tag: getNotEmpty(widget.detail.activityLevel),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
btnItem(
|
||||
title: "Edit Profile",
|
||||
icon: RemixIcons.edit_box_line,
|
||||
color: Colors.white,
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
Theme.of(context).colorScheme.primary,
|
||||
Theme.of(context).colorScheme.primaryEnd,
|
||||
],
|
||||
),
|
||||
),
|
||||
onTap: _goEdit,
|
||||
),
|
||||
btnItem(
|
||||
title: "Logout",
|
||||
icon: RemixIcons.logout_circle_line,
|
||||
decoration: BoxDecoration(color: Theme.of(context).colorScheme.surfaceContainer),
|
||||
onTap: _handLogout,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
///头像
|
||||
Widget avatarWidget() {
|
||||
return Container(
|
||||
width: 70,
|
||||
height: 70,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
Theme.of(context).colorScheme.primary,
|
||||
Theme.of(context).colorScheme.primaryEnd,
|
||||
],
|
||||
),
|
||||
),
|
||||
child: Icon(
|
||||
RemixIcons.user_3_line,
|
||||
color: Colors.white,
|
||||
size: 30,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
///标题标签
|
||||
Widget buildTitledTags({
|
||||
required String title,
|
||||
String? tag,
|
||||
}) {
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(top: 20),
|
||||
width: double.infinity,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(title, style: Theme.of(context).textTheme.bodyMedium),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 3),
|
||||
margin: const EdgeInsets.only(top: 5),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surfaceContainerLow,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Text(
|
||||
tag ?? "Untitled",
|
||||
style: Theme.of(context).textTheme.labelMedium?.copyWith(
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
///按钮
|
||||
Widget btnItem({
|
||||
required String title,
|
||||
required IconData icon,
|
||||
required BoxDecoration decoration,
|
||||
Color color = Colors.black,
|
||||
required Function() onTap,
|
||||
}) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
margin: const EdgeInsets.only(top: 15),
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
decoration: decoration.copyWith(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(icon, size: 20, color: color),
|
||||
SizedBox(width: 10),
|
||||
Text(
|
||||
title,
|
||||
style: TextStyle(color: color, fontWeight: FontWeight.w500),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user