This commit is contained in:
zhutao
2025-09-08 15:30:09 +08:00
parent 193d29b0ce
commit 4623094bad
15 changed files with 374 additions and 246 deletions

View File

@@ -1,9 +1,9 @@
class PlanStepDto { class PlanStepDto {
num? id; int? id;
String? stepIcon; String? stepIcon;
String? stepContent; String? stepContent;
String? stepExplain; String? stepExplain;
num? stepStatus; int? stepStatus;
PlanStepDto({this.id, this.stepIcon, this.stepContent, this.stepExplain, this.stepStatus}); PlanStepDto({this.id, this.stepIcon, this.stepContent, this.stepExplain, this.stepStatus});

View File

@@ -2,6 +2,8 @@ import 'package:plan/api/dto/plan_detail_dto.dart';
import 'package:plan/api/dto/plan_item_dto.dart'; import 'package:plan/api/dto/plan_item_dto.dart';
import 'package:plan/api/network/request.dart'; import 'package:plan/api/network/request.dart';
import '../../data/models/plan_acttion_type.dart';
///初始化计划 ///初始化计划
Future<int> initPlanApi(String need, int agentId) async { Future<int> initPlanApi(String need, int agentId) async {
var res = await Request().post("/plan/init", { var res = await Request().post("/plan/init", {
@@ -56,3 +58,28 @@ Future<void> deletePlanApi(int planId) async {
"plan_id": planId, "plan_id": planId,
}); });
} }
///编辑用户计划步骤
Future<void> editPlanStepApi(
int planId, {
required PlanActionType act,
int? stepId,
String? content,
String? explain,
}) async {
await Request().post("/plan/edit_plan_steps_info", {
"plan_id": planId,
"act": act.value,
"step_id": stepId,
"step_content": content,
"step_explain": explain,
});
}
///修改步骤顺序
Future<void> editPlanStepOrderApi(int planId,List<PlanStepDto> list) async {
await Request().post("/plan/change_plan_steps", {
"plan_id": planId,
"steps": list.map((e) => e.toJson()).toList(),
});
}

View File

@@ -0,0 +1,10 @@
enum PlanActionType {
delete(1), //删除
complete(2), //完成
edit(3), //编辑
completeAll(99); //全部完成
final int value;
const PlanActionType(this.value);
}

View File

@@ -12,7 +12,7 @@ class PlanFormCard extends StatefulWidget {
} }
class _PlanFormCardState extends State<PlanFormCard> { class _PlanFormCardState extends State<PlanFormCard> {
final TextEditingController _inputController = TextEditingController(text: ""); final TextEditingController _inputController = TextEditingController(text: "刷牙");
void _handSubmit() { void _handSubmit() {
if (_inputController.text.isEmpty) { if (_inputController.text.isEmpty) {

View File

@@ -0,0 +1,80 @@
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';
import '../../widgets/edit_desc_dialog.dart';
import '../viewmodel/plan_detail_store.dart';
class BarActions extends StatefulWidget {
final PlanDetailStore store;
const BarActions({super.key, required this.store});
@override
State<BarActions> createState() => _BarActionsState();
}
class _BarActionsState extends State<BarActions> {
///popup菜单
void _onPopupActionSelected(String value) {
if (value == 'edit_step') {
widget.store.setEdit(true);
} else if (value == 'edit_desc') {
showEditDescDialog(
context,
value: widget.store.planDetail.summary ?? "",
onConfirm: (value) async {
widget.store.updatePlanDetail((dto) {
dto.summary = value;
});
await editPlanSummaryApi(int.parse(widget.store.planId), value);
},
);
}
}
///取消编辑
void _cancelEdit() {
widget.store.setEdit(false);
}
@override
Widget build(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.min, // 关键Row 只占实际内容宽度
children: [
AnimatedSwitcher(
duration: Duration(milliseconds: 300),
transitionBuilder: (child, animation) {
// 仅使用渐变动画
return FadeTransition(
opacity: animation,
child: child,
);
},
child: widget.store.isEdit
? InkWell(
onTap: _cancelEdit,
child: Icon(RemixIcons.check_fill),
)
: PopupAction(
onSelected: _onPopupActionSelected,
items: [
PopupMenuItem(
value: 'edit_step',
child: Text("编辑步骤"),
),
PopupMenuItem(
value: 'edit_desc',
child: Text("编辑摘要"),
),
],
child: Icon(RemixIcons.more_fill),
),
),
],
);
}
}

View File

@@ -1,12 +1,10 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.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/page/plan/detail/viewmodel/plan_detail_store.dart';
import 'package:plan/theme/decorations/app_shadows.dart'; import 'package:plan/theme/decorations/app_shadows.dart';
import 'package:plan/widgets/ui_kit/popup/popup_action.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:remixicon/remixicon.dart';
import '../widgets/edit_desc_dialog.dart';
import 'widgets/avatar_card.dart'; import 'widgets/avatar_card.dart';
import 'widgets/coach_message.dart'; import 'widgets/coach_message.dart';
import 'widgets/plan_list.dart'; import 'widgets/plan_list.dart';
@@ -28,7 +26,6 @@ class PlanDetailPage extends StatefulWidget {
} }
class _PlanDetailPageState extends State<PlanDetailPage> { class _PlanDetailPageState extends State<PlanDetailPage> {
bool _isEdit = false;
final ScrollController scrollController = ScrollController(); final ScrollController scrollController = ScrollController();
///store对象 ///store对象
@@ -44,28 +41,6 @@ class _PlanDetailPageState extends State<PlanDetailPage> {
); );
} }
///popup菜单
void _onPopupActionSelected(String value) {
if (value == 'edit_step') {
setState(() {
_isEdit = true;
});
} else if (value == 'edit_desc') {
showEditDescDialog(
context,
value: "你好",
onConfirm: (value) {},
);
}
}
///取消编辑
void _cancelEdit() {
setState(() {
_isEdit = false;
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ChangeNotifierProvider<PlanDetailStore>( return ChangeNotifierProvider<PlanDetailStore>(
@@ -83,9 +58,8 @@ class _PlanDetailPageState extends State<PlanDetailPage> {
child: ScrollBox( child: ScrollBox(
child: Container( child: Container(
decoration: shadowDecoration, decoration: shadowDecoration,
child: CustomScrollView( child: Column(
controller: scrollController, children: [
slivers: [
CoachMessage(), CoachMessage(),
PlanList(), PlanList(),
SuggestedTitle(), SuggestedTitle(),
@@ -104,40 +78,7 @@ class _PlanDetailPageState extends State<PlanDetailPage> {
backgroundColor: Colors.white, backgroundColor: Colors.white,
navigationBar: CupertinoNavigationBar( navigationBar: CupertinoNavigationBar(
middle: Text(store.planDetail.summary ?? ""), middle: Text(store.planDetail.summary ?? ""),
trailing: Row( trailing: BarActions(store: store),
mainAxisSize: MainAxisSize.min, // 关键Row 只占实际内容宽度
children: [
AnimatedSwitcher(
duration: Duration(milliseconds: 300),
transitionBuilder: (child, animation) {
// 仅使用渐变动画
return FadeTransition(
opacity: animation,
child: child,
);
},
child: _isEdit
? InkWell(
onTap: _cancelEdit,
child: Icon(RemixIcons.check_fill),
)
: PopupAction(
onSelected: _onPopupActionSelected,
items: [
PopupMenuItem(
value: 'edit_step',
child: Text("编辑步骤"),
),
PopupMenuItem(
value: 'edit_desc',
child: Text("编辑摘要"),
),
],
child: Icon(RemixIcons.more_fill),
),
),
],
),
), ),
child: child!, child: child!,
); );

View File

@@ -14,7 +14,7 @@ class PlanDetailStore extends ChangeNotifier {
//如果没有id进行初始化 //如果没有id进行初始化
if (planId == "0") { if (planId == "0") {
createPlan(); createPlan();
}else{ } else {
//获取详情 //获取详情
getPlanDetail(); getPlanDetail();
} }
@@ -42,6 +42,15 @@ class PlanDetailStore extends ChangeNotifier {
///计划详情 ///计划详情
PlanDetailDto planDetail = PlanDetailDto(summary: "计划详情"); PlanDetailDto planDetail = PlanDetailDto(summary: "计划详情");
///是否正在编辑
bool isEdit = false;
///切换编辑模式
void setEdit(bool value) {
isEdit = value;
notifyListeners();
}
///流请求工具 ///流请求工具
StreamUtils streamUtils = StreamUtils(); StreamUtils streamUtils = StreamUtils();
@@ -49,7 +58,6 @@ class PlanDetailStore extends ChangeNotifier {
void createPlan() async { void createPlan() async {
var id = await initPlanApi(planContent, 1); var id = await initPlanApi(planContent, 1);
planId = id.toString(); planId = id.toString();
// planId = "3";
///生成摘要--------------------------- ///生成摘要---------------------------
String summary = ""; String summary = "";
@@ -92,9 +100,12 @@ class PlanDetailStore extends ChangeNotifier {
.where((e) => e.contains("[NEXT]")) .where((e) => e.contains("[NEXT]"))
.map((e) => e.replaceAll("[NEXT]", "").trim()) .map((e) => e.replaceAll("[NEXT]", "").trim())
.toList(); .toList();
// 直接覆盖 stepsList // 直接覆盖 stepsList
planDetail.stepsList = sentences.map((s) => PlanStepDto(stepContent: s)).toList(); planDetail.stepsList = sentences
.asMap()
.entries
.map((e) => PlanStepDto(id: e.key, stepContent: e.value))
.toList();
notifyListeners(); notifyListeners();
}, },
); );
@@ -159,4 +170,10 @@ class PlanDetailStore extends ChangeNotifier {
planDetail = await getPlanDetailApi(planId); planDetail = await getPlanDetailApi(planId);
notifyListeners(); notifyListeners();
} }
///更新计划详情
void updatePlanDetail(void Function(PlanDetailDto dto) updater) {
updater(planDetail);
notifyListeners();
}
} }

View File

@@ -14,23 +14,21 @@ class _CoachMessageState extends State<CoachMessage> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
var store = context.read<PlanDetailStore>(); var store = context.read<PlanDetailStore>();
if (store.planContent.isEmpty) { if (store.planContent.isEmpty) {
return SliverToBoxAdapter(); return SizedBox();
} }
return SliverToBoxAdapter( return Container(
child: Container( padding: EdgeInsets.all(20),
padding: EdgeInsets.all(20), child: Column(
child: Column( children: [
children: [ Text(
Text( "你的教练正在拆分",
"你的教练正在拆分", style: Theme.of(context).textTheme.bodyMedium,
style: Theme.of(context).textTheme.bodyMedium, ),
), Text(
Text( '"${store.planContent}"',
'"${store.planContent}"', style: Theme.of(context).textTheme.titleMedium,
style: Theme.of(context).textTheme.titleMedium, ),
), ],
],
),
), ),
); );
} }

View File

@@ -1,5 +1,9 @@
import 'package:animated_reorderable_list/animated_reorderable_list.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:plan/api/dto/plan_detail_dto.dart'; import 'package:plan/api/dto/plan_detail_dto.dart';
import 'package:plan/api/endpoints/plan_api.dart';
import 'package:plan/data/models/plan_acttion_type.dart';
import 'package:plan/page/plan/detail/viewmodel/plan_detail_store.dart'; import 'package:plan/page/plan/detail/viewmodel/plan_detail_store.dart';
import 'package:plan/utils/common.dart'; import 'package:plan/utils/common.dart';
import 'package:plan/widgets/business/delete_row_item.dart'; import 'package:plan/widgets/business/delete_row_item.dart';
@@ -14,143 +18,197 @@ class PlanList extends StatefulWidget {
} }
class _PlanListState extends State<PlanList> { class _PlanListState extends State<PlanList> {
final GlobalKey<SliverAnimatedListState> _listKey = GlobalKey<SliverAnimatedListState>();
List<PlanStepDto> _stepsList = [];
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_initListen();
} }
void _initListen() { ///删除步骤
final store = context.read<PlanDetailStore>(); void _handDelete(int id) async {
//先初始化,只在详情时才会有意义 var store = context.read<PlanDetailStore>();
_stepsList = store.planDetail.stepsList; store.updatePlanDetail((dto) {
store.addListener(() { dto.stepsList = dto.stepsList.where((element) => element.id != id).toList();
final newList = store.planDetail.stepsList; });
await editPlanStepApi(
int.parse(store.planId),
act: PlanActionType.delete,
stepId: id,
);
}
// 找出新增的 item ///确认排序
if (newList.length > _stepsList.length) { void _confirmSort(List<PlanStepDto> list) async {
final addedItems = newList.sublist(_stepsList.length); var store = context.read<PlanDetailStore>();
store.updatePlanDetail((dto) {
dto.stepsList = list;
});
await editPlanStepOrderApi(int.parse(store.planId), list);
}
for (var item in addedItems) { ///确认完成或者取消
final index = _stepsList.length; void _handComplete(int id) async {
_stepsList.add(item); HapticFeedback.vibrate();
var store = context.read<PlanDetailStore>();
// 插入动画 store.updatePlanDetail((dto) {
_listKey.currentState?.insertItem( dto.stepsList = dto.stepsList.map((step) {
index, if (step.id == id) {
duration: Duration(milliseconds: 300), // 只更新匹配的项
step.stepStatus = step.stepStatus == 2 ? 0 : 2;
editPlanStepApi(
int.parse(store.planId),
act: PlanActionType.complete,
stepId: id,
); );
} }
} else { return step;
setState(() { }).toList();
_stepsList = store.planDetail.stepsList;
});
}
}); });
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SliverAnimatedList( final isEdit = context.select<PlanDetailStore, bool>((s) => s.isEdit);
key: _listKey, return Selector<PlanDetailStore, List<String>>(
initialItemCount: _stepsList.length, selector: (_, store) => store.planDetail.stepsList
itemBuilder: (_, index, animation) { .map((e) => '${e.id}_${e.stepExplain}_${e.stepStatus}')
//动画 .toList(),
final curvedAnimation = CurvedAnimation( builder: (context, list, _) {
parent: animation, final list = context.read<PlanDetailStore>().planDetail.stepsList;
curve: Curves.easeInOut, return AnimatedReorderableListView(
); items: list,
return PlanItem( physics: const NeverScrollableScrollPhysics(),
step: _stepsList[index], shrinkWrap: true,
curvedAnimation: curvedAnimation, itemBuilder: (BuildContext context, int index) {
onDelete: (id) {}, var item = list[index];
return PlanItem(
key: ValueKey('${item.id ?? index}_${item.hashCode}'),
step: item,
isEdit: isEdit,
onDelete: _handDelete,
onComplete: _handComplete,
);
},
enterTransition: [SlideInDown()],
exitTransition: [SlideInUp()],
insertDuration: const Duration(milliseconds: 300),
removeDuration: const Duration(milliseconds: 300),
dragStartDelay: const Duration(milliseconds: 300),
onReorder: (int oldIndex, int newIndex) {
setState(() {
final item = list.removeAt(oldIndex);
list.insert(newIndex, item);
_confirmSort(list);
});
},
nonDraggableItems: isEdit ? <PlanStepDto>[] : list,
buildDefaultDragHandles: false,
longPressDraggable: false,
isSameItem: (a, b) => a.stepContent == b.stepContent,
); );
}, },
); );
} }
} }
///计划item
class PlanItem extends StatelessWidget { class PlanItem extends StatelessWidget {
final PlanStepDto step; final PlanStepDto step;
final bool showEdit; final bool isEdit;
final CurvedAnimation curvedAnimation;
final Function(int) onDelete; final Function(int) onDelete;
final Function(int) onComplete;
const PlanItem({ const PlanItem({
super.key, super.key,
required this.step, required this.step,
required this.curvedAnimation, this.isEdit = false,
this.showEdit = false,
required this.onDelete, required this.onDelete,
required this.onComplete,
}); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return FadeTransition( return GestureDetector(
opacity: curvedAnimation, onTap: () {
child: SizeTransition( if (!isEdit) {
sizeFactor: curvedAnimation, onComplete(step.id!);
axis: Axis.vertical, }
child: Container( },
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10), child: Container(
child: DeleteRowItem( padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
showDelete: showEdit, color: Colors.white,
onDelete: () {}, child: DeleteRowItem(
builder: (_, animate) { showDelete: isEdit,
return [ onDelete: () {
Expanded( onDelete(step.id!);
child: Column( },
crossAxisAlignment: CrossAxisAlignment.start, builder: (_, animate) {
children: [ return [
Container( Expanded(
margin: EdgeInsets.only(bottom: 3), child: Column(
child: Text( crossAxisAlignment: CrossAxisAlignment.start,
step.stepContent ?? "", children: [
style: Theme.of(context).textTheme.bodyMedium, Container(
), margin: EdgeInsets.only(bottom: 3),
child: Text(
step.stepContent ?? "",
style: stepTextStyle(context, Theme.of(context).textTheme.bodyMedium),
), ),
AnimatedSwitcher(
duration: Duration(milliseconds: 300),
transitionBuilder: (child, animation) {
return FadeTransition(
opacity: animation,
child: SizeTransition(
sizeFactor: animation,
axis: Axis.vertical,
child: child,
),
);
},
child: getNotEmpty(step.stepExplain) == null
? SizedBox.shrink(key: ValueKey("empty"))
: Text(
step.stepExplain!,
style: Theme.of(context).textTheme.labelSmall,
key: ValueKey(step.stepExplain),
),
),
],
),
),
SizeTransition(
axis: Axis.horizontal,
sizeFactor: animate,
child: Container(
margin: EdgeInsets.only(left: 10),
child: Opacity(
opacity: 0.4,
child: Icon(RemixIcons.menu_line),
), ),
AnimatedSwitcher(
duration: Duration(milliseconds: 300),
transitionBuilder: (child, animation) {
return FadeTransition(
opacity: animation,
child: SizeTransition(
sizeFactor: animation,
axis: Axis.vertical,
child: child,
),
);
},
child: getNotEmpty(step.stepExplain) == null
? SizedBox.shrink(key: ValueKey("empty"))
: Text(
step.stepExplain!,
style: stepTextStyle(
context,
Theme.of(context).textTheme.labelSmall,
),
key: ValueKey(step.stepExplain),
),
),
],
),
),
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),
), ),
), ),
]; ),
}, ];
), },
), ),
), ),
); );
} }
TextStyle? stepTextStyle(BuildContext context, TextStyle? baseStyle) {
if (step.stepStatus == 2) {
return baseStyle?.copyWith(
decoration: TextDecoration.lineThrough,
decorationThickness: 3,
decorationColor: Theme.of(context).colorScheme.onSurfaceVariant,
color: Theme.of(context).colorScheme.onSurfaceVariant,
);
}
return baseStyle;
}
} }

View File

@@ -23,8 +23,9 @@ class ScrollBox extends StatelessWidget {
radius: const Radius.circular(5), radius: const Radius.circular(5),
), ),
child: Scrollbar( child: Scrollbar(
controller: scrollController, child: SingleChildScrollView(
child: child, child: child,
),
), ),
); );
} }

