native_workmanager 1.0.2 copy "native_workmanager: ^1.0.2" to clipboard
native_workmanager: ^1.0.2 copied to clipboard

Background task manager for Flutter using platform-native APIs. Zero Flutter Engine overhead for I/O operations.

example/lib/main.dart

import 'dart:io';
import 'dart:typed_data'; // Added for Uint8List
import 'package:path_provider/path_provider.dart'; // Added for getTemporaryDirectory

import 'package:flutter/material.dart';
import 'package:workmanager/workmanager.dart' hide Constraints, BackoffPolicy;
import 'package:native_workmanager/native_workmanager.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'advanced_metrics_overlay.dart';
import 'pages/manual_benchmark_page.dart';
import 'pages/production_impact_page_improved.dart';
import 'pages/demo_scenarios_page.dart';
import 'pages/comprehensive_demo_page.dart';
import 'pages/performance_page.dart';
import 'examples/chain_resilience_test.dart';
import 'examples/chain_data_flow_demo.dart';

/// workmanager background callback.
/// Runs in a separate isolate โ€” communicates completion back via SharedPreferences.
@pragma('vm:entry-point')
void flutterWorkmanagerCallback() {
  Workmanager().executeTask((taskName, inputData) async {
    final completionKey = inputData?['completionKey'] as String?;

    try {
      switch (taskName) {
        case 'bench_httpGet':
          final client = HttpClient();
          final req = await client.getUrl(Uri.parse('https://httpbin.org/get'));
          await req.close();
          client.close();

        case 'bench_httpPost':
          final client = HttpClient();
          final req = await client.postUrl(
            Uri.parse('https://httpbin.org/post'),
          );
          req.headers.contentType = ContentType.json;
          req.write(
            '{"benchmark":true,"ts":${DateTime.now().millisecondsSinceEpoch}}',
          );
          await req.close();
          client.close();

        case 'bench_jsonSync':
          final client = HttpClient();
          final req = await client.postUrl(
            Uri.parse('https://httpbin.org/post'),
          );
          req.headers.contentType = ContentType.json;
          req.write(
            '{"sync":true,"ts":${DateTime.now().millisecondsSinceEpoch}}',
          );
          final resp = await req.close();
          await resp.toList();
          client.close();

        case 'bench_fileDownload':
          final client = HttpClient();
          final req = await client.getUrl(
            Uri.parse('https://httpbin.org/bytes/51200'),
          );
          final resp = await req.close();
          await resp.toList();
          client.close();

        case 'bench_heavyCompute':
          // Reduced from 40 to 38 for better performance on emulators
          // fib(40) can take 30-60+ seconds on slow devices
          fibonacciCompute(38);

        default:
          return false;
      }

      // Signal completion to main thread
      if (completionKey != null) {
        final prefs = await SharedPreferences.getInstance();
        await prefs.setInt(
          completionKey,
          DateTime.now().millisecondsSinceEpoch,
        );
      }
      return true;
    } catch (e) {
      return false;
    }
  });
}

/// CPU-intensive Fibonacci โ€” used by both libs for heavy compute benchmark.
int fibonacciCompute(int n) {
  if (n <= 1) return n;
  return fibonacciCompute(n - 1) + fibonacciCompute(n - 2);
}

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Initialize workmanager (for A/B benchmark comparison only)
  Workmanager().initialize(flutterWorkmanagerCallback);

  // Initialize native_workmanager
  await NativeWorkManager.initialize(
    dartWorkers: {
      'customTask': customTaskCallback,
      'heavyTask': heavyTaskCallback,
      'benchHeavyCompute': benchHeavyComputeCallback,
    },
  );

  runApp(const MyApp());

  // Performance benchmarks - DISABLED by default to avoid auto-running tasks on app start
  // Users can run benchmarks manually from the Performance page
  debugPrint('๐Ÿ’ก Benchmarks disabled - Use Performance page to run manually');
}

/// Heavy compute callback for A/B benchmark (runs inside native_workmanager's cached engine).
@pragma('vm:entry-point')
Future<bool> benchHeavyComputeCallback(Map<String, dynamic>? input) async {
  fibonacciCompute(40);
  return true;
}

/// Custom Dart worker callback.
@pragma('vm:entry-point')
Future<bool> customTaskCallback(Map<String, dynamic>? input) async {
  debugPrint('๐Ÿ“ฑ Dart Worker: Executing custom task with input: $input');
  await Future.delayed(const Duration(seconds: 2));
  debugPrint('๐Ÿ“ฑ Dart Worker: Task completed successfully');
  return true;
}

/// Heavy task callback (for isHeavyTask demo).
@pragma('vm:entry-point')
Future<bool> heavyTaskCallback(Map<String, dynamic>? input) async {
  debugPrint('โš™๏ธ Heavy Task: Starting long-running work...');

  // Simulate heavy processing
  for (int i = 0; i < 10; i++) {
    await Future.delayed(const Duration(seconds: 1));
    debugPrint('โš™๏ธ Heavy Task: Progress ${(i + 1) * 10}%');
  }

  debugPrint('โš™๏ธ Heavy Task: Completed!');
  return true;
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Native WorkManager v1.0.0 Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
        useMaterial3: true,
      ),
      home: const DemoHomePage(),
    );
  }
}

class DemoHomePage extends StatefulWidget {
  const DemoHomePage({super.key});

  @override
  State<DemoHomePage> createState() => _DemoHomePageState();
}

