import 'dart:io'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:styled_widget/styled_widget.dart'; import 'package:url_launcher/url_launcher.dart'; import '../../api/api.dart'; import '../../api/model/task.dart'; import '../../util/util.dart'; import 'task_controller.dart'; class Item extends StatelessWidget { final Task task; const Item({Key? key, required this.task}) : super(key: key); @override Widget build(BuildContext context) { return Card( elevation: 4.0, child: InkWell( onTap: () {}, child: Column( mainAxisSize: MainAxisSize.min, children: [ ListTile( title: Text(task.res.name), leading: const Icon(Icons.insert_drive_file), ), Row( children: [ Expanded( child: Text( "${isDone() ? "" : "${Util.fmtByte(task.progress.downloaded)} / "}${Util.fmtByte(task.size)}", style: context.textTheme.bodyText1 ?.copyWith(color: Get.theme.disabledColor), ).padding(left: 18)), Expanded( child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ Text("${Util.fmtByte(task.progress.speed)} / s", style: context.textTheme.subtitle2), ...buildActions() ], )), ], ), LinearProgressIndicator( value: getProgress(), ), ], ), )).padding(horizontal: 8, top: 8); } List buildActions() { final list = []; if (isDone()) { if (Util.isDesktop()) { list.add(IconButton( icon: const Icon(Icons.folder_open), onPressed: () async { final file = File(Util.buildAbsPath(task.opts.path, task.res.files[0].path, task.res.files[0].name)); await launchUrl(file.parent.uri); }, )); } } else { if (isRunning()) { list.add(IconButton( icon: const Icon(Icons.pause), onPressed: () async { await pauseTask(task.id); }, )); } else { list.add(IconButton( icon: const Icon(Icons.play_arrow), onPressed: () async { await continueTask(task.id); }, )); } } list.add(IconButton( icon: const Icon(Icons.delete), onPressed: () { _showDeleteDialog(task.id); }, )); return list; } double getProgress() { return task.size <= 0 ? 1 : task.progress.downloaded / task.size; } bool isDone() { return task.status == Status.done; } bool isRunning() { return task.status == Status.running; } Future _showDeleteDialog(String id) { final keep = true.obs; final context = Get.context!; return showDialog( context: context, barrierDismissible: false, builder: (_) => AlertDialog( title: Text('task.deleteTask'.tr), content: Obx(() => CheckboxListTile( value: keep.value, title: Text('task.deleteTaskTip'.tr, style: context.textTheme.bodyText1), onChanged: (v) { keep.value = v!; })), actions: [ TextButton( child: Text('cancel'.tr), onPressed: () => Get.back(), ), TextButton( child: Text( 'task.delete'.tr, style: const TextStyle(color: Colors.redAccent), ), onPressed: () async { try { await deleteTask(id, !keep.value); Get.find().loadTab(); Get.back(); } catch (e) { Get.snackbar('error'.tr, e.toString()); } }, ), ], )); } } class TaskView extends GetView { const TaskView({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return DefaultTabController( length: 2, child: Scaffold( appBar: PreferredSize( preferredSize: const Size.fromHeight(56), child: AppBar( bottom: TabBar( tabs: const [ Tab( icon: Icon(Icons.file_download), ), Tab( icon: Icon(Icons.done), ), ], onTap: (index) { if (controller.tabIndex.value != index) { controller.tabIndex.value = index; controller.loadTab(); } }, ), )), body: TabBarView( children: [ Obx(() => buildTaskList(controller.unDoneTasks)), Obx(() => buildTaskList(controller.doneTasks)), ], ), ), ); } Widget buildTaskList(List tasks) { return ListView.builder( itemCount: tasks.length, itemBuilder: (context, index) { return Item(task: tasks[index]); }, ); } }