LCOV - code coverage report
Current view: top level - src/workers - native_worker_file.dart Coverage Total Hit
Test: lcov.info Lines: 100.0 % 29 29
Test Date: 2026-04-30 18:23:23 Functions: - 0 0

            Line data    Source code
       1              : part of '../worker.dart';
       2              : 
       3              : /// File compression worker (ZIP format).
       4              : ///
       5              : /// Compresses files or directories into ZIP archives in the background.
       6              : /// Runs in native code **without** Flutter Engine for maximum efficiency.
       7              : /// Perfect for log archiving, backup preparation, or reducing upload sizes.
       8              : ///
       9              : /// ## Basic File Compression
      10              : ///
      11              : /// ```dart
      12              : /// await NativeWorkManager.enqueue(
      13              : ///   taskId: 'compress-logs',
      14              : ///   trigger: TaskTrigger.oneTime(),
      15              : ///   worker: NativeWorker.fileCompress(
      16              : ///     inputPath: '/app/logs/app.log',
      17              : ///     outputPath: '/app/archive/logs.zip',
      18              : ///   ),
      19              : /// );
      20              : /// ```
      21              : ///
      22              : /// ## Compress Directory with Options
      23              : ///
      24              : /// ```dart
      25              : /// await NativeWorkManager.enqueue(
      26              : ///   taskId: 'compress-directory',
      27              : ///   trigger: TaskTrigger.oneTime(),
      28              : ///   worker: NativeWorker.fileCompress(
      29              : ///     inputPath: '/app/data/',
      30              : ///     outputPath: '/app/backups/data_${DateTime.now()}.zip',
      31              : ///     level: CompressionLevel.high,
      32              : ///     excludePatterns: ['*.tmp', '.DS_Store', '*.bak'],
      33              : ///     deleteOriginal: false,
      34              : ///   ),
      35              : /// );
      36              : /// ```
      37              : ///
      38              : /// ## Compress and Delete Original
      39              : ///
      40              : /// ```dart
      41              : /// // Archive old logs and delete originals to save space
      42              : /// await NativeWorkManager.enqueue(
      43              : ///   taskId: 'archive-old-logs',
      44              : ///   trigger: TaskTrigger.oneTime(),
      45              : ///   worker: NativeWorker.fileCompress(
      46              : ///     inputPath: '/app/logs/2025/',
      47              : ///     outputPath: '/app/archive/logs_2025.zip',
      48              : ///     level: CompressionLevel.medium,
      49              : ///     deleteOriginal: true,  // Delete source after compression
      50              : ///   ),
      51              : ///   constraints: Constraints(requiresStorageNotLow: true),
      52              : /// );
      53              : /// ```
      54              : ///
      55              : /// ## Periodic Log Archiving
      56              : ///
      57              : /// ```dart
      58              : /// // Compress logs daily
      59              : /// await NativeWorkManager.enqueue(
      60              : ///   taskId: 'daily-log-archive',
      61              : ///   trigger: TaskTrigger.periodic(Duration(days: 1)),
      62              : ///   worker: NativeWorker.fileCompress(
      63              : ///     inputPath: '/app/logs/',
      64              : ///     outputPath: '/app/archive/logs_\${DateTime.now().day}.zip',
      65              : ///     excludePatterns: ['current.log'],  // Keep current log
      66              : ///   ),
      67              : /// );
      68              : /// ```
      69              : ///
      70              : /// ## Parameters
      71              : ///
      72              : /// **[inputPath]** *(required)* - Path to file or directory to compress.
      73              : /// - Must be absolute path
      74              : /// - Can be a single file or directory
      75              : /// - Directory will be compressed recursively
      76              : /// - Throws `ArgumentError` if empty or doesn't exist
      77              : ///
      78              : /// **[outputPath]** *(required)* - Where to save the ZIP file.
      79              : /// - Must be absolute path ending with .zip
      80              : /// - Parent directory will be created if needed
      81              : /// - Existing file will be overwritten
      82              : /// - Throws `ArgumentError` if empty or doesn't end with .zip
      83              : ///
      84              : /// **[level]** *(optional)* - Compression level (default: medium).
      85              : /// - `CompressionLevel.low` - Faster compression, larger file
      86              : /// - `CompressionLevel.medium` - Balanced (recommended)
      87              : /// - `CompressionLevel.high` - Best compression, slower
      88              : ///
      89              : /// **[excludePatterns]** *(optional)* - Patterns to exclude (default: empty).
      90              : /// - Supports wildcards: `*.tmp`, `temp*`, `*backup*`
      91              : /// - Exact match: `.DS_Store`, `Thumbs.db`
      92              : /// - Case-insensitive matching
      93              : ///
      94              : /// **[deleteOriginal]** *(optional)* - Delete source after compression (default: false).
      95              : /// - Use with caution!
      96              : /// - Only deletes if compression succeeds
      97              : /// - Cannot be undone
      98              : ///
      99              : /// ## Progress Tracking
     100              : ///
     101              : /// ```dart
     102              : /// // Listen to compression progress
     103              : /// NativeWorkManager.progress
     104              : ///     .where((p) => p.taskId == 'my-compression')
     105              : ///     .listen((progress) {
     106              : ///   print('Compressed: ${progress.currentStep}/${progress.totalSteps} files');
     107              : ///   print('Progress: ${progress.progress}%');
     108              : /// });
     109              : /// ```
     110              : ///
     111              : /// ## Behavior
     112              : ///
     113              : /// - Compresses using ZIP format (universal compatibility)
     114              : /// - Preserves file modification times
     115              : /// - Creates parent directories automatically
     116              : /// - Overwrites existing output file
     117              : /// - Reports progress via [NativeWorkManager.progress] stream
     118              : /// - Task succeeds if compression completes successfully
     119              : /// - Task fails on I/O error, missing file, or insufficient storage
     120              : ///
     121              : /// ## When to Use
     122              : ///
     123              : /// ✅ **Use fileCompress when:**
     124              : /// - Archiving log files periodically
     125              : /// - Preparing backups for upload
     126              : /// - Reducing file sizes before transfer
     127              : /// - Freeing up storage space
     128              : /// - Creating distributable packages
     129              : ///
     130              : /// ❌ **Don't use fileCompress when:**
     131              : /// - Files are already compressed (JPEG, PNG, MP4, PDF)
     132              : /// - Need other formats (7z, RAR, tar.gz) → Use custom worker
     133              : /// - Need encryption → Use FileEncryptionWorker (v1.1+)
     134              : ///
     135              : /// ## Common Pitfalls
     136              : ///
     137              : /// ❌ **Don't** compress already-compressed files (no benefit)
     138              : /// ❌ **Don't** use deleteOriginal without backup
     139              : /// ❌ **Don't** forget storage constraints for large files
     140              : /// ❌ **Don't** compress system directories
     141              : /// ✅ **Do** use excludePatterns to skip unnecessary files
     142              : /// ✅ **Do** check available storage before large compressions
     143              : /// ✅ **Do** use periodic tasks for automated archiving
     144              : /// ✅ **Do** test with small files first
     145              : ///
     146              : /// ## Platform Notes
     147              : ///
     148              : /// **Android:**
     149              : /// - Uses `java.util.zip.ZipOutputStream`
     150              : /// - Supports all compression levels
     151              : /// - No file size limit (system dependent)
     152              : ///
     153              : /// **iOS:**
     154              : /// - Uses `Compression` framework (iOS 13+)
     155              : /// - Supports all compression levels
     156              : /// - No file size limit (system dependent)
     157              : ///
     158              : /// ## Performance
     159              : ///
     160              : /// | File Size | Low | Medium | High | Note |
     161              : /// |-----------|-----|--------|------|------|
     162              : /// | 10 MB | ~1s | ~2s | ~3s | Text files |
     163              : /// | 100 MB | ~8s | ~15s | ~25s | Mixed content |
     164              : /// | 1 GB | ~80s | ~150s | ~250s | Use constraints! |
     165              : ///
     166              : /// **Tip:** For large files (>100MB), use:
     167              : /// ```dart
     168              : /// constraints: Constraints(
     169              : ///   requiresCharging: true,
     170              : ///   requiresDeviceIdle: true,
     171              : ///   requiresStorageNotLow: true,
     172              : /// )
     173              : /// ```
     174              : ///
     175              : /// ## See Also
     176              : ///
     177              : /// - [NativeWorker.httpUpload] - Upload compressed files
     178              : /// - [NativeWorkManager.progress] - Track compression progress
     179              : /// - [NativeWorker.custom] - Custom compression formats
     180            4 : Worker _buildFileCompress({
     181              :   required String inputPath,
     182              :   required String outputPath,
     183              :   CompressionLevel level = CompressionLevel.medium,
     184              :   List<String> excludePatterns = const [],
     185              :   bool deleteOriginal = false,
     186              : }) {
     187            4 :   NativeWorker._validateFilePath(inputPath, 'inputPath');
     188            4 :   NativeWorker._validateFilePath(outputPath, 'outputPath');
     189              : 
     190            8 :   if (!outputPath.toLowerCase().endsWith('.zip')) {
     191            4 :     throw ArgumentError(
     192              :       'Output path must end with .zip\n'
     193              :       'Current: $outputPath\n'
     194              :       'Example: /app/archive/backup.zip',
     195              :     );
     196              :   }
     197              : 
     198            4 :   return FileCompressionWorker(
     199              :     inputPath: inputPath,
     200              :     outputPath: outputPath,
     201              :     level: level,
     202              :     excludePatterns: excludePatterns,
     203              :     deleteOriginal: deleteOriginal,
     204              :   );
     205              : }
     206              : 
     207              : /// File decompression worker (ZIP extraction).
     208              : ///
     209              : /// Extracts files from ZIP archives in the background. Supports password-protected
     210              : /// archives, selective extraction, and zip bomb protection. Runs in native code
     211              : /// **without** Flutter Engine for maximum efficiency.
     212              : ///
     213              : /// ## Basic Extraction
     214              : ///
     215              : /// ```dart
     216              : /// await NativeWorkManager.enqueue(
     217              : ///   taskId: 'extract-backup',
     218              : ///   trigger: TaskTrigger.oneTime(),
     219              : ///   worker: NativeWorker.fileDecompress(
     220              : ///     archivePath: '/app/downloads/backup.zip',
     221              : ///     destinationPath: '/app/data/restored/',
     222              : ///   ),
     223              : /// );
     224              : /// ```
     225              : ///
     226              : /// ## Extract Specific Files Only
     227              : ///
     228              : /// ```dart
     229              : /// await NativeWorkManager.enqueue(
     230              : ///   taskId: 'extract-config',
     231              : ///   trigger: TaskTrigger.oneTime(),
     232              : ///   worker: NativeWorker.fileDecompress(
     233              : ///     archivePath: '/app/downloads/package.zip',
     234              : ///     destinationPath: '/app/config/',
     235              : ///     extractFiles: ['config.json', 'settings.xml'],
     236              : ///   ),
     237              : /// );
     238              : /// ```
     239              : ///
     240              : /// ## Password-Protected Archive
     241              : ///
     242              : /// ```dart
     243              : /// await NativeWorkManager.enqueue(
     244              : ///   taskId: 'extract-secure',
     245              : ///   trigger: TaskTrigger.oneTime(),
     246              : ///   worker: NativeWorker.fileDecompress(
     247              : ///     archivePath: '/app/downloads/secure.zip',
     248              : ///     destinationPath: '/app/private/',
     249              : ///     password: 'mySecurePassword',
     250              : ///   ),
     251              : /// );
     252              : /// ```
     253              : ///
     254              : /// ## Extract and Delete Archive
     255              : ///
     256              : /// ```dart
     257              : /// await NativeWorkManager.enqueue(
     258              : ///   taskId: 'extract-temp',
     259              : ///   trigger: TaskTrigger.oneTime(),
     260              : ///   worker: NativeWorker.fileDecompress(
     261              : ///     zipPath: '/app/downloads/data.zip',
     262              : ///     targetDir: '/app/temp/',
     263              : ///     deleteAfterExtract: true,  // Save storage space
     264              : ///     overwrite: true,
     265              : ///   ),
     266              : /// );
     267              : /// ```
     268              : ///
     269              : /// ## Complete Workflow: Download → Extract → Process
     270              : ///
     271              : /// ```dart
     272              : /// // Step 1: Download ZIP
     273              : /// await NativeWorkManager.enqueue(
     274              : ///   taskId: 'download-data',
     275              : ///   trigger: TaskTrigger.oneTime(),
     276              : ///   worker: NativeWorker.httpDownload(
     277              : ///     url: 'https://cdn.example.com/data.zip',
     278              : ///     savePath: '/app/downloads/data.zip',
     279              : ///   ),
     280              : /// );
     281              : ///
     282              : /// // Step 2: Extract downloaded ZIP
     283              : /// await NativeWorkManager.enqueue(
     284              : ///   taskId: 'extract-data',
     285              : ///   trigger: TaskTrigger.contentUri(taskId: 'download-data'),
     286              : ///   worker: NativeWorker.fileDecompress(
     287              : ///     zipPath: '/app/downloads/data.zip',
     288              : ///     targetDir: '/app/data/',
     289              : ///     deleteAfterExtract: true,
     290              : ///   ),
     291              : /// );
     292              : /// ```
     293              : ///
     294              : /// ## Parameters
     295              : ///
     296              : /// **[zipPath]** *(required)* - Path to ZIP archive to extract.
     297              : /// - Must be absolute path
     298              : /// - File must exist at execution time
     299              : /// - Throws `ArgumentError` if empty
     300              : ///
     301              : /// **[targetDir]** *(required)* - Directory where files will be extracted.
     302              : /// - Must be absolute path
     303              : /// - Directory will be created if it doesn't exist
     304              : /// - Throws `ArgumentError` if empty
     305              : ///
     306              : /// **[deleteAfterExtract]** *(optional)* - Delete archive after extraction (default: false).
     307              : /// - Saves storage space
     308              : /// - Only deletes if extraction succeeds
     309              : /// - Use with caution!
     310              : ///
     311              : /// **[overwrite]** *(optional)* - Overwrite existing files (default: true).
     312              : /// - If false, skips files that already exist
     313              : /// - If true, replaces existing files
     314              : ///
     315              : /// ## Progress Tracking
     316              : ///
     317              : /// ```dart
     318              : /// // Listen to extraction progress
     319              : /// NativeWorkManager.progress
     320              : ///     .where((p) => p.taskId == 'my-extraction')
     321              : ///     .listen((progress) {
     322              : ///   print('Extracted: ${progress.currentStep}/${progress.totalSteps} files');
     323              : ///   print('Progress: ${progress.progress}%');
     324              : /// });
     325              : /// ```
     326              : ///
     327              : /// ## Behavior
     328              : ///
     329              : /// - Extracts all files preserving directory structure
     330              : /// - Creates destination directory if needed
     331              : /// - Path traversal protection (prevents ../../../ attacks)
     332              : /// - Validates uncompressed size before extraction
     333              : /// - Reports progress via [NativeWorkManager.progress] stream
     334              : /// - Task succeeds if extraction completes successfully
     335              : /// - Task fails on I/O error, wrong password, or zip bomb detected
     336              : ///
     337              : /// ## When to Use
     338              : ///
     339              : /// ✅ **Use fileDecompress when:**
     340              : /// - Extracting downloaded content packages
     341              : /// - Restoring backups
     342              : /// - Unpacking app resources
     343              : /// - Processing uploaded archives
     344              : /// - Handling OTA update packages
     345              : ///
     346              : /// ❌ **Don't use fileDecompress when:**
     347              : /// - Archive format is not ZIP → Use custom worker
     348              : /// - Need to extract on-the-fly during download → Use streaming
     349              : /// - Archive is untrusted → Validate maxSizeBytes carefully
     350              : ///
     351              : /// ## Security Notes
     352              : ///
     353              : /// **Zip Bomb Protection:**
     354              : /// - Built-in validation prevents decompression bombs
     355              : /// - Checks extracted size during extraction
     356              : /// - Task fails if suspicious expansion detected
     357              : ///
     358              : /// **Path Traversal Protection:**
     359              : /// - Automatically validates all file paths
     360              : /// - Prevents extraction outside destination directory
     361              : /// - Blocks malicious paths like `../../etc/passwd`
     362              : ///
     363              : /// ## Common Pitfalls
     364              : ///
     365              : /// ❌ **Don't** extract untrusted archives without validation
     366              : /// ❌ **Don't** use deleteAfterExtract without verifying extraction success
     367              : /// ❌ **Don't** forget to handle task failure (archive may be corrupt)
     368              : /// ❌ **Don't** extract to system directories
     369              : /// ✅ **Do** use storage constraints for large archives
     370              : /// ✅ **Do** validate archive integrity before extraction
     371              : /// ✅ **Do** test with known-good archives first
     372              : ///
     373              : /// ## Platform Notes
     374              : ///
     375              : /// **Android:**
     376              : /// - Uses standard Java ZIP libraries
     377              : /// - Supports all ZIP formats including ZIP64
     378              : /// - Streaming extraction (low memory)
     379              : ///
     380              : /// **iOS:**
     381              : /// - Uses ZIPFoundation framework
     382              : /// - Streaming extraction (low memory)
     383              : /// - Built-in security validations
     384              : ///
     385              : /// ## Future Features (v1.1.0)
     386              : ///
     387              : /// - Password-protected ZIP support
     388              : /// - Selective file extraction
     389              : /// - Custom extraction filters
     390              : ///
     391              : /// ## Performance
     392              : ///
     393              : /// | Archive Size | Files | Time | Note |
     394              : /// |--------------|-------|------|------|
     395              : /// | 10 MB | 100 | ~1s | Small packages |
     396              : /// | 100 MB | 1000 | ~8s | Medium backups |
     397              : /// | 500 MB | 5000 | ~40s | Large archives |
     398              : ///
     399              : /// **Tip:** For large archives (>100MB), use:
     400              : /// ```dart
     401              : /// constraints: Constraints(
     402              : ///   requiresStorageNotLow: true,
     403              : /// )
     404              : /// ```
     405              : ///
     406              : /// ## See Also
     407              : ///
     408              : /// - `NativeWorker.fileCompress` (deprecated v1.1.0 — use `archive` package)
     409              : /// - [NativeWorker.httpDownload] - Download ZIP archives
     410              : /// - [NativeWorkManager.progress] - Track extraction progress
     411            4 : Worker _buildFileDecompress({
     412              :   required String zipPath,
     413              :   required String targetDir,
     414              :   bool deleteAfterExtract = false,
     415              :   bool overwrite = true,
     416              : }) {
     417            4 :   NativeWorker._validateFilePath(zipPath, 'zipPath');
     418            4 :   NativeWorker._validateFilePath(targetDir, 'targetDir');
     419              : 
     420            8 :   if (!zipPath.toLowerCase().endsWith('.zip')) {
     421            4 :     throw ArgumentError(
     422              :       'ZIP path must end with .zip\n'
     423              :       'Current: $zipPath\n'
     424              :       'Example: /app/downloads/archive.zip',
     425              :     );
     426              :   }
     427              : 
     428            3 :   return FileDecompressionWorker(
     429              :     zipPath: zipPath,
     430              :     targetDir: targetDir,
     431              :     deleteAfterExtract: deleteAfterExtract,
     432              :     overwrite: overwrite,
     433              :   );
     434              : }
     435              : 
     436              : /// Copy file or directory worker.
     437              : ///
     438              : /// Copies files or directories for pure-native task chains **without** Flutter Engine.
     439              : /// Useful for organizing files, creating backups, or duplicating data.
     440              : ///
     441              : /// ## Basic File Copy
     442              : ///
     443              : /// ```dart
     444              : /// await NativeWorkManager.enqueue(
     445              : ///   taskId: 'copy-file',
     446              : ///   trigger: TaskTrigger.oneTime(),
     447              : ///   worker: NativeWorker.fileCopy(
     448              : ///     sourcePath: '/downloads/photo.jpg',
     449              : ///     destinationPath: '/backups/photo.jpg',
     450              : ///   ),
     451              : /// );
     452              : /// ```
     453              : ///
     454              : /// ## Copy Directory
     455              : ///
     456              : /// ```dart
     457              : /// await NativeWorkManager.enqueue(
     458              : ///   taskId: 'copy-directory',
     459              : ///   trigger: TaskTrigger.oneTime(),
     460              : ///   worker: NativeWorker.fileCopy(
     461              : ///     sourcePath: '/photos/vacation',
     462              : ///     destinationPath: '/backups/vacation',
     463              : ///     recursive: true,
     464              : ///   ),
     465              : /// );
     466              : /// ```
     467              : ///
     468              : /// ## Parameters
     469              : ///
     470              : /// **[sourcePath]** *(required)* - Path to source file or directory.
     471              : ///
     472              : /// **[destinationPath]** *(required)* - Where to copy the file/directory.
     473              : ///
     474              : /// **[overwrite]** *(optional)* - Overwrite if destination exists (default: false).
     475              : ///
     476              : /// **[recursive]** *(optional)* - Copy directories recursively (default: true).
     477              : ///
     478              : /// ## See Also
     479              : ///
     480              : /// - [NativeWorker.fileMove] - Move files instead of copying
     481              : /// - [NativeWorker.fileDelete] - Delete files
     482            3 : Worker _buildFileCopy({
     483              :   required String sourcePath,
     484              :   required String destinationPath,
     485              :   bool overwrite = false,
     486              :   bool recursive = true,
     487              : }) {
     488            3 :   NativeWorker._validateFilePath(sourcePath, 'sourcePath');
     489            3 :   NativeWorker._validateFilePath(destinationPath, 'destinationPath');
     490              : 
     491            3 :   return FileSystemCopyWorker(
     492              :     sourcePath: sourcePath,
     493              :     destinationPath: destinationPath,
     494              :     overwrite: overwrite,
     495              :     recursive: recursive,
     496              :   );
     497              : }
     498              : 
     499              : /// Move file or directory worker.
     500              : ///
     501              : /// Moves files or directories for pure-native task chains **without** Flutter Engine.
     502              : /// More efficient than copy+delete for large files (atomic operation when possible).
     503              : ///
     504              : /// ## Basic File Move
     505              : ///
     506              : /// ```dart
     507              : /// await NativeWorkManager.enqueue(
     508              : ///   taskId: 'move-file',
     509              : ///   trigger: TaskTrigger.oneTime(),
     510              : ///   worker: NativeWorker.fileMove(
     511              : ///     sourcePath: '/temp/download.zip',
     512              : ///     destinationPath: '/downloads/file.zip',
     513              : ///   ),
     514              : /// );
     515              : /// ```
     516              : ///
     517              : /// ## Parameters
     518              : ///
     519              : /// **[sourcePath]** *(required)* - Path to source file or directory.
     520              : ///
     521              : /// **[destinationPath]** *(required)* - Where to move the file/directory.
     522              : ///
     523              : /// **[overwrite]** *(optional)* - Overwrite if destination exists (default: false).
     524              : ///
     525              : /// ## See Also
     526              : ///
     527              : /// - [NativeWorker.fileCopy] - Copy files instead of moving
     528              : /// - [NativeWorker.fileDelete] - Delete files after processing
     529            3 : Worker _buildFileMove({
     530              :   required String sourcePath,
     531              :   required String destinationPath,
     532              :   bool overwrite = false,
     533              : }) {
     534            3 :   NativeWorker._validateFilePath(sourcePath, 'sourcePath');
     535            3 :   NativeWorker._validateFilePath(destinationPath, 'destinationPath');
     536              : 
     537            3 :   return FileSystemMoveWorker(
     538              :     sourcePath: sourcePath,
     539              :     destinationPath: destinationPath,
     540              :     overwrite: overwrite,
     541              :   );
     542              : }
     543              : 
     544              : /// Delete file or directory worker.
     545              : ///
     546              : /// Deletes files or directories for cleanup in pure-native task chains **without** Flutter Engine.
     547              : ///
     548              : /// ## Basic File Delete
     549              : ///
     550              : /// ```dart
     551              : /// await NativeWorkManager.enqueue(
     552              : ///   taskId: 'cleanup',
     553              : ///   trigger: TaskTrigger.oneTime(),
     554              : ///   worker: NativeWorker.fileDelete(
     555              : ///     path: '/temp/cache.dat',
     556              : ///   ),
     557              : /// );
     558              : /// ```
     559              : ///
     560              : /// ## Delete Directory
     561              : ///
     562              : /// ```dart
     563              : /// await NativeWorkManager.enqueue(
     564              : ///   taskId: 'cleanup-temp',
     565              : ///   trigger: TaskTrigger.oneTime(),
     566              : ///   worker: NativeWorker.fileDelete(
     567              : ///     path: '/temp',
     568              : ///     recursive: true,  // Delete all contents
     569              : ///   ),
     570              : /// );
     571              : /// ```
     572              : ///
     573              : /// ## Parameters
     574              : ///
     575              : /// **[path]** *(required)* - Path to file or directory to delete.
     576              : ///
     577              : /// **[recursive]** *(optional)* - Delete directories recursively (default: false).
     578              : /// - If false and path is directory, task fails
     579              : /// - If true, deletes directory and all contents
     580              : ///
     581              : /// ## Safety
     582              : ///
     583              : /// - Protected paths (/, /system, etc.) cannot be deleted
     584              : /// - Deletion is permanent (no trash/recycle bin)
     585              : ///
     586              : /// ## See Also
     587              : ///
     588              : /// - [NativeWorker.fileCopy] - Copy files before deleting
     589              : /// - [NativeWorker.fileMove] - Move files instead of deleting
     590            4 : Worker _buildFileDelete({required String path, bool recursive = false}) {
     591            4 :   NativeWorker._validateFilePath(path, 'path');
     592              : 
     593            3 :   return FileSystemDeleteWorker(path: path, recursive: recursive);
     594              : }
     595              : 
     596              : /// List directory contents worker.
     597              : ///
     598              : /// Lists files in a directory for pure-native task chains **without** Flutter Engine.
     599              : /// Useful for scanning directories, finding files, or building file indexes.
     600              : ///
     601              : /// ## Basic Directory Listing
     602              : ///
     603              : /// ```dart
     604              : /// await NativeWorkManager.enqueue(
     605              : ///   taskId: 'list-files',
     606              : ///   trigger: TaskTrigger.oneTime(),
     607              : ///   worker: NativeWorker.fileList(
     608              : ///     path: '/downloads',
     609              : ///   ),
     610              : /// );
     611              : /// ```
     612              : ///
     613              : /// ## List with Pattern
     614              : ///
     615              : /// ```dart
     616              : /// // Find all JPG files
     617              : /// await NativeWorkManager.enqueue(
     618              : ///   taskId: 'find-photos',
     619              : ///   trigger: TaskTrigger.oneTime(),
     620              : ///   worker: NativeWorker.fileList(
     621              : ///     path: '/photos',
     622              : ///     pattern: '*.jpg',
     623              : ///     recursive: true,
     624              : ///   ),
     625              : /// );
     626              : /// ```
     627              : ///
     628              : /// ## Parameters
     629              : ///
     630              : /// **[path]** *(required)* - Directory path to list.
     631              : ///
     632              : /// **[pattern]** *(optional)* - Glob pattern to filter files (e.g., "*.jpg", "file_*.txt").
     633              : /// - Supports wildcards: `*` (any chars), `?` (single char)
     634              : /// - Example: `*.jpg` matches all JPEG files
     635              : /// - Example: `photo_?.png` matches `photo_1.png`, `photo_a.png`
     636              : ///
     637              : /// **[recursive]** *(optional)* - List subdirectories recursively (default: false).
     638              : ///
     639              : /// ## Result
     640              : ///
     641              : /// Returns list of file info with:
     642              : /// - `path` - Full file path
     643              : /// - `name` - File name
     644              : /// - `size` - File size in bytes
     645              : /// - `lastModified` - Last modification timestamp
     646              : ///
     647              : /// ## See Also
     648              : ///
     649              : /// - [NativeWorker.fileDelete] - Delete found files
     650              : /// - [NativeWorker.fileCopy] - Copy found files
     651            2 : Worker _buildFileList({
     652              :   required String path,
     653              :   String? pattern,
     654              :   bool recursive = false,
     655              : }) {
     656            2 :   NativeWorker._validateFilePath(path, 'path');
     657              : 
     658            2 :   return FileSystemListWorker(
     659              :     path: path,
     660              :     pattern: pattern,
     661              :     recursive: recursive,
     662              :   );
     663              : }
     664              : 
     665              : /// Create directory worker (mkdir).
     666              : ///
     667              : /// Creates directories for pure-native task chains **without** Flutter Engine.
     668              : /// Useful for setting up folder structure before file operations.
     669              : ///
     670              : /// ## Create Directory
     671              : ///
     672              : /// ```dart
     673              : /// await NativeWorkManager.enqueue(
     674              : ///   taskId: 'create-backup-dir',
     675              : ///   trigger: TaskTrigger.oneTime(),
     676              : ///   worker: NativeWorker.fileMkdir(
     677              : ///     path: '/backups/2024-02-07',
     678              : ///   ),
     679              : /// );
     680              : /// ```
     681              : ///
     682              : /// ## Parameters
     683              : ///
     684              : /// **[path]** *(required)* - Directory path to create.
     685              : ///
     686              : /// **[createParents]** *(optional)* - Create parent directories if needed (default: true).
     687              : /// - If true, creates `/backups/2024/02/07` even if `/backups` doesn't exist
     688              : /// - If false, fails if parent doesn't exist
     689              : ///
     690              : /// ## See Also
     691              : ///
     692              : /// - [NativeWorker.fileCopy] - Copy files after creating directory
     693              : /// - [NativeWorker.fileMove] - Move files to new directory
     694            2 : Worker _buildFileMkdir({required String path, bool createParents = true}) {
     695            2 :   NativeWorker._validateFilePath(path, 'path');
     696              : 
     697            2 :   return FileSystemMkdirWorker(path: path, createParents: createParents);
     698              : }
        

Generated by: LCOV version 2.4-0