class _DemoHomePageState extends State<DemoHomePage>
    with SingleTickerProviderStateMixin {
  late TabController _tabController;
  final List<String> _logs = [];
  int _taskCounter = 0;
  bool _showMetricsOverlay = false;

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: 14, vsync: this);

    // Listen to task events (v2.3.0+: includes resultData)
    NativeWorkManager.events.listen((event) {
      setState(() {
        var logMessage =
            '${_formatTime(event.timestamp)} '
            '${event.success ? "โœ…" : "โŒ"} '
            '${event.taskId}: '
            '${event.message ?? (event.success ? "Success" : "Failed")}';

        // v2.3.0+: Show result data if available
        if (event.resultData != null && event.resultData!.isNotEmpty) {
          final data = event.resultData!;
          if (data.containsKey('filePath')) {
            logMessage +=
                ' | File: ${data['fileName']}, Size: ${data['fileSize']} bytes';
          } else if (data.containsKey('statusCode')) {
            logMessage += ' | HTTP ${data['statusCode']}';
          } else if (data.containsKey('compressionRatio')) {
            logMessage +=
                ' | ${data['filesCompressed']} files, ${data['compressionRatio']}% ratio';
          }
        }

        _logs.insert(0, logMessage);
        if (_logs.length > 50) _logs.removeLast();
      });
    });

    _addLog('๐Ÿš€ Native WorkManager v1.0.0 initialized (100% KMP parity)');
  }

  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

  String _formatTime(DateTime dt) {
    return '${dt.hour.toString().padLeft(2, '0')}:'
        '${dt.minute.toString().padLeft(2, '0')}:'
        '${dt.second.toString().padLeft(2, '0')}';
  }

  void _addLog(String message) {
    setState(() {
      _logs.insert(0, '${_formatTime(DateTime.now())} $message');
      if (_logs.length > 50) _logs.removeLast();
    });
  }

  // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
  // TAB 1: Basic Tasks (Native Workers)
  // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

  Future<void> _scheduleHttpGet() async {
    final taskId = 'http-get-${_taskCounter++}';
    try {
      await NativeWorkManager.enqueue(
        taskId: taskId,
        trigger: TaskTrigger.oneTime(),
        worker: HttpRequestWorker(
          url: 'https://httpbin.org/get',
          method: HttpMethod.get,
        ),
      );
      _addLog('๐Ÿ“ค Scheduled: HTTP GET ($taskId)');
    } catch (e) {
      _addLog('โŒ Error: $e');
    }
  }

  Future<void> _scheduleHttpPost() async {
    final taskId = 'http-post-${_taskCounter++}';
    try {
      await NativeWorkManager.enqueue(
        taskId: taskId,
        trigger: TaskTrigger.oneTime(),
        worker: HttpRequestWorker(
          url: 'https://httpbin.org/post',
          method: HttpMethod.post,
          headers: const {'Content-Type': 'application/json'},
          body: '{"timestamp":${DateTime.now().millisecondsSinceEpoch}}',
        ),
      );
      _addLog('๐Ÿ“ค Scheduled: HTTP POST ($taskId)');
    } catch (e) {
      _addLog('โŒ Error: $e');
    }
  }

  Future<void> _scheduleSync() async {
    final taskId = 'sync-${_taskCounter++}';
    try {
      await NativeWorkManager.enqueue(
        taskId: taskId,
        trigger: TaskTrigger.oneTime(),
        worker: HttpSyncWorker(
          url: 'https://httpbin.org/post',
          method: HttpMethod.post,
          requestBody: {
            'lastSync': DateTime.now().millisecondsSinceEpoch,
            'data': ['item1', 'item2', 'item3'],
          },
        ),
        constraints: const Constraints(requiresNetwork: true),
      );
      _addLog('๐Ÿ“ค Scheduled: JSON Sync ($taskId)');
    } catch (e) {
      _addLog('โŒ Error: $e');
    }
  }

  // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
  // TAB 2: v1.0.0 Features - BackoffPolicy
  // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

  Future<void> _scheduleWithExponentialBackoff() async {
    final taskId = 'backoff-exp-${_taskCounter++}';
    try {
      await NativeWorkManager.enqueue(
        taskId: taskId,
        trigger: TaskTrigger.oneTime(),
        worker: HttpRequestWorker(
          url: 'https://httpbin.org/status/500', // Will fail
          method: HttpMethod.get,
        ),
        constraints: const Constraints(
          requiresNetwork: true,
          backoffPolicy: BackoffPolicy.exponential,
          backoffDelayMs: 10000, // 10s, 20s, 40s, 80s...
        ),
      );
      _addLog('๐Ÿ“ค Scheduled: Exponential Backoff ($taskId)');
      _addLog('โฐ Retry delays: 10s โ†’ 20s โ†’ 40s โ†’ 80s');
    } catch (e) {
      _addLog('โŒ Error: $e');
    }
  }

  Future<void> _scheduleWithLinearBackoff() async {
    final taskId = 'backoff-lin-${_taskCounter++}';
    try {
      await NativeWorkManager.enqueue(
        taskId: taskId,
        trigger: TaskTrigger.oneTime(),
        worker: HttpRequestWorker(
          url: 'https://httpbin.org/status/503', // Will fail
          method: HttpMethod.get,
        ),
        constraints: const Constraints(
          requiresNetwork: true,
          backoffPolicy: BackoffPolicy.linear,
          backoffDelayMs: 15000, // 15s, 15s, 15s, 15s...
        ),
      );
      _addLog('๐Ÿ“ค Scheduled: Linear Backoff ($taskId)');
      _addLog('โฐ Retry delays: 15s โ†’ 15s โ†’ 15s โ†’ 15s');
    } catch (e) {
      _addLog('โŒ Error: $e');
    }
  }

  // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
  // TAB 4: Advanced Constraints
  // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

  Future<void> _scheduleHeavyTask() async {
    final taskId = 'heavy-${_taskCounter++}';
    try {
      await NativeWorkManager.enqueue(
        taskId: taskId,
        trigger: TaskTrigger.oneTime(),
        worker: DartWorker(callbackId: 'heavyTask'),
        constraints: const Constraints(
          isHeavyTask: true, // Uses ForegroundService on Android
          requiresCharging: true,
          requiresUnmeteredNetwork: true,
        ),
      );
      _addLog('๐Ÿ“ค Scheduled: Heavy Task ($taskId)');
      _addLog('โš™๏ธ Will show notification on Android (ForegroundService)');
    } catch (e) {
      _addLog('โŒ Error: $e');
    }
  }

  Future<void> _scheduleWithQoS() async {
    final taskId = 'qos-${_taskCounter++}';
    try {
      await NativeWorkManager.enqueue(
        taskId: taskId,
        trigger: TaskTrigger.oneTime(),
        worker: DartWorker(callbackId: 'customTask'),
        constraints: const Constraints(
          qos: QoS.utility, // Low priority on iOS
        ),
      );
      _addLog('๐Ÿ“ค Scheduled: QoS Task ($taskId)');
      _addLog('๐Ÿ“ฑ Priority: Utility (iOS only)');
    } catch (e) {
      _addLog('โŒ Error: $e');
    }
  }

  // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
  // TAB 5: Task Chains
  // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

  Future<void> _scheduleSequentialChain() async {
    try {
      await NativeWorkManager.beginWith(
            TaskRequest(
              id: 'chain-step-1',
              worker: HttpRequestWorker(
                url: 'https://httpbin.org/get',
                method: HttpMethod.get,
              ),
            ),
          )
          .then(
            TaskRequest(
              id: 'chain-step-2',
              worker: HttpSyncWorker(
                url: 'https://httpbin.org/post',
                method: HttpMethod.post,
                requestBody: {'step': 2},
              ),
            ),
          )
          .then(
            TaskRequest(
              id: 'chain-step-3',
              worker: DartWorker(callbackId: 'customTask'),
            ),
          )
          .named('sequential-chain')
          .enqueue();

      _addLog('๐Ÿ“ค Scheduled: Sequential Chain');
      _addLog('โ›“๏ธ Step 1 โ†’ Step 2 โ†’ Step 3');
    } catch (e) {
      _addLog('โŒ Error: $e');
    }
  }

  Future<void> _scheduleParallelChain() async {
    try {
      await NativeWorkManager.beginWith(
            TaskRequest(
              id: 'parallel-download',
              worker: HttpRequestWorker(
                url: 'https://httpbin.org/get',
                method: HttpMethod.get,
              ),
            ),
          )
          .thenAll([
            TaskRequest(
              id: 'parallel-upload-1',
              worker: HttpRequestWorker(
                url: 'https://httpbin.org/post',
                method: HttpMethod.post,
                body: '{"file":1}',
              ),
            ),
            TaskRequest(
              id: 'parallel-upload-2',
              worker: HttpRequestWorker(
                url: 'https://httpbin.org/post',
                method: HttpMethod.post,
                body: '{"file":2}',
              ),
            ),
          ])
          .named('parallel-chain')
          .enqueue();

      _addLog('๐Ÿ“ค Scheduled: Parallel Chain');
      _addLog('โ›“๏ธ Download โ†’ [Upload1 + Upload2] in parallel');
    } catch (e) {
      _addLog('โŒ Error: $e');
    }
  }

  // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
  // TAB 6: Periodic & Scheduled
  // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

  Future<void> _schedulePeriodicTask() async {
    const taskId = 'periodic-sync';
    try {
      await NativeWorkManager.enqueue(
        taskId: taskId,
        trigger: TaskTrigger.periodic(const Duration(minutes: 15)),
        worker: HttpSyncWorker(
          url: 'https://httpbin.org/post',
          method: HttpMethod.post,
          requestBody: {'type': 'periodic'},
        ),
        constraints: const Constraints(requiresNetwork: true),
      );
      _addLog('๐Ÿ“ค Scheduled: Periodic Task (every 15 min)');
    } catch (e) {
      _addLog('โŒ Error: $e');
    }
  }

  Future<void> _scheduleExactAlarm() async {
    final taskId = 'exact-${_taskCounter++}';
    final scheduledTime = DateTime.now().add(const Duration(minutes: 5));
    try {
      await NativeWorkManager.enqueue(
        taskId: taskId,
        trigger: TaskTrigger.exact(scheduledTime),
        worker: HttpRequestWorker(
          url: 'https://httpbin.org/get',
          method: HttpMethod.get,
        ),
      );
      _addLog('๐Ÿ“ค Scheduled: Exact Alarm ($taskId)');
      _addLog('โฐ Will run at ${_formatTime(scheduledTime)}');
    } catch (e) {
      _addLog('โŒ Error: $e');
    }
  }

  Future<void> _scheduleWindowedTask() async {
    final taskId = 'windowed-${_taskCounter++}';
    try {
      await NativeWorkManager.enqueue(
        taskId: taskId,
        trigger: TaskTrigger.windowed(
          earliest: const Duration(minutes: 2),
          latest: const Duration(minutes: 10),
        ),
        worker: HttpRequestWorker(
          url: 'https://httpbin.org/get',
          method: HttpMethod.get,
        ),
      );
      _addLog('๐Ÿ“ค Scheduled: Windowed Task ($taskId)');
      _addLog('โฐ Will run between 2-10 minutes from now');
    } catch (e) {
      _addLog('โŒ Error: $e');
    }
  }

  // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
  // Common Actions
  // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

  Future<void> _cancelAll() async {
    try {
      await NativeWorkManager.cancelAll();
      _addLog('๐Ÿ—‘๏ธ Cancelled all tasks');
    } catch (e) {
      _addLog('โŒ Error: $e');
    }
  }

  void _clearLogs() {
    setState(() {
      _logs.clear();
    });
    _addLog('๐Ÿงน Logs cleared');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Native WorkManager v1.0.0'),
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        actions: [
          // Toggle metrics overlay button
          IconButton(
            icon: Icon(
              _showMetricsOverlay ? Icons.speed : Icons.speed_outlined,
              color: _showMetricsOverlay ? Colors.green : null,
            ),
            tooltip: 'Toggle Real-time Metrics',
            onPressed: () {
              setState(() {
                _showMetricsOverlay = !_showMetricsOverlay;
              });
            },
          ),
        ],
        bottom: TabBar(
          controller: _tabController,
          isScrollable: true,
          tabs: const [
            Tab(text: 'Demo'),
            Tab(text: 'โœจ All Workers'),
            Tab(text: 'Performance'),
            Tab(text: 'Basic'),
            Tab(text: 'Upload/Download'),
            Tab(text: 'Retry'),
            Tab(text: 'Constraints'),
            Tab(text: 'Chains'),
            Tab(text: 'Scheduled'),
            Tab(text: 'Custom Worker'),
            Tab(text: 'Manual BM'),
            Tab(text: 'Production'),
            Tab(text: '๐Ÿ”„ Chain Test'),
            Tab(text: '๐Ÿ”— Data Flow'),
          ],
        ),
      ),
      body: Stack(
        children: [
          Column(
            children: [
              Expanded(
                child: TabBarView(
                  controller: _tabController,
                  children: [
                    const DemoScenariosPage(),
                    const ComprehensiveDemoPage(),
                    const PerformancePage(),
                    _buildBasicTab(),
                    _buildUploadDownloadTab(),
                    _buildBackoffPolicyTab(),
                    _buildConstraintsTab(),
                    _buildChainsTab(),
                    _buildScheduledTab(),
                    _buildCustomWorkerTab(),
                    const ManualBenchmarkPage(),
                    const ProductionImpactPageImproved(),
                    const ChainResilienceTest(),
                    const ChainDataFlowDemo(),
                  ],
                ),
              ),
              const Divider(height: 1),
              _buildLogSection(),
            ],
          ),
          // Advanced floating metrics overlay
          if (_showMetricsOverlay) const AdvancedMetricsOverlay(),
        ],
      ),
    );
  }

  Widget _buildBasicTab() {
    return ListView(
      padding: const EdgeInsets.all(16),
      children: [
        const _SectionTitle('Native Workers (Mode 1)'),
        const Text(
          'Zero Flutter Engine overhead\n'
          'RAM: 2-5MB | Startup: <50ms',
          style: TextStyle(color: Colors.grey),
        ),
        const SizedBox(height: 16),
        _buildButton(
          'HTTP GET Request',
          Icons.cloud_download,
          _scheduleHttpGet,
          Colors.blue,
        ),
        _buildButton(
          'HTTP POST Request',
          Icons.cloud_upload,
          _scheduleHttpPost,
          Colors.green,
        ),
        _buildButton('JSON Sync', Icons.sync, _scheduleSync, Colors.orange),
        const SizedBox(height: 16),
        const Divider(),
        const SizedBox(height: 16),
        const _SectionTitle('Dart Workers (Mode 2)'),
        const Text(
          'Full Flutter Engine access\n'
          'RAM: 30-50MB | Startup: 500-1000ms',
          style: TextStyle(color: Colors.grey),
        ),
        const SizedBox(height: 16),
        _buildButton(
          'Custom Dart Task',
          Icons.code,
          _scheduleCustomDartTask,
          Colors.purple,
        ),
      ],
    );
  }

  // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
  // TAB 2: Upload/Download Workers
  // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

  Widget _buildUploadDownloadTab() {
    return ListView(
      padding: const EdgeInsets.all(16),
      children: [
        const _SectionTitle('Upload & Download Workers'),
        const Text(
          'File transfer with progress tracking\n'
          'Native URLSession/OkHttp implementation',
          style: TextStyle(color: Colors.grey),
        ),
        const SizedBox(height: 16),
        _buildButton(
          'Upload File (with progress)',
          Icons.cloud_upload,
          _scheduleFileUpload,
          Colors.blue,
        ),
        const Text(
          '  Uploads with custom fileName & mimeType',
          style: TextStyle(fontSize: 12, color: Colors.grey),
        ),
        const SizedBox(height: 8),
        _buildButton(
          'Download File',
          Icons.cloud_download,
          _scheduleFileDownload,
          Colors.green,
        ),
        const Text(
          '  Downloads file to app temp directory',
          style: TextStyle(fontSize: 12, color: Colors.grey),
        ),
        const SizedBox(height: 8),
        _buildButton(
          'Compress File/Directory (ZIP)',
          Icons.archive,
          _scheduleFileCompression,
          Colors.orange,
        ),
        const Text(
          '  Compresses files to ZIP archive (v1.0.0+)',
          style: TextStyle(fontSize: 12, color: Colors.grey),
        ),
        const SizedBox(height: 16),
        const Card(
          child: Padding(
            padding: EdgeInsets.all(12),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  '๐Ÿ“ File Operations:',
                  style: TextStyle(fontWeight: FontWeight.bold),
                ),
                SizedBox(height: 8),
                Text(
                  'โ€ข Upload: Multipart w/ custom fileName & mimeType\n'
                  'โ€ข Download: Streaming with progress\n'
                  'โ€ข Compress: ZIP files/directories (NEW!)\n'
                  'โ€ข Native implementation (no Dart overhead)\n'
                  'โ€ข Works in background even when app killed',
                  style: TextStyle(fontSize: 12),
                ),
              ],
            ),
          ),
        ),
      ],
    );
  }

  Future<void> _scheduleFileUpload() async {
    final taskId = 'upload-${_taskCounter++}';
    try {
      // Create temp file with UUID name (simulating cache file)
      final tempFileName = 'temp_${DateTime.now().millisecondsSinceEpoch}.dat';
      final testFile = '${Directory.systemTemp.path}/$tempFileName';
      await File(testFile).writeAsString(
        'test upload content - ${DateTime.now().toIso8601String()}',
      );

      // Upload with custom fileName and mimeType
      final customFileName =
          'photo_${DateTime.now().millisecondsSinceEpoch}.jpg';

      await NativeWorkManager.enqueue(
        taskId: taskId,
        trigger: TaskTrigger.oneTime(),
        worker: HttpUploadWorker(
          url: 'https://httpbin.org/post',
          filePath: testFile,
          fileFieldName: 'photo',
          fileName: customFileName, // NEW: Custom uploaded filename
          mimeType: 'image/jpeg', // NEW: Explicit MIME type
          headers: const {'X-Test': 'Upload'},
          additionalFields: const {
            'userId': 'demo-user',
            'description': 'Test photo upload',
          },
        ),
        constraints: const Constraints(requiresNetwork: true),
      );
      _addLog('๐Ÿ“ค Scheduled: File Upload ($taskId)');
      _addLog('๐Ÿ“ Local file: $tempFileName');
      _addLog('๐Ÿท๏ธ Upload as: $customFileName (image/jpeg)');
      _addLog('๐Ÿ‘ค With userId: demo-user');
    } catch (e) {
      _addLog('โŒ Error: $e');
    }
  }

  Future<void> _scheduleFileDownload() async {
    final taskId = 'download-${_taskCounter++}';
    try {
      final tempDir = await getTemporaryDirectory();
      final savePath = '${tempDir.path}/downloaded-file.json';

      await NativeWorkManager.enqueue(
        taskId: taskId,
        trigger: TaskTrigger.oneTime(),
        worker: HttpDownloadWorker(
          url: 'https://httpbin.org/json',
          savePath: savePath,
        ),
        constraints: const Constraints(requiresNetwork: true),
      );
      _addLog('๐Ÿ“ค Scheduled: File Download ($taskId)');
      _addLog('๐Ÿ’พ Will save to $savePath');
    } catch (e) {
      _addLog('โŒ Error: $e');
    }
  }

  Future<void> _scheduleFileCompression() async {
    final taskId = 'compress-${_taskCounter++}';
    try {
      // Create a test directory with sample files
      final tempDir = Directory.systemTemp.path;
      final testDir = Directory(
        '$tempDir/test_compress_${DateTime.now().millisecondsSinceEpoch}',
      );
      await testDir.create(recursive: true);

      // Create some test files
      await File(
        '${testDir.path}/file1.txt',
      ).writeAsString('Sample file 1 content\n' * 100);
      await File(
        '${testDir.path}/file2.txt',
      ).writeAsString('Sample file 2 content\n' * 100);
      await File(
        '${testDir.path}/readme.md',
      ).writeAsString('# Test Files\n\nThese are test files for compression.');

      // Create a subdirectory with more files
      final subDir = Directory('${testDir.path}/logs');
      await subDir.create();
      await File(
        '${subDir.path}/app.log',
      ).writeAsString('Log entry 1\nLog entry 2\n' * 50);
      await File(
        '${subDir.path}/error.log',
      ).writeAsString('Error 1\nError 2\n' * 30);

      // Also create files to exclude
      await File(
        '${testDir.path}/temp.tmp',
      ).writeAsString('Temporary file - should be excluded');
      await File(
        '${testDir.path}/.DS_Store',
      ).writeAsString('macOS metadata - should be excluded');

      final outputZip =
          '$tempDir/compressed_${DateTime.now().millisecondsSinceEpoch}.zip';

      await NativeWorkManager.enqueue(
        taskId: taskId,
        trigger: TaskTrigger.oneTime(),
        worker: NativeWorker.fileCompress(
          inputPath: testDir.path,
          outputPath: outputZip,
          level: CompressionLevel.medium,
          excludePatterns: const ['*.tmp', '.DS_Store'],
          deleteOriginal: false, // Keep original for demo
        ),
      );

      _addLog('๐Ÿ“ค Scheduled: File Compression ($taskId)');
      _addLog('๐Ÿ“ Input: ${testDir.path}');
      _addLog('๐Ÿ“ฆ Output: $outputZip');
      _addLog('๐Ÿšซ Excluding: *.tmp, .DS_Store');
    } catch (e) {
      _addLog('โŒ Error: $e');
    }
  }

  Future<void> _scheduleCustomDartTask() async {
    final taskId = 'dart-${_taskCounter++}';
    try {
      await NativeWorkManager.enqueue(
        taskId: taskId,
        trigger: TaskTrigger.oneTime(),
        worker: DartWorker(callbackId: 'customTask'),
      );
      _addLog('๐Ÿ“ค Scheduled: Custom Dart Task ($taskId)');
    } catch (e) {
      _addLog('โŒ Error: $e');
    }
  }

  Widget _buildBackoffPolicyTab() {
    return ListView(
      padding: const EdgeInsets.all(16),
      children: [
        const _SectionTitle('v1.0.0: Intelligent Retry (Android)'),
        const Text(
          'Automatic retry with exponential or linear backoff\n'
          'Failed tasks will retry automatically with increasing delays',
          style: TextStyle(color: Colors.grey),
        ),
        const SizedBox(height: 16),
        _buildButton(
          'Exponential Backoff',
          Icons.trending_up,
          _scheduleWithExponentialBackoff,
          Colors.purple,
        ),
        const Text(
          '  Retry: 10s โ†’ 20s โ†’ 40s โ†’ 80s โ†’ ...',
          style: TextStyle(fontSize: 12, color: Colors.grey),
        ),
        const SizedBox(height: 8),
        _buildButton(
          'Linear Backoff',
          Icons.linear_scale,
          _scheduleWithLinearBackoff,
          Colors.indigo,
        ),
        const Text(
          '  Retry: 15s โ†’ 15s โ†’ 15s โ†’ 15s โ†’ ...',
          style: TextStyle(fontSize: 12, color: Colors.grey),
        ),
        const SizedBox(height: 16),
        const Card(
          child: Padding(
            padding: EdgeInsets.all(12),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  'โ„น๏ธ How it works:',
                  style: TextStyle(fontWeight: FontWeight.bold),
                ),
                SizedBox(height: 8),
                Text(
                  '1. Task scheduled with backoffPolicy\n'
                  '2. If task fails (returns false), automatic retry\n'
                  '3. Delay increases based on policy\n'
                  '4. Continues until success or max retries',
                  style: TextStyle(fontSize: 12),
                ),
              ],
            ),
          ),
        ),
      ],
    );
  }

  Widget _buildConstraintsTab() {
    return ListView(
      padding: const EdgeInsets.all(16),
      children: [
        const _SectionTitle('Advanced Constraints'),
        const Text(
          'isHeavyTask, QoS, and more',
          style: TextStyle(color: Colors.grey),
        ),
        const SizedBox(height: 16),
        _buildButton(
          'Heavy Task (Foreground Service)',
          Icons.work,
          _scheduleHeavyTask,
          Colors.red,
        ),
        const Text(
          '  Uses ForegroundService on Android\n'
          '  Shows notification, prevents kill',
          style: TextStyle(fontSize: 12, color: Colors.grey),
        ),
        const SizedBox(height: 8),
        _buildButton(
          'QoS Priority (iOS)',
          Icons.priority_high,
          _scheduleWithQoS,
          Colors.teal,
        ),
        const Text(
          '  Sets DispatchQoS on iOS\n'
          '  Controls task priority',
          style: TextStyle(fontSize: 12, color: Colors.grey),
        ),
        const SizedBox(height: 16),
        const Divider(),
        const SizedBox(height: 16),
        const _SectionTitle('Android-Only Triggers'),
        const Text(
          'System state triggers (Android only)',
          style: TextStyle(color: Colors.grey),
        ),
        const SizedBox(height: 16),
        _buildButton(
          'Schedule All Android Triggers',
          Icons.phone_android,
          _scheduleAndroidTriggers,
          Colors.green,
        ),
        const Text(
          '  Schedules battery-okay, battery-low, device-idle, storage-low',
          style: TextStyle(fontSize: 12, color: Colors.grey),
        ),
      ],
    );
  }

  Widget _buildChainsTab() {
    return ListView(
      padding: const EdgeInsets.all(16),
      children: [
        const _SectionTitle('Task Chains'),
        const Text(
          'Complex workflows made simple\n'
          'Sequential: A โ†’ B โ†’ C\n'
          'Parallel: A โ†’ [B + C + D]',
          style: TextStyle(color: Colors.grey),
        ),
        const SizedBox(height: 16),
        _buildButton(
          'Sequential Chain',
          Icons.timeline,
          _scheduleSequentialChain,
          Colors.deepPurple,
        ),
        const Text(
          '  HTTP โ†’ Sync โ†’ Dart (all sequential)',
          style: TextStyle(fontSize: 12, color: Colors.grey),
        ),
        const SizedBox(height: 8),
        _buildButton(
          'Parallel Chain',
          Icons.account_tree,
          _scheduleParallelChain,
          Colors.cyan,
        ),
        const Text(
          '  Download โ†’ [Upload1 + Upload2] parallel',
          style: TextStyle(fontSize: 12, color: Colors.grey),
        ),
        const SizedBox(height: 8),
        _buildButton(
          'Hybrid Chain (Native + Dart)',
          Icons.merge_type,
          _scheduleHybridChain,
          Colors.pink,
        ),
        const Text(
          '  Native Download โ†’ Dart Process โ†’ Native Upload',
          style: TextStyle(fontSize: 12, color: Colors.grey),
        ),
        const SizedBox(height: 16),
        const Card(
          child: Padding(
            padding: EdgeInsets.all(12),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  '๐Ÿ’ก Hybrid Chain Benefits:',
                  style: TextStyle(fontWeight: FontWeight.bold),
                ),
                SizedBox(height: 8),
                Text(
                  'โ€ข Use Native workers for I/O (low memory)\n'
                  'โ€ข Use Dart workers for business logic\n'
                  'โ€ข Mix both in same chain seamlessly\n'
                  'โ€ข Example: Download (2MB) โ†’ Process (50MB) โ†’ Upload (2MB)',
                  style: TextStyle(fontSize: 12),
                ),
              ],
            ),
          ),
        ),
      ],
    );
  }

  Future<void> _scheduleHybridChain() async {
    try {
      await NativeWorkManager.beginWith(
            TaskRequest(
              id: 'hybrid-download',
              worker: HttpRequestWorker(
                url: 'https://httpbin.org/get',
                method: HttpMethod.get,
              ),
            ),
          )
          .then(
            TaskRequest(
              id: 'hybrid-process',
              worker: DartWorker(
                callbackId: 'customTask',
                input: {'step': 'processing'},
              ),
            ),
          )
          .then(
            TaskRequest(
              id: 'hybrid-upload',
              worker: HttpRequestWorker(
                url: 'https://httpbin.org/post',
                method: HttpMethod.post,
                body: '{"status":"complete"}',
              ),
            ),
          )
          .named('hybrid-chain')
          .enqueue();

      _addLog('๐Ÿ“ค Scheduled: Hybrid Chain');
      _addLog('๐Ÿ”— Native (2MB) โ†’ Dart (50MB) โ†’ Native (2MB)');
      _addLog('๐Ÿ’ก Optimal: Low memory for I/O, Dart for logic');
    } catch (e) {
      _addLog('โŒ Error: $e');
    }
  }

  Future<void> _scheduleAndroidTriggers() async {
    final triggers = [
      ('battery-okay-${_taskCounter++}', TaskTrigger.batteryOkay()),
      ('battery-low-${_taskCounter++}', TaskTrigger.batteryLow()),
      ('device-idle-${_taskCounter++}', TaskTrigger.deviceIdle()),
      ('storage-low-${_taskCounter++}', TaskTrigger.storageLow()),
    ];
    for (final (id, trigger) in triggers) {
      try {
        await NativeWorkManager.enqueue(
          taskId: id,
          trigger: trigger,
          worker: HttpRequestWorker(
            url: 'https://httpbin.org/get',
            method: HttpMethod.get,
          ),
        );
        _addLog('๐Ÿ“ค Scheduled: $id');
      } catch (e) {
        _addLog('โŒ $id: $e');
      }
    }
  }

  Widget _buildScheduledTab() {
    return ListView(
      padding: const EdgeInsets.all(16),
      children: [
        const _SectionTitle('Scheduled Tasks'),
        const Text(
          'Periodic, Exact, and Windowed triggers',
          style: TextStyle(color: Colors.grey),
        ),
        const SizedBox(height: 16),
        _buildButton(
          'Periodic (Every 15 min)',
          Icons.repeat,
          _schedulePeriodicTask,
          Colors.green,
        ),
        _buildButton(
          'Exact Alarm (5 min from now)',
          Icons.alarm,
          _scheduleExactAlarm,
          Colors.orange,
        ),
        _buildButton(
          'Windowed (2-10 min window)',
          Icons.timelapse,
          _scheduleWindowedTask,
          Colors.blue,
        ),
      ],
    );
  }

  // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
  // TAB 10: Custom Native Workers (v1.0.0+)
  // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

  Future<void> _scheduleImageCompress() async {
    final taskId = 'image-compress-${_taskCounter++}';
    try {
      // 1. Create a dummy image file in the app's temporary directory
      final tempDir = await getTemporaryDirectory();
      final inputFileName = 'dummy_image_${DateTime.now().millisecondsSinceEpoch}.jpg';
      final inputFilePath = '${tempDir.path}/$inputFileName';

      // Create a simple dummy JPEG content (e.g., a small red square)
      // This is a minimal valid JPEG header + data for a 1x1 red pixel
      final dummyImageData = Uint8List.fromList([
        0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01,
        0x01, 0x01, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0xFF, 0xDB, 0x00, 0x43,
        0x00, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02, 0x02, 0x03,
        0x03, 0x03, 0x03, 0x04, 0x06, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x06,
        0x06, 0x05, 0x06, 0x09, 0x08, 0x0A, 0x0A, 0x09, 0x08, 0x09, 0x09, 0x0A,
        0x0C, 0x0F, 0x0C, 0x0A, 0x0B, 0x0E, 0x0B, 0x09, 0x09, 0x0D, 0x11, 0x0D,
        0x0E, 0x0F, 0x10, 0x10, 0x11, 0x10, 0x0A, 0x0C, 0x12, 0x13, 0x12, 0x10,
        0x13, 0x0F, 0x10, 0x10, 0x10, 0xFF, 0xC9, 0x00, 0x0B, 0x08, 0x00, 0x01,
        0x00, 0x01, 0x01, 0x01, 0x11, 0x00, 0xFF, 0xCC, 0x00, 0x06, 0x00, 0x10,
        0x10, 0x05, 0xFF, 0xDA, 0x00, 0x08, 0x01, 0x01, 0x00, 0x00, 0x3F, 0x00,
        0xD2, 0xCF, 0x20, 0xFF, 0xD9,
      ]);
      await File(inputFilePath).writeAsBytes(dummyImageData);

      final outputFileName = 'compressed_image_${DateTime.now().millisecondsSinceEpoch}.jpg';
      final outputFilePath = '${tempDir.path}/$outputFileName';

      await NativeWorkManager.enqueue(
        taskId: taskId,
        trigger: TaskTrigger.oneTime(),
        worker: NativeWorker.custom(
          className: 'ImageCompressWorker',
          input: {
            'inputPath': inputFilePath,
            'outputPath': outputFilePath,
            'quality': 85,
            'maxWidth': 1920,
            'maxHeight': 1080,
          },
        ),
      );
      _addLog('๐Ÿ–ผ๏ธ Scheduled: Image Compression ($taskId)');
      _addLog('๐Ÿ“ Input: $inputFileName, Output: $outputFileName');
    } catch (e) {
      _addLog('โŒ Error: $e');
    }
  }

  Widget _buildCustomWorkerTab() {
    return ListView(
      padding: const EdgeInsets.all(16),
      children: [
        const _SectionTitle('Custom Native Workers (v1.0.0+)'),
        const Text(
          'Extend with your own high-performance native workers\n'
          'Written in Kotlin (Android) and Swift (iOS)',
          style: TextStyle(color: Colors.grey),
        ),
        const SizedBox(height: 16),
        const Card(
          color: Colors.green,
          child: Padding(
            padding: EdgeInsets.all(12),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  'โœจ What\'s New in v1.0.0',
                  style: TextStyle(
                    fontWeight: FontWeight.bold,
                    color: Colors.white,
                  ),
                ),
                SizedBox(height: 8),
                Text(
                  'โ€ข Register custom workers without forking the plugin\n'
                  'โ€ข Same performance as built-in workers (~2-5MB RAM)\n'
                  'โ€ข Support for any native processing (image, crypto, ML, etc.)',
                  style: TextStyle(fontSize: 12, color: Colors.white),
                ),
              ],
            ),
          ),
        ),
        const SizedBox(height: 16),
        const Card(
          child: Padding(
            padding: EdgeInsets.all(12),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  '๐Ÿ“– Demo Worker: ImageCompressWorker',
                  style: TextStyle(fontWeight: FontWeight.bold),
                ),
                SizedBox(height: 8),
                Text(
                  'This demo shows a custom native worker that compresses images:\n\n'
                  'โ€ข Android: Uses BitmapFactory (native Android API)\n'
                  'โ€ข iOS: Uses UIImage (native iOS API)\n'
                  'โ€ข RAM Usage: ~2-5MB (same as built-in HTTP workers)\n'
                  'โ€ข Registered in MainActivity.kt / AppDelegate.swift',
                  style: TextStyle(fontSize: 12, color: Colors.black87),
                ),
              ],
            ),
          ),
        ),
        const SizedBox(height: 16),
        _buildButton(
          'Compress Image (Custom Worker)',
          Icons.compress,
          _scheduleImageCompress,
          Colors.deepPurple,
        ),
        const SizedBox(height: 16),
        const Divider(),
        const SizedBox(height: 16),
        const _SectionTitle('How It Works'),
        const Card(
          child: Padding(
            padding: EdgeInsets.all(12),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  '1๏ธโƒฃ Implement Worker (Kotlin/Swift)',
                  style: TextStyle(fontWeight: FontWeight.bold),
                ),
                SizedBox(height: 4),
                Text(
                  'See: android/.../ ImageCompressWorker.kt\n'
                  'See: ios/Classes/workers/ImageCompressWorker.swift',
                  style: TextStyle(fontSize: 11, fontFamily: 'monospace'),
                ),
                SizedBox(height: 12),
                Text(
                  '2๏ธโƒฃ Register Worker (MainActivity/AppDelegate)',
                  style: TextStyle(fontWeight: FontWeight.bold),
                ),
                SizedBox(height: 4),
                Text(
                  'SimpleAndroidWorkerFactory.setUserFactory(...)\n'
                  'IosWorkerFactory.registerWorker(...)',
                  style: TextStyle(fontSize: 11, fontFamily: 'monospace'),
                ),
                SizedBox(height: 12),
                Text(
                  '3๏ธโƒฃ Use from Dart',
                  style: TextStyle(fontWeight: FontWeight.bold),
                ),
                SizedBox(height: 4),
                Text(
                  'NativeWorker.custom(\n'
                  '  className: \'ImageCompressWorker\',\n'
                  '  input: {...},\n'
                  ')',
                  style: TextStyle(fontSize: 11, fontFamily: 'monospace'),
                ),
              ],
            ),
          ),
        ),
        const SizedBox(height: 16),
        const Card(
          color: Colors.blue,
          child: Padding(
            padding: EdgeInsets.all(12),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  '๐Ÿ“š Documentation',
                  style: TextStyle(
                    fontWeight: FontWeight.bold,
                    color: Colors.white,
                  ),
                ),
                SizedBox(height: 8),
                Text(
                  'See: docs/use-cases/07-custom-native-workers.md\n'
                  'Complete tutorial with examples for image compression,\n'
                  'encryption, database operations, and more.',
                  style: TextStyle(fontSize: 12, color: Colors.white),
                ),
              ],
            ),
          ),
        ),
      ],
    );
  }

  Widget _buildButton(
    String label,
    IconData icon,
    VoidCallback onPressed,
    Color color,
  ) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 8),
      child: ElevatedButton.icon(
        onPressed: onPressed,
        icon: Icon(icon),
        label: Text(label),
        style: ElevatedButton.styleFrom(
          backgroundColor: color.withValues(alpha: 0.2),
          foregroundColor: color,
          alignment: Alignment.centerLeft,
        ),
      ),
    );
  }

  Widget _buildLogSection() {
    return Container(
      height: 200,
      decoration: BoxDecoration(
        color: Colors.grey.shade100,
        border: Border(top: BorderSide(color: Colors.grey.shade300)),
      ),
      child: Column(
        children: [
          Padding(
            padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                const Text(
                  'Event Log',
                  style: TextStyle(fontWeight: FontWeight.bold),
                ),
                Row(
                  children: [
                    TextButton.icon(
                      onPressed: _clearLogs,
                      icon: const Icon(Icons.clear_all, size: 16),
                      label: const Text('Clear'),
                    ),
                    TextButton.icon(
                      onPressed: _cancelAll,
                      icon: const Icon(Icons.delete_sweep, size: 16),
                      label: const Text('Cancel All'),
                      style: TextButton.styleFrom(foregroundColor: Colors.red),
                    ),
                  ],
                ),
              ],
            ),
          ),
          Expanded(
            child: _logs.isEmpty
                ? const Center(
                    child: Text(
                      'No events yet. Schedule a task to see events!',
                    ),
                  )
                : ListView.builder(
                    itemCount: _logs.length,
                    itemBuilder: (context, index) {
                      return Container(
                        padding: const EdgeInsets.symmetric(
                          horizontal: 16,
                          vertical: 4,
                        ),
                        child: SelectableText(
                          _logs[index],
                          style: const TextStyle(
                            fontFamily: 'monospace',
                            fontSize: 11,
                          ),
                        ),
                      );
                    },
                  ),
          ),
        ],
      ),
    );
  }
}

class _SectionTitle extends StatelessWidget {
  final String title;

  const _SectionTitle(this.title);

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 8),
      child: Text(
        title,
        style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
      ),
    );
  }
}
4
likes
160
points
37
downloads

Publisher

verified publisherbrewkits.dev

Weekly Downloads

Background task manager for Flutter using platform-native APIs. Zero Flutter Engine overhead for I/O operations.

Repository (GitHub)
View/report issues
Contributing

Documentation

API reference

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on native_workmanager

Packages that implement native_workmanager