View File

@@ -9,51 +9,48 @@ class SuggestedTitle extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var list = context.select<PlanDetailStore, List<String>>( return Consumer<PlanDetailStore>(
(store) => store.planDetail.suggestionsList, builder: (context, store, _) {
); if (store.planDetail.suggestionsList.isEmpty) {
if (list.isEmpty) { return SizedBox();
return const SliverToBoxAdapter( }
child: SizedBox(), return TweenAnimationBuilder<double>(
); tween: Tween(begin: 0, end: 1), // 从透明到完全显示
} duration: const Duration(milliseconds: 300),
return SliverToBoxAdapter( builder: (context, value, child) {
child: TweenAnimationBuilder<double>( return Opacity(
tween: Tween(begin: 0, end: 1), // 从透明到完全显示 opacity: value,
duration: const Duration(milliseconds: 300), child: child,
builder: (context, value, child) { );
return Opacity( },
opacity: value, child: Container(
child: child, margin: const EdgeInsets.only(top: 20, bottom: 5),
); child: Opacity(
}, opacity: 0.6,
child: Container( child: Row(
margin: const EdgeInsets.only(top: 20, bottom: 5), spacing: 20,
child: Opacity( mainAxisAlignment: MainAxisAlignment.center,
opacity: 0.6, children: [
child: Row( Container(
spacing: 20, width: 15,
mainAxisAlignment: MainAxisAlignment.center, height: 1,
children: [ color: Theme.of(context).colorScheme.surfaceContainerHigh,
Container( ),
width: 15, Text(
height: 1, "额外建议",
color: Theme.of(context).colorScheme.surfaceContainerHigh, style: Theme.of(context).textTheme.titleSmall,
), ),
Text( Container(
"额外建议", width: 15,
style: Theme.of(context).textTheme.titleSmall, height: 1,
), color: Theme.of(context).colorScheme.surfaceContainerHigh,
Container( ),
width: 15, ],
height: 1, ),
color: Theme.of(context).colorScheme.surfaceContainerHigh,
),
],
), ),
), ),
), );
), },
); );
} }
} }
@@ -67,13 +64,14 @@ class SuggestedList extends StatefulWidget {
} }
class _SuggestedListState extends State<SuggestedList> { class _SuggestedListState extends State<SuggestedList> {
final GlobalKey<SliverAnimatedListState> _listKey = GlobalKey<SliverAnimatedListState>(); final GlobalKey<AnimatedListState> _listKey = GlobalKey<AnimatedListState>();
List<String> _suggestionsList = []; List<String> _suggestionsList = [];
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_initListen(); _initListen();
WidgetsBinding.instance.addPostFrameCallback((_) => _initListen());
} }
void _initListen() { void _initListen() {
@@ -82,7 +80,6 @@ class _SuggestedListState extends State<SuggestedList> {
_suggestionsList = store.planDetail.suggestionsList; _suggestionsList = store.planDetail.suggestionsList;
store.addListener(() { store.addListener(() {
final newList = store.planDetail.suggestionsList; final newList = store.planDetail.suggestionsList;
// 找出新增的 item // 找出新增的 item
if (newList.length > _suggestionsList.length) { if (newList.length > _suggestionsList.length) {
final addedItems = newList.sublist(_suggestionsList.length); final addedItems = newList.sublist(_suggestionsList.length);
@@ -107,8 +104,10 @@ class _SuggestedListState extends State<SuggestedList> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SliverAnimatedList( return AnimatedList(
key: _listKey, key: _listKey,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
initialItemCount: _suggestionsList.length, initialItemCount: _suggestionsList.length,
itemBuilder: (_, index, animation) { itemBuilder: (_, index, animation) {
final curvedAnimation = CurvedAnimation( final curvedAnimation = CurvedAnimation(

View File

@@ -2,10 +2,8 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:plan/api/dto/plan_item_dto.dart'; import 'package:plan/api/dto/plan_item_dto.dart';
import 'package:plan/api/endpoints/plan_api.dart'; import 'package:plan/api/endpoints/plan_api.dart';
import 'package:remixicon/remixicon.dart';
import 'widgets/history_item.dart'; import 'widgets/history_item.dart';
import '../../../widgets/ui_kit/popup/popup_action.dart';
import 'widgets/loading_box.dart'; import 'widgets/loading_box.dart';
class PlanHistoryPage extends StatefulWidget { class PlanHistoryPage extends StatefulWidget {
@@ -38,23 +36,11 @@ class _PlanHistoryPageState extends State<PlanHistoryPage> {
}); });
} }
///popup事件
void _onPopupActionSelected(String value) {
switch (value) {
case 'edit':
setState(() {
_isDelete = !_isDelete;
});
break;
}
}
///确认删除 ///确认删除
void _confirmDelete(int id) { void _confirmDelete(int id) {
print(_record.map((e) => e.toJson()));
setState(() { setState(() {
_record.removeWhere((element) => element.id == id); _record.removeWhere((element) => element.id == id);
print(_record.map((e) => e.toJson()));
}); });
} }

View File

@@ -89,6 +89,7 @@ class _DeleteRowItemState extends State<DeleteRowItem> with TickerProviderStateM
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Row( return Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
SizeTransition( SizeTransition(
axis: Axis.horizontal, axis: Axis.horizontal,
@@ -98,6 +99,7 @@ class _DeleteRowItemState extends State<DeleteRowItem> with TickerProviderStateM
onTap: _handleDelete, onTap: _handleDelete,
child: Container( child: Container(
margin: EdgeInsets.only(right: 10), margin: EdgeInsets.only(right: 10),
alignment: Alignment.centerRight,
child: Icon( child: Icon(
RemixIcons.indeterminate_circle_fill, RemixIcons.indeterminate_circle_fill,
color: Colors.red, color: Colors.red,

View File

@@ -1,6 +1,14 @@
# Generated by pub # Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile # See https://dart.dev/tools/pub/glossary#lockfile
packages: packages:
animated_reorderable_list:
dependency: "direct main"
description:
name: animated_reorderable_list
sha256: "5de5cca556a8c9c8f7b65234ae4b683593dc6e167db498744a5e389302f24d13"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.3.0"
args: args:
dependency: transitive dependency: transitive
description: description:

View File

@@ -30,6 +30,7 @@ dependencies:
flutter_image_compress: ^2.4.0 flutter_image_compress: ^2.4.0
cached_network_image: ^3.4.1 cached_network_image: ^3.4.1
intl: ^0.19.0 intl: ^0.19.0
animated_reorderable_list: ^1.3.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: