diff --git a/README.md b/README.md index 02fe8ec..1caa1a8 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,115 @@ - - -TODO: Put a short description of the package here that helps potential users -know whether this package might be useful for them. +Task Manager is a tool for managing and scheduling task execution, designed to simplify and optimize the execution of asynchronous tasks. ## Features -TODO: List what your package can do. Maybe include images, gifs, or videos. +- Supports canceling and pausing ongoing tasks +- Allows adjustment of task priority +- Enables persistent storage of task states, supporting continued execution after application interruption and restart ## Getting started -TODO: List prerequisites and provide or point to information on how to -start using the package. +Add the following dependencies to your `pubspec.yaml file: + +``` +task_manager: + git: + url: https://github.com/cezres/task_manager.git + ref: main +``` ## Usage -TODO: Include short and useful examples for package users. Add longer examples -to `/example` folder. + +### Create a task + +The following example demonstrates how to create a simple task: + +```dart +class ExampleOperation extends Operation { + const ExampleOperation(); + + @override + FutureOr> run(OperationContext context) async { + await Future.delayed(const Duration(seconds: 1)); + return Result.completed('Hello World - ${context.data}'); + } +} + +void example() async { + // Create a worker + final worker = Worker(); + worker.maxConcurrencies = 2; + // Add a task + final task = worker.addTask(const ExampleOperation(), 1); + // Wait for the task to complete + await task.wait(); // Result.completed('Hello World - 1') +} +``` + +### Pause or cancel a task + +For tasks in progress, you need to check if the operation should be paused or canceled, as shown below: ```dart -const like = 'sample'; +class CountdownOperation extends Operation { + const CountdownOperation(); + + @override + FutureOr> run(OperationContext context) async { + int data = context.data; + while (data > 0) { + await Future.delayed(const Duration(milliseconds: 1000)); + data -= 1; + + /// Check if the operation should be paused or canceled + if (context.shouldPause) { + return Result.paused(data); + } else if (context.shouldCancel) { + return Result.canceled(); + } else { + context.emit(data); + } + } + return Result.completed(); + } +} + +void example() { + task.cancel(); + task.pause(); + task.resume(); +} ``` -## Additional information +### Create hydrated task + +To create a hydrated task, refer to the following code: -TODO: Tell users more about the package: where to find more information, how to -contribute to the package, how to file issues, what response they can expect -from the package authors, and more. +```dart +class ExampleHydratedOperation extends HydratedOperation { + const ExampleHydratedOperation(); + + @override + FutureOr> run(OperationContext context) async { + await Future.delayed(const Duration(seconds: 1)); + return Result.completed('Hello World - ${context.data}'); + } + + @override + toJson(int data) { + return data; + } + + @override + int fromJson(json) { + return json; + } +} + +void example() { + StorageManager.registerStorage(CustomStorage()); + StorageManager.registerOperation(() => const ExampleHydratedOperation()); +} +``` diff --git a/example/lib/main.dart b/example/lib/main.dart index 262aa05..35311dd 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,22 +1,13 @@ import 'package:example/countdown_operation.dart'; import 'package:example/storage/custom_storage.dart'; import 'package:example/task_manager_view.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:path_provider/path_provider.dart'; import 'package:task_manager/task_manager.dart'; void main() async { - WidgetsFlutterBinding.ensureInitialized(); - StorageManager.registerStorage(CustomStorage.adapter()); StorageManager.registerOperation(() => const CountdownOperation()); - if (!kIsWeb) { - final directory = await getApplicationDocumentsDirectory(); - debugPrint('directory: ${directory.path}'); - } - runApp(const MyApp()); } @@ -63,9 +54,55 @@ class _MyHomePageState extends State { } } + void _showMaxConcurrenciesDialog() { + final controller = + TextEditingController(text: worker.maxConcurrencies.toString()); + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text("Max Concurrencies"), + content: TextField( + controller: controller, + keyboardType: TextInputType.number, + ), + actions: [ + TextButton( + onPressed: () { + Navigator.pop(context); + }, + child: const Text("Cancel"), + ), + TextButton( + onPressed: () { + final value = int.tryParse(controller.text); + if (value != null) { + worker.maxConcurrencies = value; + } + Navigator.pop(context); + }, + child: const Text("OK"), + ), + ], + ), + ); + } + @override Widget build(BuildContext context) { return Scaffold( + appBar: AppBar( + title: const Text("Task Manager Example"), + centerTitle: true, + actions: [ + IconButton.outlined( + onPressed: _showMaxConcurrenciesDialog, + icon: const Icon(Icons.settings), + ), + const SizedBox( + width: 24, + ) + ], + ), body: TaskManagerView(worker: worker), floatingActionButton: FloatingActionButton( onPressed: _addTasks, diff --git a/example/lib/task_manager_view.dart b/example/lib/task_manager_view.dart index 8a9d73f..dcff8ca 100644 --- a/example/lib/task_manager_view.dart +++ b/example/lib/task_manager_view.dart @@ -11,27 +11,34 @@ class TaskManagerView extends StatelessWidget { @override Widget build(BuildContext context) { - return Row( + return Column( children: [ - _buildExpandedTaskList( - context, - title: 'Running', - color: Colors.green[300], - tasks: (worker) => worker.runningTasks, - ), - const VerticalDivider(width: 1, thickness: 1), - _buildExpandedTaskList( - context, - title: 'Pending', - color: Colors.orange[300], - tasks: (worker) => worker.pendingTasks, - ), - const VerticalDivider(width: 1, thickness: 1), - _buildExpandedTaskList( - context, - title: 'Pasued', - color: Colors.blue[300], - tasks: (worker) => worker.pausedTasks, + const Divider(height: 1, thickness: 1), + Expanded( + child: Row( + children: [ + _buildExpandedTaskList( + context, + title: 'Running', + color: Colors.green[300], + tasks: (worker) => worker.runningTasks, + ), + const VerticalDivider(width: 1, thickness: 1), + _buildExpandedTaskList( + context, + title: 'Pending', + color: Colors.orange[300], + tasks: (worker) => worker.pendingTasks, + ), + const VerticalDivider(width: 1, thickness: 1), + _buildExpandedTaskList( + context, + title: 'Pasued', + color: Colors.blue[300], + tasks: (worker) => worker.pausedTasks, + ), + ], + ), ), ], ); diff --git a/lib/isolate/background_isolate.dart b/lib/src/isolate/background_isolate.dart similarity index 100% rename from lib/isolate/background_isolate.dart rename to lib/src/isolate/background_isolate.dart diff --git a/lib/isolate/background_isolate_manager.dart b/lib/src/isolate/background_isolate_manager.dart similarity index 100% rename from lib/isolate/background_isolate_manager.dart rename to lib/src/isolate/background_isolate_manager.dart diff --git a/lib/isolate/background_isolate_task_result.dart b/lib/src/isolate/background_isolate_task_result.dart similarity index 100% rename from lib/isolate/background_isolate_task_result.dart rename to lib/src/isolate/background_isolate_task_result.dart diff --git a/lib/operation/isolate_operation_context_impl.dart b/lib/src/operation/isolate_operation_context_impl.dart similarity index 99% rename from lib/operation/isolate_operation_context_impl.dart rename to lib/src/operation/isolate_operation_context_impl.dart index 79c3d4e..91673c1 100644 --- a/lib/operation/isolate_operation_context_impl.dart +++ b/lib/src/operation/isolate_operation_context_impl.dart @@ -1,4 +1,4 @@ -part of '../task_manager.dart'; +part of '../../task_manager.dart'; class IsolateOperationContextImpl extends OperationContextImpl { IsolateOperationContextImpl({ diff --git a/lib/operation/operation_context_impl.dart b/lib/src/operation/operation_context_impl.dart similarity index 98% rename from lib/operation/operation_context_impl.dart rename to lib/src/operation/operation_context_impl.dart index 5275143..25e26c0 100644 --- a/lib/operation/operation_context_impl.dart +++ b/lib/src/operation/operation_context_impl.dart @@ -1,4 +1,4 @@ -part of '../task_manager.dart'; +part of '../../task_manager.dart'; class OperationContextImpl extends OperationContext { OperationContextImpl({ diff --git a/lib/scheduling/scheduler.dart b/lib/src/scheduling/scheduler.dart similarity index 99% rename from lib/scheduling/scheduler.dart rename to lib/src/scheduling/scheduler.dart index 30ee5a5..4263d53 100644 --- a/lib/scheduling/scheduler.dart +++ b/lib/src/scheduling/scheduler.dart @@ -1,4 +1,4 @@ -part of '../task_manager.dart'; +part of '../../task_manager.dart'; typedef TaskIdentifier = String; typedef TaskId = String; diff --git a/lib/scheduling/worker.dart b/lib/src/scheduling/worker.dart similarity index 99% rename from lib/scheduling/worker.dart rename to lib/src/scheduling/worker.dart index de8acbe..dba0263 100644 --- a/lib/scheduling/worker.dart +++ b/lib/src/scheduling/worker.dart @@ -1,4 +1,4 @@ -part of '../task_manager.dart'; +part of '../../task_manager.dart'; final Map _workers = {}; diff --git a/lib/scheduling/worker_isolate.dart b/lib/src/scheduling/worker_isolate.dart similarity index 96% rename from lib/scheduling/worker_isolate.dart rename to lib/src/scheduling/worker_isolate.dart index 7201cfc..b475815 100644 --- a/lib/scheduling/worker_isolate.dart +++ b/lib/src/scheduling/worker_isolate.dart @@ -1,4 +1,4 @@ -part of '../task_manager.dart'; +part of '../../task_manager.dart'; class IsolateWorker extends WorkerImpl { IsolateWorker() : super._('IsolateWorker'); diff --git a/lib/storage/storage.dart b/lib/src/storage/storage.dart similarity index 97% rename from lib/storage/storage.dart rename to lib/src/storage/storage.dart index 357ea84..fc6c593 100644 --- a/lib/storage/storage.dart +++ b/lib/src/storage/storage.dart @@ -1,4 +1,4 @@ -part of '../task_manager.dart'; +part of '../../task_manager.dart'; abstract class Storage { const Storage(); diff --git a/lib/storage/storage_manager.dart b/lib/src/storage/storage_manager.dart similarity index 98% rename from lib/storage/storage_manager.dart rename to lib/src/storage/storage_manager.dart index e4573b3..140b13b 100644 --- a/lib/storage/storage_manager.dart +++ b/lib/src/storage/storage_manager.dart @@ -1,4 +1,4 @@ -part of '../task_manager.dart'; +part of '../../task_manager.dart'; typedef OperationCreater = T Function(); diff --git a/lib/task/hydrated_task_impl.dart b/lib/src/task/hydrated_task_impl.dart similarity index 96% rename from lib/task/hydrated_task_impl.dart rename to lib/src/task/hydrated_task_impl.dart index bd457c3..dc42519 100644 --- a/lib/task/hydrated_task_impl.dart +++ b/lib/src/task/hydrated_task_impl.dart @@ -1,4 +1,4 @@ -part of '../task_manager.dart'; +part of '../../task_manager.dart'; class HydratedTaskImpl> extends TaskImpl { diff --git a/lib/task/result.dart b/lib/src/task/result.dart similarity index 97% rename from lib/task/result.dart rename to lib/src/task/result.dart index 094d7ec..967433e 100644 --- a/lib/task/result.dart +++ b/lib/src/task/result.dart @@ -1,4 +1,4 @@ -part of '../task_manager.dart'; +part of '../../task_manager.dart'; class Result { final D? data; diff --git a/lib/task/task_impl.dart b/lib/src/task/task_impl.dart similarity index 99% rename from lib/task/task_impl.dart rename to lib/src/task/task_impl.dart index ca02bbe..c3fc40b 100644 --- a/lib/task/task_impl.dart +++ b/lib/src/task/task_impl.dart @@ -1,4 +1,4 @@ -part of '../task_manager.dart'; +part of '../../task_manager.dart'; class TaskImpl> extends Task with PriorityMixin { diff --git a/lib/task/task_priority.dart b/lib/src/task/task_priority.dart similarity index 100% rename from lib/task/task_priority.dart rename to lib/src/task/task_priority.dart diff --git a/lib/utils/generate_incremental_id.dart b/lib/src/utils/generate_incremental_id.dart similarity index 100% rename from lib/utils/generate_incremental_id.dart rename to lib/src/utils/generate_incremental_id.dart diff --git a/lib/utils/priority_queue.dart b/lib/src/utils/priority_queue.dart similarity index 100% rename from lib/utils/priority_queue.dart rename to lib/src/utils/priority_queue.dart diff --git a/lib/utils/reused_object.dart b/lib/src/utils/reused_object.dart similarity index 100% rename from lib/utils/reused_object.dart rename to lib/src/utils/reused_object.dart diff --git a/lib/task_manager.dart b/lib/task_manager.dart index 225cced..c93b2f6 100644 --- a/lib/task_manager.dart +++ b/lib/task_manager.dart @@ -4,23 +4,23 @@ import 'dart:async'; import 'dart:isolate'; import 'package:flutter/foundation.dart'; -import 'package:task_manager/task/task_priority.dart'; -import 'package:task_manager/utils/generate_incremental_id.dart'; -import 'package:task_manager/utils/priority_queue.dart'; +import 'package:task_manager/src/task/task_priority.dart'; +import 'package:task_manager/src/utils/generate_incremental_id.dart'; +import 'package:task_manager/src/utils/priority_queue.dart'; -part 'task/task_impl.dart'; -part 'task/hydrated_task_impl.dart'; -part 'task/result.dart'; +part 'src/task/task_impl.dart'; +part 'src/task/hydrated_task_impl.dart'; +part 'src/task/result.dart'; -part 'operation/operation_context_impl.dart'; -part 'operation/isolate_operation_context_impl.dart'; +part 'src/operation/operation_context_impl.dart'; +part 'src/operation/isolate_operation_context_impl.dart'; -part 'scheduling/scheduler.dart'; -part 'scheduling/worker.dart'; -part 'scheduling/worker_isolate.dart'; +part 'src/scheduling/scheduler.dart'; +part 'src/scheduling/worker.dart'; +part 'src/scheduling/worker_isolate.dart'; -part 'storage/storage.dart'; -part 'storage/storage_manager.dart'; +part 'src/storage/storage.dart'; +part 'src/storage/storage_manager.dart'; abstract class OperationContext { String get id; diff --git a/test/priority_queue_test.dart b/test/priority_queue_test.dart index 8f52257..10fce3d 100644 --- a/test/priority_queue_test.dart +++ b/test/priority_queue_test.dart @@ -1,5 +1,5 @@ import 'package:flutter_test/flutter_test.dart'; -import 'package:task_manager/utils/priority_queue.dart'; +import 'package:task_manager/src/utils/priority_queue.dart'; void main() { test('priority_queue', () {