This commit is contained in:
zhutao
2025-09-09 14:07:38 +08:00
parent 71aa4a6790
commit 900dc025d7
24 changed files with 383 additions and 91 deletions

BIN
assets/image/kbn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1,21 @@
class DailyTipDto {
int? id;
String? title;
String? content;
DailyTipDto({this.id, this.title, this.content});
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map["id"] = id;
map["title"] = title;
map["content"] = content;
return map;
}
DailyTipDto.fromJson(dynamic json) {
id = json["id"] ?? 0;
title = json["title"] ?? "";
content = json["content"] ?? "";
}
}

View File

@@ -24,6 +24,21 @@ class PlanStepDto {
stepExplain = json["step_explain"];
stepStatus = json["step_status"];
}
/// 浅拷贝(只复制字段,不生成新 id
PlanStepDto copyWith({
int? id,
String? stepIcon,
String? stepContent,
String? stepExplain,
int? stepStatus,
}) => PlanStepDto(
id: id ?? this.id,
stepIcon: stepIcon ?? this.stepIcon,
stepContent: stepContent ?? this.stepContent,
stepExplain: stepExplain ?? this.stepExplain,
stepStatus: stepStatus ?? this.stepStatus,
);
}
class PlanDetailDto {

View File

@@ -0,0 +1,8 @@
import 'package:plan/api/dto/daily_tip_dto.dart';
import 'package:plan/api/network/request.dart';
///获取每日一句列表
Future<List<DailyTipDto>> getDailyTipList() async {
var res = await Request().get("/daily_tips");
return (res as List).map((e) => DailyTipDto.fromJson(e)).toList();
}

View File

@@ -15,7 +15,7 @@ Future<int> initPlanApi(String need, int agentId) async {
///保存用户计划
Future<void> savePlanApi({
required String planId,
required int planId,
required String summary,
required String dialog,
required List<PlanStepDto> steps,
@@ -45,7 +45,7 @@ Future<void> editPlanSummaryApi(int planId, String summary) async {
}
///获取计划详情
Future<PlanDetailDto> getPlanDetailApi(String planId) async {
Future<PlanDetailDto> getPlanDetailApi(int planId) async {
var res = await Request().get("/plan/plan_detail", {
"plan_id": planId,
});

View File

@@ -12,7 +12,7 @@ class PlanFormCard extends StatefulWidget {
}
class _PlanFormCardState extends State<PlanFormCard> {
final TextEditingController _inputController = TextEditingController(text: "刷牙");
final TextEditingController _inputController = TextEditingController(text: "");
void _handSubmit() {
if (_inputController.text.isEmpty) {
@@ -36,7 +36,7 @@ class _PlanFormCardState extends State<PlanFormCard> {
top: 56,
child: SizedBox(
height: 100,
child: Image.asset("assets/image/xiaozhi.png"),
child: Image.asset("assets/image/kbn.png"),
),
),
Container(
@@ -48,14 +48,14 @@ class _PlanFormCardState extends State<PlanFormCard> {
children: [
Container(
margin: EdgeInsets.only(bottom: 20),
child: Text("有什么事情你一直在拖延?"),
child: Text("What have you been putting off?"),
),
TextField(
controller: _inputController,
style: Theme.of(context).textTheme.bodyMedium,
maxLength: 40,
decoration: InputDecoration(
hintText: "我躺在床上听歌",
hintText: "Clean the kitchen",
fillColor: Theme.of(context).colorScheme.surfaceContainerLow,
filled: true,
enabledBorder: OutlineInputBorder(
@@ -83,7 +83,7 @@ class _PlanFormCardState extends State<PlanFormCard> {
border: Border.all(color: Colors.black, width: 1.5),
),
child: Text(
"创建计划",
"Create Plan",
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w700,

View File

@@ -1,4 +1,7 @@
import 'package:animated_reorderable_list/animated_reorderable_list.dart';
import 'package:flutter/material.dart';
import 'package:plan/api/dto/daily_tip_dto.dart';
import 'package:plan/api/endpoints/other.dart';
import 'package:remixicon/remixicon.dart';
class QuoteCard extends StatefulWidget {
@@ -9,8 +12,37 @@ class QuoteCard extends StatefulWidget {
}
class _QuoteCardState extends State<QuoteCard> {
List<DailyTipDto> _list = [];
int _currentIndex = 0;
///获取当前语句
DailyTipDto? get currentTip => _list.isEmpty ? null : _list[_currentIndex];
@override
void initState() {
super.initState();
_init();
}
void _init() async {
var res = await getDailyTipList();
setState(() {
_list = res;
});
}
///切换下一条
void _next() {
setState(() {
_currentIndex = (_currentIndex + 1) % _list.length;
});
}
@override
Widget build(BuildContext context) {
if (_list.isEmpty) {
return SizedBox();
}
return Container(
margin: EdgeInsets.only(top: 20),
padding: const EdgeInsets.all(3),
@@ -30,26 +62,27 @@ class _QuoteCardState extends State<QuoteCard> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"每个教练都有什么特长?",
style: Theme.of(context).textTheme.titleSmall,
_fadeText(
currentTip?.title ?? "",
Theme.of(context).textTheme.titleSmall,
),
Container(
margin: EdgeInsets.only(top: 10),
child: Text(
"在主页点击教练可以查看介绍",
style: Theme.of(context).textTheme.labelMedium,
),
SizedBox(height: 10),
_fadeText(
currentTip?.content ?? "",
Theme.of(context).textTheme.labelMedium,
),
Container(
margin: EdgeInsets.only(top: 10),
child: Row(
spacing: 5,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(RemixIcons.arrow_right_circle_line, size: 18),
Text("下一条", style: Theme.of(context).textTheme.bodySmall),
],
GestureDetector(
onTap: _next,
child: Container(
margin: EdgeInsets.only(top: 10),
child: Row(
spacing: 5,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(RemixIcons.arrow_right_circle_line, size: 18),
Text("Next", style: Theme.of(context).textTheme.bodySmall),
],
),
),
),
],
@@ -57,4 +90,40 @@ class _QuoteCardState extends State<QuoteCard> {
),
);
}
///渐变文字动画
Widget _fadeText(String text, TextStyle? style) {
return AnimatedSize(
duration: const Duration(milliseconds: 400),
child: Container(
alignment: Alignment.topLeft,
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 400),
transitionBuilder: (Widget child, Animation<double> animation) {
return FadeTransition(
opacity: animation,
child: child,
);
},
layoutBuilder: (Widget? currentChild, List<Widget> previousChildren) {
return Stack(
children: <Widget>[
if (currentChild != null) currentChild, // 新 child
Positioned(
top: 0,
child: Opacity(
opacity: 0.3,
child: Column(
children: previousChildren,
),
),
),
],
);
},
child: Text(text, key: Key(text), style: style),
),
),
);
}
}

View File

@@ -93,7 +93,7 @@ class _MyPageState extends State<MyPage> {
return CupertinoPageScaffold(
backgroundColor: Colors.white,
navigationBar: CupertinoNavigationBar(
middle: Text("个人资料"),
middle: Text("Profile"),
leading: IconButton(
onPressed: () {
widget.scaffoldKey.currentState?.closeDrawer();
@@ -118,7 +118,7 @@ class _MyPageState extends State<MyPage> {
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
onPressed: _handLogout,
child: Text(
"退出登录",
"Log Out",
style: TextStyle(color: Colors.white, fontSize: 14),
),
),
@@ -126,7 +126,7 @@ class _MyPageState extends State<MyPage> {
CupertinoButton(
onPressed: _handDelete,
child: const Text(
"删除账号",
"Delete Account",
style: TextStyle(color: CupertinoColors.systemRed, fontSize: 14),
),
),

View File

@@ -132,7 +132,7 @@ class _AvatarNameState extends State<AvatarName> {
style: Theme.of(context).textTheme.titleSmall,
),
child: Text(
"教练如何称呼你?",
"What should we call you?",
style: Theme.of(context).textTheme.labelMedium,
),
),
@@ -150,7 +150,7 @@ class _AvatarNameState extends State<AvatarName> {
style: TextStyle(fontSize: 14),
maxLength: 20,
decoration: InputDecoration(
hintText: "输入你的姓名",
hintText: "Enter your name",
isCollapsed: true,
contentPadding: EdgeInsets.symmetric(vertical: 8, horizontal: 10),
enabledBorder: OutlineInputBorder(

View File

@@ -20,9 +20,9 @@ class _ProfileSectionState extends State<ProfileSection> {
final TextEditingController _inputController = TextEditingController();
final List<String> _tips = [
"教练每次为你制定计划时,都会首先参考这里的信息",
"你分享的背景信息越详细,教练就越能为你量身定制,符合你独特情况的行动步骤",
"你可以在这里为教练提需求,比如“我不吃香菜”",
"Whenever your coach creates a plan for you, theyll start by looking at this information.",
"The more details you share, the better your coach can tailor steps that fit your unique situation.",
"You can also add requests here — for example, I dont eat cilantro.",
];
//防抖
@@ -67,7 +67,7 @@ class _ProfileSectionState extends State<ProfileSection> {
children: [
Container(
margin: EdgeInsets.only(bottom: 20),
child: Text("你的画像"),
child: Text("About You"),
),
Container(
margin: EdgeInsets.only(bottom: 20),
@@ -78,7 +78,7 @@ class _ProfileSectionState extends State<ProfileSection> {
style: TextStyle(fontSize: 14, letterSpacing: 1),
onChanged: _onTextChanged,
decoration: InputDecoration(
hintText: "我是19岁女生,刷碗时用洗碗机,请不要按手洗拆解步骤..",
hintText: "Im 19 and always use a dishwasher. Please dont follow the hand-wash disassembly steps.",
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey), // 普通状态
borderRadius: BorderRadius.circular(8),

View File

@@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:plan/api/endpoints/plan_api.dart';
import 'package:plan/widgets/ui_kit/popup/popup_action.dart';
import 'package:remixicon/remixicon.dart';
@@ -29,7 +28,7 @@ class _BarActionsState extends State<BarActions> {
widget.store.updatePlanDetail((dto) {
dto.summary = value;
});
await editPlanSummaryApi(int.parse(widget.store.planId), value);
await editPlanSummaryApi(widget.store.planId, value);
},
);
}
@@ -64,11 +63,11 @@ class _BarActionsState extends State<BarActions> {
items: [
PopupMenuItem(
value: 'edit_step',
child: Text("编辑步骤"),
child: Text("Edit Steps"),
),
PopupMenuItem(
value: 'edit_desc',
child: Text("编辑摘要"),
child: Text("Edit Summary"),
),
],
child: Icon(RemixIcons.more_fill),

View File

@@ -0,0 +1,135 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:plan/api/dto/plan_detail_dto.dart';
class EditPopup extends StatefulWidget {
final PlanStepDto step;
final Function(PlanStepDto) onEdit;
const EditPopup({super.key, required this.step, required this.onEdit});
@override
State<EditPopup> createState() => _EditPopupState();
}
class _EditPopupState extends State<EditPopup> {
///输入框
final TextEditingController _titleController = TextEditingController();
final TextEditingController _descriptionController = TextEditingController();
@override
void initState() {
super.initState();
_titleController.text = widget.step.stepContent ?? "";
_descriptionController.text = widget.step.stepExplain ?? "";
// 监听任何一次输入
_titleController.addListener(_updateSaveButton);
_descriptionController.addListener(_updateSaveButton);
}
///是否允许保存
get isSave => _titleController.text.isNotEmpty && _descriptionController.text.isNotEmpty;
void _updateSaveButton() => setState(() {});
///保存
void _handSave() {
//更新数据
var step = widget.step.copyWith(
stepContent: _titleController.text,
stepExplain: _descriptionController.text,
);
widget.onEdit(step);
context.pop();
}
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(top: 40),
child: Container(
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10),
topRight: Radius.circular(10),
),
),
child: CupertinoPageScaffold(
backgroundColor: Theme.of(context).colorScheme.surfaceContainer,
navigationBar: CupertinoNavigationBar(
middle: Text("Edit Steps"),
leading: CupertinoButton(
padding: EdgeInsets.zero,
onPressed: () {
context.pop();
},
child: Text("Cancel", style: TextStyle(color: CupertinoColors.black)),
),
trailing: CupertinoButton(
padding: EdgeInsets.zero,
onPressed: isSave ? _handSave : null,
child: Text("Save"),
),
),
child: SafeArea(
child: ListView(
padding: EdgeInsets.all(15),
children: [
_smallTitle("STEP DETAILS"),
Container(
padding: EdgeInsets.all(15),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
child: Column(
children: [
_input(_titleController, "Task"),
Divider(),
_input(_descriptionController, "Description"),
],
),
),
],
),
),
),
),
);
}
Widget _smallTitle(String title) {
return Container(
margin: EdgeInsets.only(bottom: 5),
padding: EdgeInsets.only(left: 10),
child: Text(
title,
style: Theme.of(context).textTheme.labelSmall?.copyWith(
fontWeight: FontWeight.w700,
),
),
);
}
///输入框
Widget _input(TextEditingController controller, String hint) {
return TextField(
maxLines: null,
minLines: 3,
// 允许无限换行
keyboardType: TextInputType.multiline,
controller: controller,
style: TextStyle(fontSize: 16),
decoration: InputDecoration(
hintText: hint,
border: InputBorder.none,
isCollapsed: true,
),
);
}
}

View File

@@ -1,10 +1,10 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:plan/page/plan/detail/navigation/bar_actions.dart';
import 'package:plan/page/plan/detail/viewmodel/plan_detail_store.dart';
import 'package:plan/theme/decorations/app_shadows.dart';
import 'package:provider/provider.dart';
import 'other/bar_actions.dart';
import 'widgets/avatar_card.dart';
import 'widgets/coach_message.dart';
import 'widgets/plan_list.dart';
@@ -12,7 +12,7 @@ import 'widgets/scroll_box.dart';
import 'widgets/suggested.dart';
class PlanDetailPage extends StatefulWidget {
final String? id;
final int? id;
final String? planName;
const PlanDetailPage({
@@ -35,7 +35,7 @@ class _PlanDetailPageState extends State<PlanDetailPage> {
void initState() {
super.initState();
store = PlanDetailStore(
planId: widget.id.toString(),
planId: widget.id ?? 0,
planContent: widget.planName ?? "",
scrollController: scrollController,
);

View File

@@ -8,11 +8,11 @@ class PlanDetailStore extends ChangeNotifier {
///构造函数
PlanDetailStore({
this.planContent = "",
this.planId = "",
required this.planId,
required this.scrollController,
}) {
//如果没有id进行初始化
if (planId == "0") {
if (planId == 0) {
createPlan();
} else {
//获取详情
@@ -37,10 +37,10 @@ class PlanDetailStore extends ChangeNotifier {
String planContent = "";
///计划id
String planId = "";
int planId;
///计划详情
PlanDetailDto planDetail = PlanDetailDto(summary: "计划详情");
PlanDetailDto planDetail = PlanDetailDto(summary: "Plan Details");
///是否正在编辑
bool isEdit = false;
@@ -57,7 +57,7 @@ class PlanDetailStore extends ChangeNotifier {
///创建计划
void createPlan() async {
var id = await initPlanApi(planContent, 1);
planId = id.toString();
planId = id;
///生成摘要---------------------------
String summary = "";
@@ -162,7 +162,8 @@ class PlanDetailStore extends ChangeNotifier {
steps: planDetail.stepsList,
suggestions: planDetail.suggestionsList,
);
EasyLoading.showToast("计划创建成功");
await getPlanDetail();
EasyLoading.showToast("Plan created!");
}
///获取详情
@@ -176,4 +177,13 @@ class PlanDetailStore extends ChangeNotifier {
updater(planDetail);
notifyListeners();
}
///更新步骤
void updateStep(PlanStepDto newStep) {
final int index = planDetail.stepsList.indexWhere((e) => e.id == newStep.id);
if (index != -1) {
planDetail.stepsList[index] = newStep; // 引用变了 → 框架感知
notifyListeners();
}
}
}

View File

@@ -94,6 +94,7 @@ class _AvatarCardState extends State<AvatarCard> with SingleTickerProviderStateM
child: Stack(
children: [
Container(
width: double.infinity,
padding: EdgeInsets.all(4),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(3),
@@ -119,7 +120,7 @@ class _AvatarCardState extends State<AvatarCard> with SingleTickerProviderStateM
child: Stack(
alignment: Alignment.bottomCenter,
children: [
Image.asset("assets/image/xiaozhi.png", height: 100),
Image.asset("assets/image/kbn.png", height: 100),
Positioned(
top: 20,
child: Transform.translate(

View File

@@ -21,7 +21,7 @@ class _CoachMessageState extends State<CoachMessage> {
child: Column(
children: [
Text(
"你的教练正在拆分",
"Organizing your plan…",
style: Theme.of(context).textTheme.bodyMedium,
),
Text(

View File

@@ -10,6 +10,8 @@ import 'package:plan/widgets/business/delete_row_item.dart';
import 'package:provider/provider.dart';
import 'package:remixicon/remixicon.dart';
import '../other/edit_popup.dart';
class PlanList extends StatefulWidget {
const PlanList({super.key});
@@ -30,7 +32,7 @@ class _PlanListState extends State<PlanList> {
dto.stepsList = dto.stepsList.where((element) => element.id != id).toList();
});
await editPlanStepApi(
int.parse(store.planId),
store.planId,
act: PlanActionType.delete,
stepId: id,
);
@@ -42,37 +44,56 @@ class _PlanListState extends State<PlanList> {
store.updatePlanDetail((dto) {
dto.stepsList = list;
});
await editPlanStepOrderApi(int.parse(store.planId), list);
await editPlanStepOrderApi(store.planId, list);
}
///确认完成或者取消
void _handComplete(int id) async {
void _handComplete(PlanStepDto newStep) async {
HapticFeedback.vibrate();
var store = context.read<PlanDetailStore>();
newStep.stepStatus = newStep.stepStatus == 2 ? 0 : 2;
//更新数据
store.updateStep(newStep);
//接口更新
editPlanStepApi(
store.planId,
act: PlanActionType.complete,
stepId: newStep.id,
);
}
store.updatePlanDetail((dto) {
dto.stepsList = dto.stepsList.map((step) {
if (step.id == id) {
// 只更新匹配的项
step.stepStatus = step.stepStatus == 2 ? 0 : 2;
editPlanStepApi(
int.parse(store.planId),
act: PlanActionType.complete,
stepId: id,
);
}
return step;
}).toList();
});
///打开编辑
void _handEditDialog(PlanStepDto step) {
showModalBottomSheet(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (_) {
return EditPopup(
step: step,
onEdit: (newStep) {
var store = context.read<PlanDetailStore>();
store.updateStep(newStep);
// 接口
editPlanStepApi(
store.planId,
act: PlanActionType.edit,
stepId: newStep.id,
content: newStep.stepContent,
explain: newStep.stepExplain,
);
},
);
},
);
}
@override
Widget build(BuildContext context) {
final isEdit = context.select<PlanDetailStore, bool>((s) => s.isEdit);
return Selector<PlanDetailStore, List<String>>(
selector: (_, store) => store.planDetail.stepsList
.map((e) => '${e.id}_${e.stepExplain}_${e.stepStatus}')
.toList(),
selector: (_, store) =>
store.planDetail.stepsList.map((e) => e.toJson().toString()).toList(),
builder: (context, list, _) {
final list = context.read<PlanDetailStore>().planDetail.stepsList;
return AnimatedReorderableListView(
@@ -87,6 +108,7 @@ class _PlanListState extends State<PlanList> {
isEdit: isEdit,
onDelete: _handDelete,
onComplete: _handComplete,
onEdit: _handEditDialog,
);
},
enterTransition: [SlideInDown()],
@@ -116,7 +138,8 @@ class PlanItem extends StatelessWidget {
final PlanStepDto step;
final bool isEdit;
final Function(int) onDelete;
final Function(int) onComplete;
final Function(PlanStepDto) onComplete;
final Function(PlanStepDto) onEdit;
const PlanItem({
super.key,
@@ -124,6 +147,7 @@ class PlanItem extends StatelessWidget {
this.isEdit = false,
required this.onDelete,
required this.onComplete,
required this.onEdit,
});
@override
@@ -131,7 +155,7 @@ class PlanItem extends StatelessWidget {
return GestureDetector(
onTap: () {
if (!isEdit) {
onComplete(step.id!);
onComplete(step);
}
},
child: Container(
@@ -184,12 +208,17 @@ class PlanItem extends StatelessWidget {
SizeTransition(
axis: Axis.horizontal,
sizeFactor: animate,
child: Container(
alignment: Alignment.center,
margin: EdgeInsets.only(left: 10),
child: Opacity(
opacity: 0.4,
child: Icon(RemixIcons.menu_line),
child: GestureDetector(
onTap: () {
onEdit(step);
},
child: Container(
alignment: Alignment.center,
margin: EdgeInsets.only(left: 10),
child: Opacity(
opacity: 0.4,
child: Icon(RemixIcons.edit_box_line),
),
),
),
),

View File

@@ -37,7 +37,7 @@ class SuggestedTitle extends StatelessWidget {
color: Theme.of(context).colorScheme.surfaceContainerHigh,
),
Text(
"额外建议",
"Additional Suggestions",
style: Theme.of(context).textTheme.titleSmall,
),
Container(

View File

@@ -36,13 +36,11 @@ class _PlanHistoryPageState extends State<PlanHistoryPage> {
});
}
///确认删除
void _confirmDelete(int id) {
setState(() {
_record.removeWhere((element) => element.id == id);
});
}
@override
@@ -50,7 +48,7 @@ class _PlanHistoryPageState extends State<PlanHistoryPage> {
return CupertinoPageScaffold(
backgroundColor: Theme.of(context).colorScheme.surfaceContainer,
navigationBar: CupertinoNavigationBar(
middle: const Text("计划历史"),
middle: const Text("Plan History"),
),
child: SafeArea(
child: CustomScrollView(
@@ -77,6 +75,7 @@ class _PlanHistoryPageState extends State<PlanHistoryPage> {
item: _record[index],
showDelete: _isDelete,
onDelete: _confirmDelete,
onInit: _onRefresh,
);
},
separatorBuilder: (BuildContext context, int index) {

View File

@@ -5,7 +5,6 @@ import 'package:plan/api/dto/plan_item_dto.dart';
import 'package:plan/api/endpoints/plan_api.dart';
import 'package:plan/router/config/route_paths.dart';
import 'package:plan/utils/format.dart';
import 'package:plan/widgets/business/delete_row_item.dart';
import 'package:remixicon/remixicon.dart';
import '../../widgets/edit_desc_dialog.dart';
@@ -14,12 +13,14 @@ class HistoryItem extends StatefulWidget {
final PlanItemDto item;
final bool showDelete;
final Function(int) onDelete;
final Function() onInit;
const HistoryItem({
super.key,
required this.item,
this.showDelete = false,
required this.onDelete,
required this.onInit,
});
@override
@@ -46,8 +47,9 @@ class _HistoryItemState extends State<HistoryItem> {
}
///跳转详情
void _goDetail() {
context.push(RoutePaths.planDetail(_data.id));
void _goDetail() async{
await context.push(RoutePaths.planDetail(_data.id));
widget.onInit();
}
///编辑摘要
@@ -75,6 +77,7 @@ class _HistoryItemState extends State<HistoryItem> {
@override
Widget build(BuildContext context) {
return CupertinoContextMenu(
enableHapticFeedback: true,
actions: [
// 编辑摘要
CupertinoContextMenuAction(

View File

@@ -84,7 +84,6 @@ class _LoginPageState extends State<LoginPage> {
GoogleSignInAccount? user = await _googleSignIn.authenticate();
var auth = user.authentication;
// var res = await Dio().get("https://oauth2.googleapis.com/tokeninfo?id_token=${auth.idToken}");
//登陆
EasyLoading.show(status: "Logging in...");
var res = await thirdLoginApi(auth.idToken!, OtherLoginType.google);
@@ -118,8 +117,6 @@ class _LoginPageState extends State<LoginPage> {
var res = await thirdLoginApi(credential.identityToken!, OtherLoginType.apple);
EasyLoading.dismiss();
_onLogin(res);
print('Apple Credential: ${credential.identityToken}');
print('Apple Email: ${credential.email}');
} catch (e) {
print('Error during Apple sign-in: $e');
}

View File

@@ -24,7 +24,10 @@ class AgreementBox extends StatelessWidget {
recognizer: TapGestureRecognizer()
..onTap = () => context.push(
RoutePaths.agreement,
extra: {"title": "Terms of Service", "url": "https://support.curain.ai/privacy/foodcura/terms_service.html"},
extra: {
"title": "Terms of Service",
"url": "https://support.curain.ai/privacy/plancura/terms_service.html",
},
),
),
const TextSpan(text: " and "),
@@ -34,7 +37,10 @@ class AgreementBox extends StatelessWidget {
recognizer: TapGestureRecognizer()
..onTap = () => context.push(
RoutePaths.agreement,
extra: {"title": "Privacy", "url": "https://support.curain.ai/privacy/foodcura/privacy_policy.html"},
extra: {
"title": "Privacy",
"url": "https://support.curain.ai/privacy/plancura/privacy_policy.html",
},
),
),
const TextSpan(text: "."),

View File

@@ -17,7 +17,7 @@ List<RouteType> planRoutes = [
final extraMap = state.extra as Map<String, dynamic>?;
return PlanDetailPage(
id: id,
id: int.parse(id ?? "0"),
planName: extraMap?['name'],
);
},