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

Background task scheduling for Flutter — 25+ native workers (HTTP, image, crypto, file), task chains, zero Flutter Engine overhead.

example/lib/main.dart

import 'dart:io';
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 '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 'pages/case_study_page.dart';
import 'pages/progress_tracking_demo_page.dart';
import 'pages/cold_start_demo_page.dart';
import 'examples/chain_resilience_test.dart';
import 'examples/chain_data_flow_demo.dart';
import 'screens/bug_fix_demo_screen.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(
    debugMode: true,
    dartWorkers: {
      'customTask': customTaskCallback,
      'heavyTask': heavyTaskCallback,
      'benchHeavyCompute': benchHeavyComputeCallback,
      // Stress & System Test Workers
      'stress_worker': stressWorkerCallback,
      'media_processor': mediaProcessorCallback,
      'large_payload': largePayloadWorkerCallback,
      'coldStartWorker': _coldStartWorkerCallbackMain,
    },
  );

  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;
}

@pragma('vm:entry-point')
Future<bool> stressWorkerCallback(Map<String, dynamic>? input) async {
  final int index = input?['index'] ?? 0;
  debugPrint('[StressWorker] index=$index starting...');
  await Future.delayed(const Duration(milliseconds: 100));
  return true;
}

@pragma('vm:entry-point')
Future<bool> mediaProcessorCallback(Map<String, dynamic>? input) async {
  debugPrint('[MediaProcessor] input=$input');
  return true;
}

@pragma('vm:entry-point')
Future<bool> _coldStartWorkerCallbackMain(Map<String, dynamic>? input) async {
  debugPrint('[ColdStartWorker] executing, input=$input');
  await Future.delayed(const Duration(milliseconds: 50));
  debugPrint('[ColdStartWorker] completed successfully');
  return true;
}

@pragma('vm:entry-point')
Future<bool> largePayloadWorkerCallback(Map<String, dynamic>? input) async {
  final data = input?['data'] as String?;
  final len = data?.length ?? 0;
  debugPrint('[LargePayloadWorker] received data length: $len');
  return len > 0;
}

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

  @override
  Widget build(BuildContext context) {
    // Custom Seed Color for a high-end feel
    const seedColor = Color(0xFF6750A4); // Deep Royal Purple

    return MaterialApp(
      title: 'Brewkits Native WorkManager',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: seedColor,
          brightness: Brightness.light,
        ),
        useMaterial3: true,
        fontFamily: 'Inter', // Modern clean font
        cardTheme: CardThemeData(
          elevation: 0,
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(24),
            side: BorderSide(color: Colors.grey.withValues(alpha: 0.1)),
          ),
          clipBehavior: Clip.antiAlias,
        ),
        elevatedButtonTheme: ElevatedButtonThemeData(
          style: ElevatedButton.styleFrom(
            elevation: 0,
            padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(16),
            ),
          ),
        ),
      ),
      darkTheme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: seedColor,
          brightness: Brightness.dark,
          surface: const Color(0xFF121212),
        ),
        useMaterial3: true,
        fontFamily: 'Inter',
        cardTheme: CardThemeData(
          elevation: 0,
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(24),
            side: BorderSide(color: Colors.white.withValues(alpha: 0.05)),
          ),
          clipBehavior: Clip.antiAlias,
        ),
      ),
      themeMode: ThemeMode.system,
      home: const DemoHomePage(),
    );
  }
}

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

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

class _DemoHomePageState extends State<DemoHomePage> {
  int _selectedIndex = 0;
  final List<String> _logs = [];
  int _taskCounter = 0;
  bool _showMetricsOverlay = false;
  bool _logExpanded = true;

  static const _pageTitles = [
    'Quick Demo',
    'All Scenarios',
    'Performance',
    'Benchmark',
    'Production Impact',
    'User Case Studies',
    'Bug Fixes',
    'Progress Tracker',
    'Core API',
    'Transfer',
    'Reliability',
    'Environment',
    'Workflows',
    'Scheduling',
    'Extensibility',
    'Resilience',
    'Data Flow',
    'Cold-Start Persistence',
  ];

