1
+ import 'package:contextmenu/contextmenu.dart' ;
1
2
import 'package:flutter/material.dart' ;
2
3
import 'package:get/get.dart' ;
3
4
import 'package:styled_widget/styled_widget.dart' ;
@@ -8,16 +9,20 @@ import '../../util/message.dart';
8
9
import '../../util/util.dart' ;
9
10
import '../modules/app/controllers/app_controller.dart' ;
10
11
import '../modules/task/controllers/task_controller.dart' ;
12
+ import '../modules/task/controllers/task_downloaded_controller.dart' ;
13
+ import '../modules/task/controllers/task_downloading_controller.dart' ;
11
14
import '../modules/task/views/task_view.dart' ;
12
15
import '../routes/app_pages.dart' ;
13
16
import 'file_icon.dart' ;
14
17
15
18
class BuildTaskListView extends GetView {
16
19
final List <Task > tasks;
20
+ final List <String > selectedTaskIds;
17
21
18
22
const BuildTaskListView ({
19
23
Key ? key,
20
24
required this .tasks,
25
+ required this .selectedTaskIds,
21
26
}) : super (key: key);
22
27
23
28
@override
@@ -56,11 +61,15 @@ class BuildTaskListView extends GetView {
56
61
return task.status == Status .running;
57
62
}
58
63
64
+ bool isSelect () {
65
+ return selectedTaskIds.contains (task.id);
66
+ }
67
+
59
68
bool isFolderTask () {
60
69
return task.isFolder;
61
70
}
62
71
63
- Future <void > showDeleteDialog (String id ) {
72
+ Future <void > showDeleteDialog (List < String > ids ) {
64
73
final appController = Get .find <AppController >();
65
74
66
75
final context = Get .context! ;
@@ -69,7 +78,8 @@ class BuildTaskListView extends GetView {
69
78
context: context,
70
79
barrierDismissible: false ,
71
80
builder: (_) => AlertDialog (
72
- title: Text ('deleteTask' .tr),
81
+ title: Text (
82
+ 'deleteTask' .trParams ({'count' : ids.length.toString ()})),
73
83
content: Obx (() => CheckboxListTile (
74
84
value: appController
75
85
.downloaderConfig.value.extra.lastDeleteTaskKeep,
@@ -95,7 +105,7 @@ class BuildTaskListView extends GetView {
95
105
final force = ! appController
96
106
.downloaderConfig.value.extra.lastDeleteTaskKeep;
97
107
await appController.saveConfig ();
98
- await deleteTask (id , force);
108
+ await deleteTasks (ids , force);
99
109
Get .back ();
100
110
} catch (e) {
101
111
showErrorMessage (e);
@@ -143,12 +153,35 @@ class BuildTaskListView extends GetView {
143
153
list.add (IconButton (
144
154
icon: const Icon (Icons .delete),
145
155
onPressed: () {
146
- showDeleteDialog (task.id);
156
+ showDeleteDialog ([ task.id] );
147
157
},
148
158
));
149
159
return list;
150
160
}
151
161
162
+ Widget buildContextItem (IconData icon, String label, Function () onTap,
163
+ {bool enabled = true }) {
164
+ return ListTile (
165
+ dense: true ,
166
+ visualDensity: const VisualDensity (vertical: - 1 ),
167
+ minLeadingWidth: 12 ,
168
+ leading: Icon (icon, size: 18 ),
169
+ title: Text (label,
170
+ style: const TextStyle (
171
+ fontWeight: FontWeight .bold, // Make the text bold
172
+ )),
173
+ onTap: () async {
174
+ Get .back ();
175
+ try {
176
+ await onTap ();
177
+ } catch (e) {
178
+ showErrorMessage (e);
179
+ }
180
+ },
181
+ enabled: enabled,
182
+ );
183
+ }
184
+
152
185
double getProgress () {
153
186
final totalSize = task.meta.res? .size ?? 0 ;
154
187
return totalSize <= 0 ? 0 : task.progress.downloaded / totalSize;
@@ -167,55 +200,127 @@ class BuildTaskListView extends GetView {
167
200
}
168
201
169
202
final taskController = Get .find <TaskController >();
203
+ final taskListController = taskController.tabIndex.value == 0
204
+ ? Get .find <TaskDownloadingController >()
205
+ : Get .find <TaskDownloadedController >();
170
206
171
- return Card (
172
- elevation: 4.0 ,
173
- child: InkWell (
174
- onTap: () {
175
- taskController.scaffoldKey.currentState? .openEndDrawer ();
176
- taskController.selectTask.value = task;
177
- },
178
- onDoubleTap: () {
179
- task.open ();
180
- },
181
- child: Column (
182
- mainAxisSize: MainAxisSize .min,
183
- children: [
184
- ListTile (
185
- title: Text (task.name),
186
- leading: Icon (
187
- fileIcon (task.name,
188
- isFolder: isFolderTask (),
189
- isBitTorrent: task.protocol == Protocol .bt),
190
- )),
191
- Row (
207
+ // Filter selected task ids that are still in the task list
208
+ filterSelectedTaskIds (Iterable <String > selectedTaskIds) => selectedTaskIds
209
+ .where ((id) => tasks.any ((task) => task.id == id))
210
+ .toList ();
211
+
212
+ return ContextMenuArea (
213
+ width: 140 ,
214
+ builder: (context) => [
215
+ buildContextItem (Icons .checklist, 'selectAll' .tr, () {
216
+ if (tasks.isEmpty) return ;
217
+
218
+ if (selectedTaskIds.isNotEmpty) {
219
+ taskListController.selectedTaskIds ([]);
220
+ } else {
221
+ taskListController.selectedTaskIds (tasks.map ((e) => e.id).toList ());
222
+ }
223
+ }),
224
+ buildContextItem (Icons .check, 'select' .tr, () {
225
+ if (isSelect ()) {
226
+ taskListController.selectedTaskIds (taskListController
227
+ .selectedTaskIds
228
+ .where ((element) => element != task.id)
229
+ .toList ());
230
+ } else {
231
+ taskListController.selectedTaskIds (
232
+ [...taskListController.selectedTaskIds, task.id]);
233
+ }
234
+ }),
235
+ const Divider (
236
+ indent: 8 ,
237
+ endIndent: 8 ,
238
+ ),
239
+ buildContextItem (Icons .play_arrow, 'continue' .tr, () async {
240
+ try {
241
+ await continueAllTasks (filterSelectedTaskIds (
242
+ {...taskListController.selectedTaskIds, task.id}));
243
+ } finally {
244
+ taskListController.selectedTaskIds ([]);
245
+ }
246
+ }, enabled: ! isDone () && ! isRunning ()),
247
+ buildContextItem (Icons .pause, 'pause' .tr, () async {
248
+ try {
249
+ await pauseAllTasks (filterSelectedTaskIds (
250
+ {...taskListController.selectedTaskIds, task.id}));
251
+ } finally {
252
+ taskListController.selectedTaskIds ([]);
253
+ }
254
+ }, enabled: ! isDone () && isRunning ()),
255
+ buildContextItem (Icons .delete, 'delete' .tr, () async {
256
+ try {
257
+ await showDeleteDialog (filterSelectedTaskIds (
258
+ {...taskListController.selectedTaskIds, task.id}));
259
+ } finally {
260
+ taskListController.selectedTaskIds ([]);
261
+ }
262
+ }),
263
+ ],
264
+ child: Obx (
265
+ () => Card (
266
+ elevation: 4.0 ,
267
+ shape: isSelect ()
268
+ ? RoundedRectangleBorder (
269
+ borderRadius: BorderRadius .circular (8.0 ),
270
+ side: BorderSide (
271
+ color: Theme .of (context).colorScheme.primary,
272
+ width: 2.0 ,
273
+ ),
274
+ )
275
+ : null ,
276
+ child: InkWell (
277
+ onTap: () {
278
+ taskController.scaffoldKey.currentState? .openEndDrawer ();
279
+ taskController.selectTask.value = task;
280
+ },
281
+ onDoubleTap: () {
282
+ task.open ();
283
+ },
284
+ child: Column (
285
+ mainAxisSize: MainAxisSize .min,
192
286
children: [
193
- Expanded (
194
- flex: 1 ,
195
- child: Text (
196
- getProgressText (),
197
- style: Get .textTheme.bodyLarge
198
- ? .copyWith (color: Get .theme.disabledColor),
199
- ).padding (left: 18 )),
200
- Expanded (
201
- flex: 1 ,
202
- child: Row (
203
- mainAxisAlignment: MainAxisAlignment .end,
204
- children: [
205
- Text ("${Util .fmtByte (task .progress .speed )} / s" ,
206
- style: Get .textTheme.titleSmall),
207
- ...buildActions ()
208
- ],
287
+ ListTile (
288
+ title: Text (task.name),
289
+ leading: Icon (
290
+ fileIcon (task.name,
291
+ isFolder: isFolderTask (),
292
+ isBitTorrent: task.protocol == Protocol .bt),
209
293
)),
294
+ Row (
295
+ children: [
296
+ Expanded (
297
+ flex: 1 ,
298
+ child: Text (
299
+ getProgressText (),
300
+ style: Get .textTheme.bodyLarge
301
+ ? .copyWith (color: Get .theme.disabledColor),
302
+ ).padding (left: 18 )),
303
+ Expanded (
304
+ flex: 1 ,
305
+ child: Row (
306
+ mainAxisAlignment: MainAxisAlignment .end,
307
+ children: [
308
+ Text ("${Util .fmtByte (task .progress .speed )} / s" ,
309
+ style: Get .textTheme.titleSmall),
310
+ ...buildActions ()
311
+ ],
312
+ )),
313
+ ],
314
+ ),
315
+ isDone ()
316
+ ? Container ()
317
+ : LinearProgressIndicator (
318
+ value: getProgress (),
319
+ ),
210
320
],
211
321
),
212
- isDone ()
213
- ? Container ()
214
- : LinearProgressIndicator (
215
- value: getProgress (),
216
- ),
217
- ],
218
- ),
219
- )).padding (horizontal: 14 , top: 8 );
322
+ )).padding (horizontal: 14 , top: 8 ),
323
+ ),
324
+ );
220
325
}
221
326
}
0 commit comments