LCOV - code coverage report
Current view: top level - src - task_handler.dart Coverage Total Hit
Test: lcov.info Lines: 57.7 % 26 15
Test Date: 2026-04-30 18:23:23 Functions: - 0 0

            Line data    Source code
       1              : import 'dart:async';
       2              : import 'package:flutter/foundation.dart';
       3              : import 'native_work_manager.dart';
       4              : import 'events.dart';
       5              : 
       6              : /// A controller for a specific background task.
       7              : ///
       8              : /// Returned by [NativeWorkManager.enqueue] to allow tracking progress and
       9              : /// completion of a specific task without manually filtering global streams.
      10              : ///
      11              : /// ## Usage
      12              : ///
      13              : /// ```dart
      14              : /// final handler = await NativeWorkManager.enqueue(
      15              : ///   taskId: 'download-video',
      16              : ///   worker: NativeWorker.httpDownload(url: '...'),
      17              : /// );
      18              : ///
      19              : /// // 1. Check if OS accepted the task
      20              : /// if (handler.scheduleResult != ScheduleResult.accepted) {
      21              : ///   print('Failed to schedule: ${handler.scheduleResult}');
      22              : ///   return;
      23              : /// }
      24              : ///
      25              : /// // 2. Listen to progress for THIS task only
      26              : /// handler.progress.listen((p) {
      27              : ///   print('Progress: ${p.progress}% (${p.networkSpeedHuman})');
      28              : /// });
      29              : ///
      30              : /// // 3. Wait for final result
      31              : /// final event = await handler.result;
      32              : /// if (event.success) {
      33              : ///   print('Finished! Result: ${event.resultData}');
      34              : /// }
      35              : /// ```
      36              : @immutable
      37              : class TaskHandler {
      38              :   /// The unique ID of the task.
      39              :   final String taskId;
      40              : 
      41              :   /// The result of the scheduling request.
      42              :   ///
      43              :   /// If [ScheduleResult.accepted], the task was successfully added to the
      44              :   /// OS queue. Otherwise, the task will not run.
      45              :   final ScheduleResult scheduleResult;
      46              : 
      47            6 :   const TaskHandler({
      48              :     required this.taskId,
      49              :     required this.scheduleResult,
      50              :   });
      51              : 
      52              :   /// A stream of progress updates for this specific task.
      53              :   ///
      54              :   /// Only emits updates if the worker supports progress reporting (e.g.
      55              :   /// httpDownload, httpUpload).
      56            0 :   Stream<TaskProgress> get progress =>
      57            0 :       NativeWorkManager.progress.where((p) => p.taskId == taskId);
      58              : 
      59              :   /// A stream of lifecycle events for this specific task.
      60              :   ///
      61              :   /// Emits when the task starts, succeeds, or fails.
      62            0 :   Stream<TaskEvent> get events =>
      63            0 :       NativeWorkManager.events.where((e) => e.taskId == taskId);
      64              : 
      65              :   /// A future that completes when the task finishes (either success or failure).
      66              :   ///
      67              :   /// This is a convenience for `events.firstWhere((e) => !e.isStarted)`.
      68              :   ///
      69              :   /// **Note:** If the app is terminated and restarted, this future will never
      70              :   /// complete because the stream is transient. For long-running tasks, always
      71              :   /// use [NativeWorkManager.getTaskStatus] or [NativeWorkManager.events]
      72              :   /// subscription for robust state management.
      73            0 :   Future<TaskEvent> get result =>
      74            0 :       events.firstWhere((e) => !e.isStarted).timeout(
      75              :             const Duration(days: 7), // Long timeout for background tasks
      76            0 :             onTimeout: () => throw TimeoutException(
      77            0 :               'Task $taskId did not complete within 7 days or was lost.',
      78              :             ),
      79              :           );
      80              : 
      81              :   /// Cancel this task.
      82            0 :   Future<void> cancel() => NativeWorkManager.cancel(taskId: taskId);
      83              : 
      84              :   /// Get the current status of this task.
      85            0 :   Future<TaskStatus?> getStatus() =>
      86            0 :       NativeWorkManager.getTaskStatus(taskId: taskId);
      87              : }
      88              : 
      89              : /// Helper extensions for displaying [TaskProgress] information.
      90              : extension TaskProgressExtensions on TaskProgress {
      91              :   /// Returns the network speed in a human-readable format (e.g., "1.2 MB/s").
      92            1 :   String get networkSpeedHuman {
      93            1 :     if (networkSpeed == null) return 'n/a';
      94            5 :     if (networkSpeed! < 1024) return '${networkSpeed!.toStringAsFixed(1)} B/s';
      95            3 :     if (networkSpeed! < 1024 * 1024) {
      96            4 :       return '${(networkSpeed! / 1024).toStringAsFixed(1)} KB/s';
      97              :     }
      98            5 :     return '${(networkSpeed! / (1024 * 1024)).toStringAsFixed(1)} MB/s';
      99              :   }
     100              : 
     101              :   /// Returns the estimated time remaining in a human-readable format (e.g., "2m 15s").
     102            1 :   String get timeRemainingHuman {
     103            1 :     if (timeRemaining == null) return 'unknown';
     104            6 :     if (timeRemaining!.inSeconds < 60) return '${timeRemaining!.inSeconds}s';
     105            3 :     if (timeRemaining!.inMinutes < 60) {
     106            3 :       final s = timeRemaining!.inSeconds % 60;
     107            3 :       return '${timeRemaining!.inMinutes}m ${s}s';
     108              :     }
     109            3 :     final m = timeRemaining!.inMinutes % 60;
     110            3 :     return '${timeRemaining!.inHours}h ${m}m';
     111              :   }
     112              : }
        

Generated by: LCOV version 2.4-0