From 730db5c94adbe4f1ec2cfd0fe1e945c0fa16165c Mon Sep 17 00:00:00 2001 From: Simon Ding Date: Tue, 23 Jul 2024 22:22:53 +0800 Subject: [PATCH] feat: seperate active and archived activities --- server/activity.go | 8 +++ ui/lib/activity.dart | 115 ++++++++++++++++++++++++--------- ui/lib/providers/activity.dart | 16 +++-- 3 files changed, 101 insertions(+), 38 deletions(-) diff --git a/server/activity.go b/server/activity.go index ce4399e..fa9e880 100644 --- a/server/activity.go +++ b/server/activity.go @@ -4,6 +4,7 @@ import ( "fmt" "polaris/ent" "polaris/ent/episode" + "polaris/ent/history" "polaris/log" "polaris/pkg/utils" "strconv" @@ -18,9 +19,16 @@ type Activity struct { } func (s *Server) GetAllActivities(c *gin.Context) (interface{}, error) { + q := c.Query("status") his := s.db.GetHistories() var activities = make([]Activity, 0, len(his)) for _, h := range his { + if q == "active" && (h.Status != history.StatusRunning && h.Status != history.StatusUploading) { + continue //active downloads + } else if q == "archive" && (h.Status == history.StatusRunning || h.Status == history.StatusUploading) { + continue //archived downloads + } + a := Activity{ History: h, } diff --git a/ui/lib/activity.dart b/ui/lib/activity.dart index bd41883..08db836 100644 --- a/ui/lib/activity.dart +++ b/ui/lib/activity.dart @@ -5,39 +5,88 @@ import 'package:ui/providers/activity.dart'; import 'package:ui/utils.dart'; import 'package:ui/widgets/progress_indicator.dart'; -class ActivityPage extends ConsumerWidget { +class ActivityPage extends ConsumerStatefulWidget { + const ActivityPage({super.key}); static const route = "/activities"; - const ActivityPage({super.key}); @override - Widget build(BuildContext context, WidgetRef ref) { - var activitiesWatcher = ref.watch(activitiesDataProvider); + _ActivityPageState createState() => _ActivityPageState(); +} - return activitiesWatcher.when( - data: (activities) { - return SingleChildScrollView( - child: PaginatedDataTable( - rowsPerPage: 10, - columns: const [ - DataColumn(label: Text("#"), numeric: true), - DataColumn(label: Text("名称")), - DataColumn(label: Text("开始时间")), - DataColumn(label: Text("状态")), - DataColumn(label: Text("操作")) - ], - source: ActivityDataSource( - activities: activities, onDelete: onDelete(ref)), - ), - ); - }, - error: (err, trace) => Text("$err"), - loading: () => const MyProgressIndicator()); +class _ActivityPageState extends ConsumerState + with TickerProviderStateMixin { + late TabController _nestedTabController; + @override + void initState() { + super.initState(); + _nestedTabController = new TabController(length: 2, vsync: this); } - Function(int) onDelete(WidgetRef ref) { + @override + void dispose() { + super.dispose(); + _nestedTabController.dispose(); + } + + int selectedTab = 0; + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + TabBar( + controller: _nestedTabController, + isScrollable: true, + onTap: (value) { + setState(() { + selectedTab = value; + }); + }, + tabs: const [ + Tab( + text: "下载中", + ), + Tab( + text: "历史记录", + ), + ], + ), + Builder(builder: (context) { + var activitiesWatcher = ref.watch(activitiesDataProvider("active")); + if (selectedTab == 1) { + activitiesWatcher = ref.watch(activitiesDataProvider("archive")); + } + + return activitiesWatcher.when( + data: (activities) { + return SingleChildScrollView( + child: PaginatedDataTable( + rowsPerPage: 10, + columns: const [ + DataColumn(label: Text("#"), numeric: true), + DataColumn(label: Text("名称")), + DataColumn(label: Text("开始时间")), + DataColumn(label: Text("状态")), + DataColumn(label: Text("操作")) + ], + source: ActivityDataSource( + activities: activities, + onDelete: selectedTab == 0 ? onDelete() : null), + ), + ); + }, + error: (err, trace) => Text("$err"), + loading: () => const MyProgressIndicator()); + }) + ], + ); + } + + Function(int) onDelete() { return (id) { ref - .read(activitiesDataProvider.notifier) + .read(activitiesDataProvider("active").notifier) .deleteActivity(id) .whenComplete(() => Utils.showSnakeBar("删除成功")) .onError((error, trace) => Utils.showSnakeBar("删除失败:$error")); @@ -47,8 +96,8 @@ class ActivityPage extends ConsumerWidget { class ActivityDataSource extends DataTableSource { List activities; - Function(int) onDelete; - ActivityDataSource({required this.activities, required this.onDelete}); + Function(int)? onDelete; + ActivityDataSource({required this.activities, this.onDelete}); @override int get rowCount => activities.length; @@ -96,11 +145,13 @@ class ActivityDataSource extends DataTableSource { progressColor: Colors.green, ); }()), - DataCell(Tooltip( - message: "删除任务", - child: IconButton( - onPressed: () => onDelete(activity.id!), - icon: const Icon(Icons.delete)))) + onDelete != null + ? DataCell(Tooltip( + message: "删除任务", + child: IconButton( + onPressed: () => onDelete!(activity.id!), + icon: const Icon(Icons.delete)))) + : const DataCell(Text("")) ]); } diff --git a/ui/lib/providers/activity.dart b/ui/lib/providers/activity.dart index 5672e24..6d0c823 100644 --- a/ui/lib/providers/activity.dart +++ b/ui/lib/providers/activity.dart @@ -5,7 +5,7 @@ import 'package:ui/providers/APIs.dart'; import 'package:ui/providers/server_response.dart'; var activitiesDataProvider = - AsyncNotifierProvider.autoDispose>( + AsyncNotifierProvider.autoDispose.family, String>( ActivityData.new); var mediaHistoryDataProvider = FutureProvider.autoDispose.family( @@ -24,14 +24,18 @@ var mediaHistoryDataProvider = FutureProvider.autoDispose.family( }, ); -class ActivityData extends AutoDisposeAsyncNotifier> { +class ActivityData + extends AutoDisposeFamilyAsyncNotifier, String> { @override - FutureOr> build() async { - Timer( - const Duration(seconds: 5), ref.invalidateSelf); //Periodically Refresh + FutureOr> build(String arg) async { + if (arg == "active") { + //refresh active downloads + Timer(const Duration(seconds: 5), + ref.invalidateSelf); //Periodically Refresh + } final dio = await APIs.getDio(); - var resp = await dio.get(APIs.activityUrl); + var resp = await dio.get(APIs.activityUrl, queryParameters: {"status": arg}); final sp = ServerResponse.fromJson(resp.data); if (sp.code != 0) { throw sp.message;