mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-14 12:23:43 +00:00
feat(tasks): group extension folder downloads (#1594)
This commit is contained in:
1 parent
fc0a1e0ef9
commit
1e36599d52
84 files changed
+6690
-881
No files matched your search
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import '../../../../../core/utils/breakpoints.dart';
|
||||
import '../../../../../shared/theme/app_design_tokens.dart';
|
||||
import '../../../domain/task_record.dart';
|
||||
import '../task_context_menu.dart';
|
||||
import 'task_card_desktop.dart';
|
||||
@@ -10,6 +11,8 @@ class TaskCard extends StatelessWidget {
|
||||
const TaskCard({
|
||||
super.key,
|
||||
required this.task,
|
||||
this.expanded = false,
|
||||
this.nested = false,
|
||||
required this.selected,
|
||||
required this.batchMode,
|
||||
required this.selectedInBatch,
|
||||
@@ -25,6 +28,8 @@ class TaskCard extends StatelessWidget {
|
||||
});
|
||||
|
||||
final TaskRecord task;
|
||||
final bool expanded;
|
||||
final bool nested;
|
||||
final bool selected;
|
||||
final bool batchMode;
|
||||
final bool selectedInBatch;
|
||||
@@ -42,40 +47,44 @@ class TaskCard extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final isMobile = MediaQuery.sizeOf(context).width < Breakpoints.mobile;
|
||||
|
||||
if (isMobile) {
|
||||
final card = TaskCardMobile(
|
||||
task: task,
|
||||
selected: selected,
|
||||
batchMode: batchMode,
|
||||
selectedInBatch: selectedInBatch,
|
||||
onPressed: onPressed,
|
||||
onToggleBatch: onToggleBatch,
|
||||
onPause: onPause,
|
||||
onResume: onResume,
|
||||
onDelete: onDelete,
|
||||
onOpen: onOpen,
|
||||
onReveal: onReveal,
|
||||
listeningForUpdate: listeningForUpdate,
|
||||
);
|
||||
final actions = contextActions;
|
||||
return actions == null ? card : TaskContextMenu(task: task, actions: actions, child: card);
|
||||
}
|
||||
|
||||
final card = TaskCardDesktop(
|
||||
task: task,
|
||||
selected: selected,
|
||||
batchMode: batchMode,
|
||||
selectedInBatch: selectedInBatch,
|
||||
onPressed: onPressed,
|
||||
onToggleBatch: onToggleBatch,
|
||||
onPause: onPause,
|
||||
onResume: onResume,
|
||||
onDelete: onDelete,
|
||||
onOpen: onOpen,
|
||||
onReveal: onReveal,
|
||||
listeningForUpdate: listeningForUpdate,
|
||||
);
|
||||
final card = isMobile
|
||||
? TaskCardMobile(
|
||||
task: task,
|
||||
expanded: expanded,
|
||||
selected: selected,
|
||||
batchMode: batchMode,
|
||||
selectedInBatch: selectedInBatch,
|
||||
onPressed: onPressed,
|
||||
onToggleBatch: onToggleBatch,
|
||||
onPause: task.canPause ? onPause : null,
|
||||
onResume: task.canResume ? onResume : null,
|
||||
onDelete: onDelete,
|
||||
onOpen: onOpen,
|
||||
onReveal: onReveal,
|
||||
listeningForUpdate: listeningForUpdate,
|
||||
)
|
||||
: TaskCardDesktop(
|
||||
task: task,
|
||||
expanded: expanded,
|
||||
selected: selected,
|
||||
batchMode: batchMode,
|
||||
selectedInBatch: selectedInBatch,
|
||||
onPressed: onPressed,
|
||||
onToggleBatch: onToggleBatch,
|
||||
onPause: task.canPause ? onPause : null,
|
||||
onResume: task.canResume ? onResume : null,
|
||||
onDelete: onDelete,
|
||||
onOpen: onOpen,
|
||||
onReveal: onReveal,
|
||||
listeningForUpdate: listeningForUpdate,
|
||||
);
|
||||
final actions = contextActions;
|
||||
return actions == null ? card : TaskContextMenu(task: task, actions: actions, child: card);
|
||||
return Padding(
|
||||
padding: EdgeInsetsDirectional.only(start: nested ? AppDesignTokens.space24 : 0),
|
||||
child: Semantics(
|
||||
expanded: task.isGroup ? expanded : null,
|
||||
child: actions == null ? card : TaskContextMenu(task: task, actions: actions, child: card),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
+19
-11
@@ -14,6 +14,7 @@ class TaskCardDesktop extends StatefulWidget {
|
||||
const TaskCardDesktop({
|
||||
super.key,
|
||||
required this.task,
|
||||
this.expanded = false,
|
||||
required this.selected,
|
||||
required this.batchMode,
|
||||
required this.selectedInBatch,
|
||||
@@ -28,6 +29,7 @@ class TaskCardDesktop extends StatefulWidget {
|
||||
});
|
||||
|
||||
final TaskRecord task;
|
||||
final bool expanded;
|
||||
final bool selected;
|
||||
final bool batchMode;
|
||||
final bool selectedInBatch;
|
||||
@@ -64,7 +66,7 @@ class _TaskCardDesktopState extends State<TaskCardDesktop> {
|
||||
_lastTapTime = isDoubleTap ? null : now;
|
||||
_lastTapPosition = isDoubleTap ? null : details.globalPosition;
|
||||
widget.onPressed();
|
||||
if (isDoubleTap) {
|
||||
if (isDoubleTap && !widget.task.isGroup) {
|
||||
widget.onOpen?.call();
|
||||
}
|
||||
}
|
||||
@@ -134,7 +136,7 @@ class _TaskCardDesktopState extends State<TaskCardDesktop> {
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
),
|
||||
TaskCardIcon(task: task),
|
||||
TaskCardIcon(task: task, expanded: widget.expanded),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
@@ -234,15 +236,21 @@ class _ProgressContent extends StatelessWidget {
|
||||
}
|
||||
|
||||
List<Widget> _buildActionButtons(TaskRecord task, AppPalette palette, bool isDark) {
|
||||
final actions = switch (task.status) {
|
||||
TaskStatus.downloading => [(Icons.pause, onPause), (Icons.close, onDelete)],
|
||||
TaskStatus.paused => [(Icons.play_arrow, onResume), (Icons.close, onDelete)],
|
||||
TaskStatus.failed => [(Icons.refresh, onResume), (Icons.delete_outline, onDelete)],
|
||||
TaskStatus.completed => [
|
||||
if (AppWindowChrome.isDesktopWindow) (Icons.folder_open_outlined, null),
|
||||
(Icons.delete_outline, onDelete),
|
||||
],
|
||||
};
|
||||
final actions = task.isGroup && task.status != TaskStatus.completed
|
||||
? [
|
||||
if (task.canPause) (Icons.pause, onPause),
|
||||
if (task.canResume) (Icons.play_arrow, onResume),
|
||||
(Icons.close, onDelete),
|
||||
]
|
||||
: switch (task.status) {
|
||||
TaskStatus.downloading => [(Icons.pause, onPause), (Icons.close, onDelete)],
|
||||
TaskStatus.paused => [(Icons.play_arrow, onResume), (Icons.close, onDelete)],
|
||||
TaskStatus.failed => [(Icons.refresh, onResume), (Icons.delete_outline, onDelete)],
|
||||
TaskStatus.completed => [
|
||||
if (AppWindowChrome.isDesktopWindow) (Icons.folder_open_outlined, null),
|
||||
(Icons.delete_outline, onDelete),
|
||||
],
|
||||
};
|
||||
|
||||
return actions
|
||||
.map(
|
||||
|
||||
+19
-11
@@ -13,6 +13,7 @@ class TaskCardMobile extends StatefulWidget {
|
||||
const TaskCardMobile({
|
||||
super.key,
|
||||
required this.task,
|
||||
this.expanded = false,
|
||||
required this.selected,
|
||||
required this.batchMode,
|
||||
required this.selectedInBatch,
|
||||
@@ -27,6 +28,7 @@ class TaskCardMobile extends StatefulWidget {
|
||||
});
|
||||
|
||||
final TaskRecord task;
|
||||
final bool expanded;
|
||||
final bool selected;
|
||||
final bool batchMode;
|
||||
final bool selectedInBatch;
|
||||
@@ -62,7 +64,7 @@ class _TaskCardMobileState extends State<TaskCardMobile> {
|
||||
onExit: (_) => setState(() => _hovered = false),
|
||||
child: GestureDetector(
|
||||
onTap: widget.onPressed,
|
||||
onDoubleTap: !widget.batchMode && task.status == TaskStatus.completed ? widget.onOpen : null,
|
||||
onDoubleTap: !widget.batchMode && !task.isGroup && task.status == TaskStatus.completed ? widget.onOpen : null,
|
||||
child: Container(
|
||||
key: const ValueKey('task-card-mobile-surface'),
|
||||
decoration: BoxDecoration(
|
||||
@@ -117,7 +119,7 @@ class _TaskCardMobileState extends State<TaskCardMobile> {
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
),
|
||||
TaskCardIcon(task: task),
|
||||
TaskCardIcon(task: task, expanded: widget.expanded),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Text(
|
||||
@@ -168,15 +170,21 @@ class _TaskCardMobileState extends State<TaskCardMobile> {
|
||||
}
|
||||
|
||||
List<Widget> _buildActionButtons(TaskRecord task, AppPalette palette, bool isDark) {
|
||||
final actions = switch (task.status) {
|
||||
TaskStatus.downloading => [(Icons.pause, widget.onPause), (Icons.close, widget.onDelete)],
|
||||
TaskStatus.paused => [(Icons.play_arrow, widget.onResume), (Icons.close, widget.onDelete)],
|
||||
TaskStatus.failed => [(Icons.refresh, widget.onResume), (Icons.delete_outline, widget.onDelete)],
|
||||
TaskStatus.completed => [
|
||||
if (AppWindowChrome.isDesktopWindow) (Icons.folder_open_outlined, widget.onReveal),
|
||||
(Icons.delete_outline, widget.onDelete),
|
||||
],
|
||||
};
|
||||
final actions = task.isGroup && task.status != TaskStatus.completed
|
||||
? [
|
||||
if (task.canPause) (Icons.pause, widget.onPause),
|
||||
if (task.canResume) (Icons.play_arrow, widget.onResume),
|
||||
(Icons.close, widget.onDelete),
|
||||
]
|
||||
: switch (task.status) {
|
||||
TaskStatus.downloading => [(Icons.pause, widget.onPause), (Icons.close, widget.onDelete)],
|
||||
TaskStatus.paused => [(Icons.play_arrow, widget.onResume), (Icons.close, widget.onDelete)],
|
||||
TaskStatus.failed => [(Icons.refresh, widget.onResume), (Icons.delete_outline, widget.onDelete)],
|
||||
TaskStatus.completed => [
|
||||
if (AppWindowChrome.isDesktopWindow) (Icons.folder_open_outlined, widget.onReveal),
|
||||
(Icons.delete_outline, widget.onDelete),
|
||||
],
|
||||
};
|
||||
|
||||
return actions
|
||||
.map(
|
||||
|
||||
@@ -46,25 +46,35 @@ class TaskUpdateListeningIndicator extends StatelessWidget {
|
||||
}
|
||||
|
||||
class TaskCardIcon extends StatelessWidget {
|
||||
const TaskCardIcon({super.key, required this.task});
|
||||
const TaskCardIcon({super.key, required this.task, this.expanded = false});
|
||||
|
||||
final TaskRecord task;
|
||||
final bool expanded;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final palette = AppPalette.of(context);
|
||||
|
||||
return SizedBox(
|
||||
width: 32,
|
||||
height: 32,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(AppDesignTokens.controlRadius),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
child: ColoredBox(
|
||||
color: palette.taskCardIconBg,
|
||||
child: Center(child: Icon(task.icon, size: 20, color: palette.textSecondary)),
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (task.isGroup) ...[
|
||||
Icon(expanded ? Icons.expand_more : Icons.chevron_right, size: 18, color: palette.textSecondary),
|
||||
const SizedBox(width: AppDesignTokens.space4),
|
||||
],
|
||||
SizedBox(
|
||||
width: 32,
|
||||
height: 32,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(AppDesignTokens.controlRadius),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
child: ColoredBox(
|
||||
color: palette.taskCardIconBg,
|
||||
child: Center(child: Icon(task.icon, size: 20, color: palette.textSecondary)),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user