  @override
  void initState() {
    super.initState();

    // Listen to task events (v2.3.0+: includes resultData)
    NativeWorkManager.events.listen((event) {
      if (!mounted) return;
      setState(() {
        String logMessage;
        if (event.isStarted) {
          // isStarted events are NOT failures — task just began execution.
          logMessage =
              '${_formatTime(event.timestamp)} ▶️ ${event.taskId}: Started';
        } else {
          logMessage =
              '${_formatTime(event.timestamp)} ${event.success ? "✅" : "❌"} ${event.taskId}: ${event.message ?? (event.success ? "Success" : "Failed")}';

          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']}';
            }
          }
        }

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

    _addLog('🚀 NativeWorkManager v1.2.0 — High-Performance Background Engine');
  }

  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 > 100) _logs.removeLast();
    });
  }

  // Task scheduling methods remain unchanged...
  Future<void> _scheduleHttpGet() async {
    final taskId = 'get-${_taskCounter++}';
    try {
      await NativeWorkManager.enqueue(
        taskId: taskId,
        trigger: TaskTrigger.oneTime(),
        worker: HttpRequestWorker(
          url: 'https://httpbin.org/get',
          method: HttpMethod.get,
        ),
      );
      _addLog('📤 Enqueued: HTTP GET ($taskId)');
    } catch (e) {
      _addLog('❌ Error: $e');
    }
  }

  Future<void> _scheduleHttpPost() async {
    final taskId = '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: '{"ts":${DateTime.now().millisecondsSinceEpoch}}',
        ),
      );
      _addLog('📤 Enqueued: 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: {
            'ts': DateTime.now().millisecondsSinceEpoch,
            'v': '1.0.8',
          },
        ),
        constraints: const Constraints(requiresNetwork: true),
      );
      _addLog('📤 Enqueued: Sync ($taskId)');
    } 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('📤 Enqueued: Dart Task ($taskId)');
    } catch (e) {
      _addLog('❌ Error: $e');
    }
  }

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final colorScheme = theme.colorScheme;

    return Scaffold(
      body: Row(
        children: [
          // Navigation Rail for larger screens or modern feel
          if (MediaQuery.of(context).size.width > 900)
            NavigationRail(
              selectedIndex: _selectedIndex < 15 ? _selectedIndex : 0,
              onDestinationSelected: (i) => setState(() => _selectedIndex = i),
              labelType: NavigationRailLabelType.selected,
              destinations: const [
                NavigationRailDestination(
                  icon: Icon(Icons.dashboard_outlined),
                  selectedIcon: Icon(Icons.dashboard),
                  label: Text('Home'),
                ),
                NavigationRailDestination(
                  icon: Icon(Icons.bolt_outlined),
                  selectedIcon: Icon(Icons.bolt),
                  label: Text('Tasks'),
                ),
                NavigationRailDestination(
                  icon: Icon(Icons.speed_outlined),
                  selectedIcon: Icon(Icons.speed),
                  label: Text('Metrics'),
                ),
              ],
            ),

          Expanded(
            child: CustomScrollView(
              slivers: [
                SliverAppBar.large(
                  title: Text(
                    _pageTitles[_selectedIndex],
                    style: const TextStyle(
                      fontWeight: FontWeight.w800,
                      letterSpacing: -0.5,
                    ),
                  ),
                  centerTitle: false,
                  actions: [
                    IconButton.filledTonal(
                      icon: Icon(
                        _showMetricsOverlay
                            ? Icons.analytics
                            : Icons.analytics_outlined,
                      ),
                      onPressed: () => setState(
                        () => _showMetricsOverlay = !_showMetricsOverlay,
                      ),
                    ),
                    const SizedBox(width: 8),
                    Builder(
                      builder: (context) => IconButton.filledTonal(
                        icon: const Icon(Icons.menu),
                        onPressed: () => Scaffold.of(context).openDrawer(),
                      ),
                    ),
                    const SizedBox(width: 16),
                  ],
                ),

                SliverToBoxAdapter(
                  child: SizedBox(
                    height: MediaQuery.of(context).size.height,
                    child: Padding(
                      padding: const EdgeInsets.symmetric(horizontal: 16.0),
                      child: IndexedStack(
                        index: _selectedIndex,
                        children: [
                          const DemoScenariosPage(), // 0
                          const ComprehensiveDemoPage(), // 1
                          const PerformancePage(), // 2
                          const ManualBenchmarkPage(), // 3
                          const ProductionImpactPageImproved(), // 4
                          const CaseStudyPage(), // 5
                          const BugFixDemoScreen(), // 6
                          const ProgressTrackingDemoPage(), // 7
                          _buildModernGridTab(), // 8
                          const Center(
                            child: Text('Transfer Page Content'),
                          ), // 9
                          const Center(
                            child: Text('Reliability Page Content'),
                          ), // 9
                          const Center(
                            child: Text('Environment Page Content'),
                          ), // 10
                          const Center(
                            child: Text('Workflow Page Content'),
                          ), // 11
                          const Center(
                            child: Text('Scheduling Page Content'),
                          ), // 12
                          const Center(
                            child: Text('Extensibility Page Content'),
                          ), // 13
                          const ChainResilienceTest(), // 14
                          const ChainDataFlowDemo(), // 15
                          const ColdStartDemoPage(), // 16
                        ],
                      ),
                    ),
                  ),
                ),

                const SliverPadding(padding: EdgeInsets.only(bottom: 220)),
              ],
            ),
          ),
        ],
      ),
      drawer: NavigationDrawer(
        selectedIndex: _selectedIndex,
        onDestinationSelected: (i) {
          setState(() => _selectedIndex = i);
          Navigator.pop(context);
        },
        children: [
          const _DrawerHeader(),
          const Padding(
            padding: EdgeInsets.fromLTRB(28, 16, 16, 10),
            child: Text(
              'MAIN FEATURES',
              style: TextStyle(
                fontSize: 12,
                fontWeight: FontWeight.bold,
                letterSpacing: 1.2,
                color: Colors.grey,
              ),
            ),
          ),
          const NavigationDrawerDestination(
            icon: Icon(Icons.rocket_launch_outlined),
            label: Text('All Scenarios'),
          ),
          const NavigationDrawerDestination(
            icon: Icon(Icons.layers_outlined),
            label: Text('Built-in Workers'),
          ),
          const Padding(
            padding: EdgeInsets.fromLTRB(28, 16, 16, 10),
            child: Text(
              'PERFORMANCE',
              style: TextStyle(
                fontSize: 12,
                fontWeight: FontWeight.bold,
                letterSpacing: 1.2,
                color: Colors.grey,
              ),
            ),
          ),
          const NavigationDrawerDestination(
            icon: Icon(Icons.speed_outlined),
            label: Text('Core Performance'),
          ),
          const NavigationDrawerDestination(
            icon: Icon(Icons.timer_outlined),
            label: Text('Manual Benchmarks'),
          ),
          const NavigationDrawerDestination(
            icon: Icon(Icons.insights_outlined),
            label: Text('Production Impact'),
          ),
          const Padding(
            padding: EdgeInsets.fromLTRB(28, 16, 16, 10),
            child: Text(
              'CASE STUDIES',
              style: TextStyle(
                fontSize: 12,
                fontWeight: FontWeight.bold,
                letterSpacing: 1.2,
                color: Colors.grey,
              ),
            ),
          ),
          const NavigationDrawerDestination(
            icon: Icon(Icons.auto_stories_outlined),
            label: Text('User Case Studies'),
          ),
          const Padding(
            padding: EdgeInsets.fromLTRB(28, 16, 16, 10),
            child: Text(
              'DEVELOPER',
              style: TextStyle(
                fontSize: 12,
                fontWeight: FontWeight.bold,
                letterSpacing: 1.2,
                color: Colors.grey,
              ),
            ),
          ),
          const NavigationDrawerDestination(
            icon: Icon(Icons.bug_report_outlined),
            label: Text('Bug Regression'),
          ),
          const NavigationDrawerDestination(
            icon: Icon(Icons.track_changes),
            label: Text('Progress Tracker'),
          ),
          const NavigationDrawerDestination(
            icon: Icon(Icons.api_outlined),
            label: Text('Core API'),
          ),
          const NavigationDrawerDestination(
            icon: Icon(Icons.swap_vert_outlined),
            label: Text('Transfer & Files'),
          ),
          const NavigationDrawerDestination(
            icon: Icon(Icons.refresh_outlined),
            label: Text('Reliability & Retry'),
          ),
          const NavigationDrawerDestination(
            icon: Icon(Icons.security_outlined),
            label: Text('Constraints'),
          ),
          const NavigationDrawerDestination(
            icon: Icon(Icons.link_outlined),
            label: Text('Task Chains'),
          ),
          const NavigationDrawerDestination(
            icon: Icon(Icons.schedule_outlined),
            label: Text('Scheduling'),
          ),
          const NavigationDrawerDestination(
            icon: Icon(Icons.extension_outlined),
            label: Text('Custom Native'),
          ),
          const NavigationDrawerDestination(
            icon: Icon(Icons.account_tree_outlined),
            label: Text('Resilience'),
          ),
          const NavigationDrawerDestination(
            icon: Icon(Icons.device_hub_outlined),
            label: Text('Data Flow'),
          ),
          const Padding(
            padding: EdgeInsets.fromLTRB(28, 16, 16, 10),
            child: Text(
              'RELIABILITY',
              style: TextStyle(
                fontSize: 12,
                fontWeight: FontWeight.bold,
                letterSpacing: 1.2,
                color: Colors.grey,
              ),
            ),
          ),
          const NavigationDrawerDestination(
            icon: Icon(Icons.power_settings_new_outlined),
            label: Text('Cold-Start Persistence'),
          ),
        ],
      ),
      bottomSheet: _buildLogTerminal(colorScheme),
      floatingActionButton: _selectedIndex == 6
          ? FloatingActionButton.extended(
              onPressed: () => NativeWorkManager.cancelAll().then(
                (_) => _addLog('🧹 Cleared all tasks'),
              ),
              label: const Text('Clear All'),
              icon: const Icon(Icons.delete_outline),
            )
          : null,
    );
  }

  Widget _buildModernGridTab() {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        const SizedBox(height: 16),
        _buildInfoCard(),
        const SizedBox(height: 24),
        const _SectionHeader('NATIVE WORKERS', 'Low-overhead processing'),
        const SizedBox(height: 12),
        GridView.count(
          shrinkWrap: true,
          physics: const NeverScrollableScrollPhysics(),
          crossAxisCount: 2,
          mainAxisSpacing: 12,
          crossAxisSpacing: 12,
          childAspectRatio: 1.4,
          children: [
            _buildActionCard(
              'HTTP GET',
              Icons.download,
              Colors.blue,
              _scheduleHttpGet,
            ),
            _buildActionCard(
              'HTTP POST',
              Icons.upload,
              Colors.green,
              _scheduleHttpPost,
            ),
            _buildActionCard(
              'JSON Sync',
              Icons.sync,
              Colors.orange,
              _scheduleSync,
            ),
            _buildActionCard(
              'Download',
              Icons.file_download,
              Colors.teal,
              () => setState(() => _selectedIndex = 7),
            ),
          ],
        ),
        const SizedBox(height: 24),
        const _SectionHeader('DART WORKERS', 'Full framework access'),
        const SizedBox(height: 12),
        _buildActionCard(
          'Execute Custom Dart Task',
          Icons.code,
          Colors.purple,
          _scheduleCustomDartTask,
          wide: true,
        ),
      ],
    );
  }

  Widget _buildInfoCard() {
    return Card(
      color: Theme.of(
        context,
      ).colorScheme.primaryContainer.withValues(alpha: 0.3),
      child: const Padding(
        padding: EdgeInsets.all(20),
        child: Row(
          children: [
            Icon(Icons.info_outline, size: 32),
            SizedBox(width: 16),
            Expanded(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(
                    'Architecture Choice',
                    style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
                  ),
                  Text(
                    'Mode 1 (Native) uses 2-5MB RAM. Mode 2 (Dart) uses 30-50MB RAM. Brewkits lets you choose based on task complexity.',
                    style: TextStyle(fontSize: 13),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildActionCard(
    String title,
    IconData icon,
    Color color,
    VoidCallback onTap, {
    bool wide = false,
  }) {
    return Card(
      child: InkWell(
        onTap: onTap,
        borderRadius: BorderRadius.circular(24),
        child: Padding(
          padding: const EdgeInsets.all(16),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Icon(icon, size: 32, color: color),
              const SizedBox(height: 8),
              Text(
                title,
                style: const TextStyle(
                  fontWeight: FontWeight.w600,
                  fontSize: 14,
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }

  Widget _buildLogTerminal(ColorScheme colorScheme) {
    return AnimatedContainer(
      duration: const Duration(milliseconds: 200),
      curve: Curves.easeInOut,
      height: _logExpanded ? 200 : 48,
      margin: const EdgeInsets.fromLTRB(16, 0, 16, 16),
      decoration: BoxDecoration(
        color: colorScheme.surfaceContainerHighest.withValues(alpha: 0.95),
        borderRadius: BorderRadius.circular(24),
        border: Border.all(
          color: colorScheme.outlineVariant.withValues(alpha: 0.5),
        ),
      ),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          // Header — always visible, tap to toggle
          InkWell(
            onTap: () => setState(() => _logExpanded = !_logExpanded),
            borderRadius: BorderRadius.circular(24),
            child: Padding(
              padding: const EdgeInsets.fromLTRB(16, 0, 8, 0),
              child: SizedBox(
                height: 46,
                child: Row(
                  children: [
                    const Icon(Icons.terminal, size: 16),
                    const SizedBox(width: 8),
                    const Text(
                      'ENGINE LOG',
                      style: TextStyle(
                        fontWeight: FontWeight.bold,
                        fontSize: 11,
                        letterSpacing: 1.0,
                      ),
                    ),
                    const SizedBox(width: 8),
                    if (_logs.isNotEmpty)
                      Text(
                        '(${_logs.length})',
                        style: TextStyle(
                          fontSize: 10,
                          color: colorScheme.onSurfaceVariant,
                        ),
                      ),
                    const Spacer(),
                    if (_logExpanded)
                      IconButton(
                        icon: const Icon(Icons.clear_all, size: 16),
                        onPressed: () => setState(() => _logs.clear()),
                        constraints: const BoxConstraints(),
                        padding: EdgeInsets.zero,
                        tooltip: 'Clear log',
                      ),
                    IconButton(
                      icon: Icon(
                        _logExpanded
                            ? Icons.keyboard_arrow_down
                            : Icons.keyboard_arrow_up,
                        size: 20,
                      ),
                      onPressed: () =>
                          setState(() => _logExpanded = !_logExpanded),
                      constraints: const BoxConstraints(),
                      padding: EdgeInsets.zero,
                    ),
                    const SizedBox(width: 4),
                  ],
                ),
              ),
            ),
          ),
          // Log list — only visible when expanded
          if (_logExpanded)
            Expanded(
              child: ListView.builder(
                padding: const EdgeInsets.symmetric(
                  horizontal: 16,
                  vertical: 4,
                ),
                itemCount: _logs.length,
                itemBuilder: (context, index) {
                  return Padding(
                    padding: const EdgeInsets.only(bottom: 2),
                    child: Text(
                      _logs[index],
                      style: const TextStyle(
                        fontFamily: 'monospace',
                        fontSize: 10,
                        height: 1.4,
                      ),
                    ),
                  );
                },
              ),
            ),
        ],
      ),
    );
  }
}

class _DrawerHeader extends StatelessWidget {
  const _DrawerHeader();
  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.fromLTRB(28, 40, 28, 20),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Container(
            padding: const EdgeInsets.all(12),
            decoration: BoxDecoration(
              color: Theme.of(context).colorScheme.primary,
              borderRadius: BorderRadius.circular(16),
            ),
            child: const Icon(
              Icons.auto_awesome,
              color: Colors.white,
              size: 32,
            ),
          ),
          const SizedBox(height: 16),
          const Text(
            'Brewkits Native',
            style: TextStyle(
              fontSize: 24,
              fontWeight: FontWeight.w900,
              letterSpacing: -1,
            ),
          ),
          const Text(
            'WorkManager SDK',
            style: TextStyle(fontSize: 14, color: Colors.grey),
          ),
        ],
      ),
    );
  }
}

class _SectionHeader extends StatelessWidget {
  final String title;
  final String subtitle;
  const _SectionHeader(this.title, this.subtitle);
  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(
          title,
          style: const TextStyle(
            fontSize: 12,
            fontWeight: FontWeight.bold,
            letterSpacing: 1.5,
            color: Colors.grey,
          ),
        ),
        Text(
          subtitle,
          style: const TextStyle(fontSize: 14, color: Colors.grey),
        ),
      ],
    );
  }
}
17
likes
160
points
999
downloads

Documentation

API reference

Publisher

verified publisherbrewkits.dev

Weekly Downloads

Background task scheduling for Flutter — 25+ native workers (HTTP, image, crypto, file), task chains, zero Flutter Engine overhead.

Repository (GitHub)
View/report issues
Contributing

Topics

#background #networking #files #images #cryptography

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on native_workmanager

Packages that implement native_workmanager