293 lines
8.0 KiB
Dart
293 lines
8.0 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
|
import 'package:food_health/api/dto/profile_options_dto.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:food_health/page/profile/edit/widget/food_allergies.dart';
|
|
import 'package:food_health/widgets/common/app_backend.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
import 'package:remixicon/remixicon.dart';
|
|
|
|
import 'data/state.dart';
|
|
import 'widget/dietary_preferences.dart';
|
|
import 'widget/health_profile.dart';
|
|
|
|
class MyEditPage extends StatefulWidget {
|
|
final UserProfileDto userProfile;
|
|
|
|
const MyEditPage({super.key, required this.userProfile});
|
|
|
|
@override
|
|
State<MyEditPage> createState() => _MyEditPageState();
|
|
}
|
|
|
|
class _MyEditPageState extends State<MyEditPage> {
|
|
late SelectionState selectionState;
|
|
|
|
List<ProfileOptionDto> _options = [];
|
|
|
|
var _loading = true;
|
|
|
|
///步骤
|
|
var _step = 0;
|
|
|
|
var stepList = [
|
|
StepItem(
|
|
title: "Food Allergies",
|
|
icon: RemixIcons.shield_line,
|
|
subTitle: "Help us keep you safe by telling us about your allergies",
|
|
),
|
|
StepItem(
|
|
title: "Dietary Preferences",
|
|
icon: RemixIcons.heart_line,
|
|
subTitle: "What dietary restrictions or preferences do you follow?",
|
|
),
|
|
StepItem(
|
|
title: "Health Profile",
|
|
icon: RemixIcons.user_line,
|
|
subTitle: "Share relevant health information for personalized recommendations",
|
|
),
|
|
];
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_init();
|
|
}
|
|
|
|
void _init() async {
|
|
selectionState = SelectionState(widget.userProfile);
|
|
var res = await getProfileOptionsApi();
|
|
setState(() {
|
|
_options = res;
|
|
_loading = false;
|
|
});
|
|
}
|
|
|
|
///设置步骤
|
|
void _handStep(bool isNext) {
|
|
if (_step == 2 && isNext) {
|
|
_submit();
|
|
return;
|
|
}
|
|
setState(() {
|
|
_step = (_step + (isNext ? 1 : -1)).clamp(0, 2);
|
|
});
|
|
}
|
|
|
|
void _submit() async {
|
|
EasyLoading.show(
|
|
status: 'Saving…',
|
|
maskType: EasyLoadingMaskType.clear,
|
|
);
|
|
await updateProfileApi(selectionState.userProfile);
|
|
EasyLoading.dismiss();
|
|
context.pop(true);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
if (_loading) {
|
|
return Center(child: CircularProgressIndicator());
|
|
}
|
|
return Scaffold(
|
|
body: AppBackend(
|
|
child: ListView(
|
|
padding: EdgeInsets.only(top: 30),
|
|
children: [
|
|
buildHeader(),
|
|
buildStep(),
|
|
buildStepInfo(),
|
|
SelectionProvider(
|
|
notifier: selectionState,
|
|
child: Builder(
|
|
builder: (context) {
|
|
if (_step == 0) {
|
|
return FoodAllergies(
|
|
options: _options,
|
|
);
|
|
} else if (_step == 1) {
|
|
return DietaryPreferences(
|
|
options: _options,
|
|
);
|
|
} else if (_step == 2) {
|
|
return HealthProfile(
|
|
options: _options,
|
|
);
|
|
}
|
|
return SizedBox();
|
|
},
|
|
),
|
|
),
|
|
Container(
|
|
margin: EdgeInsets.only(top: 30),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Opacity(
|
|
opacity: _step == 0 ? 0.4 : 1,
|
|
child: buildItemButton(
|
|
title: "Previous",
|
|
color: Colors.black,
|
|
decoration: BoxDecoration(
|
|
color: Theme.of(context).colorScheme.surfaceContainer,
|
|
),
|
|
onTap: () {
|
|
_handStep(false);
|
|
},
|
|
),
|
|
),
|
|
buildItemButton(
|
|
title: _step == 2 ? "Complete Setup" : "Continue",
|
|
decoration: BoxDecoration(
|
|
color: _step == 2 ? Theme.of(context).colorScheme.success : null,
|
|
gradient: _step == 2
|
|
? null
|
|
: LinearGradient(
|
|
colors: [
|
|
Theme.of(context).colorScheme.primary,
|
|
Theme.of(context).colorScheme.primaryEnd,
|
|
],
|
|
),
|
|
),
|
|
onTap: () {
|
|
_handStep(true);
|
|
},
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
///构建顶部
|
|
Widget buildHeader() {
|
|
return Column(
|
|
children: [
|
|
Text(
|
|
"Welcome to FoodSafe",
|
|
style: Theme.of(context).textTheme.titleLarge,
|
|
),
|
|
Container(
|
|
margin: EdgeInsets.only(top: 5),
|
|
child: Text(
|
|
"Let's personalize your food safety experience",
|
|
style: Theme.of(context).textTheme.labelMedium,
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
///步骤条
|
|
Widget buildStep() {
|
|
return Container(
|
|
margin: EdgeInsets.only(top: 20),
|
|
child: Row(
|
|
spacing: 10,
|
|
children: stepList.asMap().entries.map((entre) {
|
|
//数据
|
|
var item = entre.value;
|
|
var index = entre.key;
|
|
var isLast = index == stepList.length - 1;
|
|
//颜色
|
|
var selectColor = Theme.of(context).colorScheme.primary;
|
|
var unselectedColor = Theme.of(context).colorScheme.surfaceContainerHigh;
|
|
return Expanded(
|
|
flex: isLast ? 0 : 1,
|
|
child: Row(
|
|
spacing: 10,
|
|
children: [
|
|
Container(
|
|
width: 50,
|
|
height: 50,
|
|
decoration: BoxDecoration(
|
|
color: _step >= index ? selectColor : unselectedColor,
|
|
shape: BoxShape.circle,
|
|
),
|
|
child: Icon(
|
|
item.icon,
|
|
color: _step >= index ? Colors.white : Color(0xff9ca3af),
|
|
),
|
|
),
|
|
|
|
Visibility(
|
|
visible: !isLast,
|
|
child: Expanded(
|
|
child: Container(
|
|
height: 3,
|
|
color: _step > index ? selectColor : unselectedColor,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}).toList(),
|
|
),
|
|
);
|
|
}
|
|
|
|
///步骤条信息
|
|
Widget buildStepInfo() {
|
|
var stepInfo = stepList[_step];
|
|
return Container(
|
|
margin: EdgeInsets.only(top: 20, bottom: 30),
|
|
child: Column(
|
|
children: [
|
|
Text(
|
|
stepInfo.title,
|
|
style: Theme.of(context).textTheme.titleMedium,
|
|
),
|
|
Container(
|
|
margin: EdgeInsets.only(top: 5),
|
|
child: Text(
|
|
stepInfo.subTitle,
|
|
style: Theme.of(context).textTheme.labelMedium,
|
|
textAlign: TextAlign.center,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
///item按钮
|
|
Widget buildItemButton({
|
|
required String title,
|
|
Color color = Colors.white,
|
|
required BoxDecoration decoration,
|
|
required Function() onTap,
|
|
}) {
|
|
return InkWell(
|
|
onTap: onTap,
|
|
child: Container(
|
|
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 20),
|
|
decoration: decoration.copyWith(
|
|
borderRadius: BorderRadius.circular(8),
|
|
),
|
|
child: Text(
|
|
title,
|
|
style: TextStyle(color: color),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class StepItem {
|
|
final IconData icon;
|
|
final String title;
|
|
final String subTitle;
|
|
|
|
StepItem({
|
|
required this.icon,
|
|
required this.title,
|
|
required this.subTitle,
|
|
});
|
|
}
|