flutter_web_file_saver 2.0.0 copy "flutter_web_file_saver: ^2.0.0" to clipboard
flutter_web_file_saver: ^2.0.0 copied to clipboard

Platformweb

The most comprehensive Flutter web file saver - 25+ methods for text, images, video, audio, ZIP archives, canvas export, batch operations and more!

example/lib/main.dart

import 'dart:convert';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter_web_file_saver/flutter_web_file_saver.dart';

void main() {
  runApp(const FileSaverDemoApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Web File Saver Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.blue,
          brightness: Brightness.light,
        ),
        textTheme: TextTheme(),
        useMaterial3: true,
      ),
      darkTheme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.blue,
          brightness: Brightness.dark,
        ),
        textTheme: ThemeData.dark().textTheme,
        useMaterial3: true,
      ),
      home: const DemoHomePage(),
    );
  }
}

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

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

class _DemoHomePageState extends State<DemoHomePage> {
  int _selectedIndex = 0;
  String _statusMessage = 'Ready to test file saving!';
  bool _isLoading = false;

  final List<DemoSection> _sections = [
    DemoSection(
      title: 'E-Commerce',
      icon: Icons.shopping_cart,
      color: Colors.orange,
    ),
    DemoSection(
      title: 'Analytics',
      icon: Icons.bar_chart,
      color: Colors.blue,
    ),
    DemoSection(
      title: 'Notes',
      icon: Icons.note,
      color: Colors.green,
    ),
    DemoSection(
      title: 'Design',
      icon: Icons.brush,
      color: Colors.purple,
    ),
    DemoSection(
      title: 'Media',
      icon: Icons.videocam,
      color: Colors.red,
    ),
    DemoSection(
      title: 'Advanced',
      icon: Icons.auto_awesome,
      color: Colors.deepPurple,
    ),
    DemoSection(
      title: 'Developer',
      icon: Icons.code,
      color: Colors.teal,
    ),
  ];

  void _showResult(SaveResult result) {
    setState(() {
      _statusMessage = result.success
          ? '✅ Successfully saved: ${result.filename}'
          : '❌ Failed: ${result.errorMessage}';
      _isLoading = false;
    });

    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Row(
          children: [
            Icon(
              result.success ? Icons.check_circle : Icons.error,
              color: Colors.white,
            ),
            const SizedBox(width: 12),
            Expanded(child: Text(_statusMessage)),
          ],
        ),
        backgroundColor: result.success ? Colors.green : Colors.red,
        behavior: SnackBarBehavior.floating,
        shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
        duration: const Duration(seconds: 3),
      ),
    );
  }

  void _setLoading(String message) {
    setState(() {
      _isLoading = true;
      _statusMessage = message;
    });
  }

  // ==================== E-COMMERCE DEMOS ====================

  Future<void> _generateInvoice() async {
    _setLoading('Generating invoice...');

    final html = '''
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Invoice #INV-2024-001</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body {
            font-family: 'Arial', sans-serif;
            padding: 40px;
            background: #f5f5f5;
        }
        .container {
            max-width: 800px;
            margin: 0 auto;
            background: white;
            padding: 40px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        .header {
            text-align: center;
            margin-bottom: 40px;
            border-bottom: 3px solid #2196F3;
            padding-bottom: 20px;
        }
        .header h1 { color: #2196F3; font-size: 36px; }
        .header p { color: #666; margin-top: 10px; }
        .details {
            display: flex;
            justify-content: space-between;
            margin-bottom: 40px;
        }
        .details div { flex: 1; }
        .details h3 { color: #333; margin-bottom: 10px; }
        .details p { color: #666; line-height: 1.6; }
        table {
            width: 100%;
            border-collapse: collapse;
            margin-bottom: 30px;
        }
        th {
            background: #2196F3;
            color: white;
            padding: 15px;
            text-align: left;
            font-weight: 600;
        }
        td {
            padding: 15px;
            border-bottom: 1px solid #ddd;
        }
        tr:hover { background: #f9f9f9; }
        .total-row {
            background: #e3f2fd;
            font-weight: bold;
            font-size: 18px;
        }
        .footer {
            text-align: center;
            margin-top: 40px;
            padding-top: 20px;
            border-top: 2px solid #eee;
            color: #999;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>INVOICE</h1>
            <p>Invoice #INV-2024-001</p>
            <p>Date: ${DateTime.now().toString().split(' ')[0]}</p>
        </div>
        
        <div class="details">
            <div>
                <h3>Bill To:</h3>
                <p>
                    <strong>John Smith</strong><br>
                    123 Main Street<br>
                    New York, NY 10001<br>
                    USA<br>
                    john.smith@email.com
                </p>
            </div>
            <div style="text-align: right;">
                <h3>From:</h3>
                <p>
                    <strong>Your Company</strong><br>
                    456 Business Ave<br>
                    San Francisco, CA 94102<br>
                    USA<br>
                    contact@yourcompany.com
                </p>
            </div>
        </div>
        
        <table>
            <thead>
                <tr>
                    <th>Item Description</th>
                    <th style="text-align: right;">Qty</th>
                    <th style="text-align: right;">Price</th>
                    <th style="text-align: right;">Total</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>Premium Flutter Development Course</td>
                    <td style="text-align: right;">1</td>
                    <td style="text-align: right;">\$299.00</td>
                    <td style="text-align: right;">\$299.00</td>
                </tr>
                <tr>
                    <td>Advanced State Management Workshop</td>
                    <td style="text-align: right;">1</td>
                    <td style="text-align: right;">\$149.00</td>
                    <td style="text-align: right;">\$149.00</td>
                </tr>
                <tr>
                    <td>Flutter Plugin Development Guide</td>
                    <td style="text-align: right;">2</td>
                    <td style="text-align: right;">\$49.00</td>
                    <td style="text-align: right;">\$98.00</td>
                </tr>
                <tr class="total-row">
                    <td colspan="3" style="text-align: right;">TOTAL:</td>
                    <td style="text-align: right;">\$546.00</td>
                </tr>
            </tbody>
        </table>
        
        <div class="footer">
            <p>Thank you for your business!</p>
            <p>Payment terms: Net 30 days</p>
        </div>
    </div>
</body>
</html>
''';

    final result = await FlutterWebFileSaver.saveHtml(
      htmlContent: html,
      filename: 'invoice_${DateTime.now().millisecondsSinceEpoch}.html',
    );

    _showResult(result);
  }

  Future<void> _exportOrderReceipt() async {
    _setLoading('Generating receipt...');

    final receipt = '''
========================================
         YOUR COMPANY RECEIPT
========================================

Receipt #: RCP-${DateTime.now().millisecondsSinceEpoch}
Date: ${DateTime.now()}

----------------------------------------
CUSTOMER INFORMATION
----------------------------------------
Name: Jane Doe
Email: jane.doe@email.com
Phone: (555) 123-4567

----------------------------------------
ORDER DETAILS
----------------------------------------
Order #: ORD-2024-5678
Payment Method: Credit Card (**** 4242)

Items:
1. MacBook Pro 16"           \$2,499.00
2. Magic Mouse               \$79.00
3. USB-C Cable               \$19.00

----------------------------------------
SUMMARY
----------------------------------------
Subtotal:                    \$2,597.00
Tax (8.5%):                  \$220.75
Shipping:                    \$0.00
----------------------------------------
TOTAL:                       \$2,817.75
----------------------------------------

Thank you for shopping with us!

Visit us: www.yourcompany.com
Support: support@yourcompany.com
========================================
''';

    final result = await FlutterWebFileSaver.saveText(
      content: receipt,
      filename: 'receipt_${DateTime.now().millisecondsSinceEpoch}.txt',
    );

    _showResult(result);
  }

  // ==================== ANALYTICS DEMOS ====================

  Future<void> _exportSalesData() async {
    _setLoading('Exporting sales data...');

    final csvData = [
      ['Date', 'Product', 'Quantity', 'Revenue', 'Region', 'Category'],
      ['2024-01-01', 'Laptop Pro', '45', '67500.00', 'North America', 'Electronics'],
      ['2024-01-01', 'Wireless Mouse', '120', '3600.00', 'Europe', 'Accessories'],
      ['2024-01-02', 'Monitor 4K', '30', '12000.00', 'Asia', 'Electronics'],
      ['2024-01-02', 'Keyboard Mechanical', '85', '8500.00', 'North America', 'Accessories'],
      ['2024-01-03', 'USB-C Hub', '200', '6000.00', 'Europe', 'Accessories'],
      ['2024-01-03', 'Laptop Pro', '38', '57000.00', 'Asia', 'Electronics'],
      ['2024-01-04', 'Webcam HD', '150', '7500.00', 'North America', 'Accessories'],
      ['2024-01-04', 'Monitor 4K', '25', '10000.00', 'Europe', 'Electronics'],
      ['2024-01-05', 'Laptop Pro', '52', '78000.00', 'Asia', 'Electronics'],
      ['2024-01-05', 'Wireless Mouse', '95', '2850.00', 'North America', 'Accessories'],
    ];

    final result = await FlutterWebFileSaver.saveCsv(
      rows: csvData,
      filename: 'sales_report_${DateTime.now().toString().split(' ')[0]}.csv',
    );

    _showResult(result);
  }

  Future<void> _exportAnalyticsJSON() async {
    _setLoading('Exporting analytics data...');

    final data = {
      'report': {
        'title': 'Monthly Analytics Report',
        'period': '${DateTime.now().year}-${DateTime.now().month.toString().padLeft(2, '0')}',
        'generated': DateTime.now().toIso8601String(),
      },
      'metrics': {
        'total_revenue': 250750.00,
        'total_orders': 1245,
        'avg_order_value': 201.40,
        'conversion_rate': 3.2,
        'returning_customers': 456,
      },
      'top_products': [
        {'name': 'Laptop Pro', 'sales': 135, 'revenue': 202500},
        {'name': 'Monitor 4K', 'sales': 78, 'revenue': 31200},
        {'name': 'Wireless Mouse', 'sales': 342, 'revenue': 10260},
      ],
      'traffic_sources': {
        'organic': 45.2,
        'paid_ads': 28.5,
        'social': 15.3,
        'direct': 8.7,
        'referral': 2.3,
      },
      'regional_breakdown': [
        {'region': 'North America', 'revenue': 125000, 'orders': 620},
        {'region': 'Europe', 'revenue': 75000, 'orders': 380},
        {'region': 'Asia', 'revenue': 50750, 'orders': 245},
      ],
    };

    final result = await FlutterWebFileSaver.saveJson(
      data: data,
      filename: 'analytics_${DateTime.now().millisecondsSinceEpoch}.json',
      prettyPrint: true,
    );

    _showResult(result);
  }

  // ==================== NOTES DEMOS ====================

  Future<void> _saveMarkdownNote() async {
    _setLoading('Saving markdown note...');

    final markdown = '''
# 📝 My Flutter Development Notes

**Date:** ${DateTime.now()}

## Today's Achievements

- ✅ Implemented file download feature
- ✅ Created reusable widget library
- ✅ Fixed navigation bug
- ✅ Improved app performance

## Code Snippets

### Custom Button Widget

\`\`\`dart
class CustomButton extends StatelessWidget {
  final String label;
  final VoidCallback onPressed;
  
  const CustomButton({
    required this.label,
    required this.onPressed,
  });
  
  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: onPressed,
      child: Text(label),
    );
  }
}
\`\`\`

## Ideas for Tomorrow

1. Implement dark mode toggle
2. Add authentication flow
3. Optimize image loading
4. Write unit tests

## Resources

- [Flutter Docs](https://flutter.dev)
- [Pub.dev](https://pub.dev)
- [GitHub Issues](https://github.com)

---

*Generated with Flutter Web File Saver Demo*
''';

    final result = await FlutterWebFileSaver.saveMarkdown(
      markdownContent: markdown,
      filename: 'flutter_notes_${DateTime.now().toString().split(' ')[0]}.md',
    );

    _showResult(result);
  }

  Future<void> _saveMeetingNotes() async {
    _setLoading('Saving meeting notes...');

    final notes = '''
MEETING NOTES
=============

Meeting: Sprint Planning
Date: ${DateTime.now()}
Attendees: Development Team

AGENDA
------
1. Review last sprint
2. Plan current sprint
3. Discuss blockers
4. Q&A

DISCUSSION POINTS
-----------------

Sprint Review:
- Completed 23/25 story points
- 2 stories carried over to next sprint
- Demo went well with stakeholders

Current Sprint Plan:
- Focus on user authentication
- Implement payment integration
- Design system improvements
- Performance optimization

Action Items:
[] John - Set up authentication service
[] Sarah - Design payment flow UI
[] Mike - Optimize database queries
[] Lisa - Update documentation

BLOCKERS
--------
- Waiting for API access from third-party
- Need design approval for new feature

NEXT MEETING
-----------
Date: ${DateTime.now().add(const Duration(days: 7))}
Time: 10:00 AM

Notes by: AI Assistant
''';

    final result = await FlutterWebFileSaver.saveText(
      content: notes,
      filename: 'meeting_notes_${DateTime.now().millisecondsSinceEpoch}.txt',
    );

    _showResult(result);
  }

  // ==================== MEDIA DEMOS ====================

  Future<void> _saveVideoFromUrl() async {
    _setLoading('Saving video from URL...');

    // Demo: Save a small test video (1 second of black frames as WebM)
    // In a real app, this would be from MediaRecorder or a video URL
    final videoDataUrl = 'data:video/webm;base64,GkXfo59ChoEBQveBAULygQRC84EIQoKEd2VibUKHgQRChYECGFOAZwH/////////FUmpZpkq17GDD0JATYCGQ2hyb21lV0GGQ2hyb21lFlSua7+uvdeBAXPFh4EEQoWBAhhTgGcB//////////';

    final result = await FlutterWebFileSaver.saveVideoUrl(
      videoUrl: videoDataUrl,
      filename: 'sample_video_${DateTime.now().millisecondsSinceEpoch}.webm',
      mimeType: MimeTypes.webm,
    );

    _showResult(result);
  }

  Future<void> _saveVideoBytes() async {
    _setLoading('Generating video file...');

    // Create a minimal valid WebM file (just header bytes for demo)
    // In production, use actual video bytes from recorder or processor
    final videoBytes = Uint8List.fromList([
      0x1A, 0x45, 0xDF, 0xA3, 0x01, 0x00, 0x00, 0x00, // WebM header
      0x00, 0x00, 0x00, 0x1F, 0x42, 0x86, 0x81, 0x01,
      0x42, 0xF7, 0x81, 0x01, 0x42, 0xF2, 0x81, 0x04,
      0x42, 0xF3, 0x81, 0x08, 0x42, 0x82, 0x88, 0x77,
      0x65, 0x62, 0x6D, 0x42, 0x87, 0x81, 0x04, 0x42,
    ]);

    final result = await FlutterWebFileSaver.saveVideo(
      bytes: videoBytes,
      filename: 'generated_video_${DateTime.now().millisecondsSinceEpoch}.webm',
      format: 'webm',
    );

    _showResult(result);
  }

  Future<void> _saveAudioFromUrl() async {
    _setLoading('Saving audio from URL...');

    // Demo: Small WAV file (1 second of silence)
    final audioDataUrl = 'data:audio/wav;base64,UklGRiQAAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YQAAAAA=';

    final result = await FlutterWebFileSaver.saveAudioUrl(
      audioUrl: audioDataUrl,
      filename: 'sample_audio_${DateTime.now().millisecondsSinceEpoch}.wav',
      mimeType: MimeTypes.wav,
    );

    _showResult(result);
  }

  Future<void> _saveAudioBytes() async {
    _setLoading('Generating audio file...');

    // Create a minimal valid WAV file (silence)
    final audioBytes = Uint8List.fromList([
      // RIFF header
      0x52, 0x49, 0x46, 0x46, // "RIFF"
      0x24, 0x00, 0x00, 0x00, // File size
      0x57, 0x41, 0x56, 0x45, // "WAVE"
      // fmt chunk
      0x66, 0x6d, 0x74, 0x20, // "fmt "
      0x10, 0x00, 0x00, 0x00, // Chunk size
      0x01, 0x00, // Audio format (PCM)
      0x01, 0x00, // Channels (mono)
      0x40, 0x1f, 0x00, 0x00, // Sample rate (8000)
      0x40, 0x1f, 0x00, 0x00, // Byte rate
      0x01, 0x00, // Block align
      0x08, 0x00, // Bits per sample
      // data chunk
      0x64, 0x61, 0x74, 0x61, // "data"
      0x00, 0x00, 0x00, 0x00, // Data size (empty)
    ]);

    final result = await FlutterWebFileSaver.saveAudio(
      bytes: audioBytes,
      filename: 'generated_audio_${DateTime.now().millisecondsSinceEpoch}.wav',
      format: 'wav',
    );

    _showResult(result);
  }

  // ==================== DESIGN DEMOS ====================

  Future<void> _saveColorPalette() async {
    _setLoading('Generating color palette...');

    final html = '''
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Color Palette</title>
    <style>
        body {
            font-family: 'Arial', sans-serif;
            padding: 40px;
            background: #f5f5f5;
        }
        .container {
            max-width: 1000px;
            margin: 0 auto;
            background: white;
            padding: 40px;
            border-radius: 10px;
            box-shadow: 0 4px 20px rgba(0,0,0,0.1);
        }
        h1 { color: #333; text-align: center; margin-bottom: 40px; }
        .palette {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 20px;
        }
        .color-card {
            border-radius: 10px;
            overflow: hidden;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        .color-box {
            height: 150px;
        }
        .color-info {
            padding: 15px;
            background: white;
        }
        .color-name { font-weight: bold; margin-bottom: 5px; }
        .color-code { color: #666; font-family: monospace; }
    </style>
</head>
<body>
    <div class="container">
        <h1>🎨 My Design Palette</h1>
        <div class="palette">
            <div class="color-card">
                <div class="color-box" style="background: #2196F3;"></div>
                <div class="color-info">
                    <div class="color-name">Primary Blue</div>
                    <div class="color-code">#2196F3</div>
                </div>
            </div>
            <div class="color-card">
                <div class="color-box" style="background: #4CAF50;"></div>
                <div class="color-info">
                    <div class="color-name">Success Green</div>
                    <div class="color-code">#4CAF50</div>
                </div>
            </div>
            <div class="color-card">
                <div class="color-box" style="background: #FF9800;"></div>
                <div class="color-info">
                    <div class="color-name">Warning Orange</div>
                    <div class="color-code">#FF9800</div>
                </div>
            </div>
            <div class="color-card">
                <div class="color-box" style="background: #F44336;"></div>
                <div class="color-info">
                    <div class="color-name">Error Red</div>
                    <div class="color-code">#F44336</div>
                </div>
            </div>
            <div class="color-card">
                <div class="color-box" style="background: #9C27B0;"></div>
                <div class="color-info">
                    <div class="color-name">Accent Purple</div>
                    <div class="color-code">#9C27B0</div>
                </div>
            </div>
            <div class="color-card">
                <div class="color-box" style="background: #607D8B;"></div>
                <div class="color-info">
                    <div class="color-name">Neutral Gray</div>
                    <div class="color-code">#607D8B</div>
                </div>
            </div>
        </div>
    </div>
</body>
</html>
''';

    final result = await FlutterWebFileSaver.saveHtml(
      htmlContent: html,
      filename: 'color_palette_${DateTime.now().millisecondsSinceEpoch}.html',
    );

    _showResult(result);
  }

  Future<void> _savePixelArt() async {
    _setLoading('Saving pixel art...');

    // Create a simple 10x10 red square PNG
    final dataUrl =
        'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAFUlEQVR42mP8z8DwHwYEBv4jRTDAAAD//0EBAQBfbdvBEgAAAABJRU5ErkJggg==';

    final result = await FlutterWebFileSaver.saveImageUrl(
      imageUrl: dataUrl,
      filename: 'pixel_art_${DateTime.now().millisecondsSinceEpoch}.png',
    );

    _showResult(result);
  }

  // ==================== ADVANCED DEMOS (V2.0.0) ====================

  final GlobalKey _canvasKey = GlobalKey();

  Future<void> _saveAsZip() async {
    _setLoading('Creating ZIP archive...');

    // Create multiple files to bundle
    final files = <String, Uint8List>{};

    // Add a text file
    files['readme.txt'] = Uint8List.fromList(
      utf8.encode('Welcome to your ZIP archive!\n\nThis archive contains:\n- Sample document\n- Data file\n- Image\n\nCreated with flutter_web_file_saver'),
    );

    // Add a JSON file
    final jsonData = {
      'title': 'Sample Project',
      'version': '2.0.0',
      'files': ['readme.txt', 'data.csv', 'image.png'],
      'created': DateTime.now().toIso8601String(),
    };
    files['data.json'] = Uint8List.fromList(
      utf8.encode(const JsonEncoder.withIndent('  ').convert(jsonData)),
    );

    // Add a CSV file
    final csvContent = 'Name,Value,Status\nItem A,100,Active\nItem B,200,Pending\nItem C,150,Complete';
    files['data.csv'] = Uint8List.fromList(utf8.encode(csvContent));

    // Add a small image (1x1 red pixel)
    final imageDataUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg==';
    final imageBytes = base64Decode(imageDataUrl.split(',')[1]);
    files['image.png'] = imageBytes;

    final result = await FlutterWebFileSaver.saveAsZip(
      files: files,
      zipFilename: 'project_bundle_${DateTime.now().millisecondsSinceEpoch}.zip',
    );

    _showResult(result);
  }

  Future<void> _saveCanvas() async {
    _setLoading('Capturing canvas...');

    // Give a moment for the canvas to render
    await Future.delayed(const Duration(milliseconds: 100));

    final result = await FlutterWebFileSaver.saveFromCanvas(
      key: _canvasKey,
      filename: 'canvas_export_${DateTime.now().millisecondsSinceEpoch}.png',
      pixelRatio: 3.0,
    );

    _showResult(result);
  }

  Future<void> _saveBatchFiles() async {
    _setLoading('Preparing batch export...');

    final files = <FileToSave>[];

    // Create 5 sample files
    for (var i = 1; i <= 5; i++) {
      final content = '''
File #$i
Generated at: ${DateTime.now()}
This is a sample file for batch export demonstration.

Batch operations are perfect for:
- Exporting multiple reports
- Downloading image galleries
- Saving document collections
- Bulk data exports

File $i of 5
''';
      files.add(FileToSave(
        bytes: Uint8List.fromList(utf8.encode(content)),
        filename: 'batch_file_$i.txt',
      ));
    }

    setState(() {
      _statusMessage = 'Saving 5 files...';
    });

    final results = await FlutterWebFileSaver.saveMultipleFiles(
      files: files,
      onProgress: (current, total) {
        setState(() {
          _statusMessage = 'Saving file $current of $total...';
        });
      },
    );

    final allSuccess = results.every((r) => r.success);
    final successCount = results.where((r) => r.success).length;

    setState(() {
      _isLoading = false;
      _statusMessage = allSuccess
          ? '✅ Successfully saved all 5 files!'
          : '⚠️ Saved $successCount of ${results.length} files';
    });

    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text(_statusMessage),
        backgroundColor: allSuccess ? Colors.green : Colors.orange,
      ),
    );
  }

  Future<void> _generateDataUrl() async {
    _setLoading('Generating data URL...');

    final imageBytes = Uint8List.fromList([
      // Small red square PNG
      0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
      0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
      0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
      0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x77, 0x53,
      0xDE, 0x00, 0x00, 0x00, 0x0C, 0x49, 0x44, 0x41,
      0x54, 0x08, 0xD7, 0x63, 0xF8, 0xCF, 0xC0, 0x00,
      0x00, 0x03, 0x01, 0x01, 0x00, 0x18, 0xDD, 0x8D,
      0xB4, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E,
      0x44, 0xAE, 0x42, 0x60, 0x82,
    ]);

    final dataUrl = FlutterWebFileSaver.generateDataUrl(
      bytes: imageBytes,
      mimeType: MimeTypes.png,
    );

    setState(() {
      _isLoading = false;
      _statusMessage = '✅ Data URL generated! (${dataUrl.length} characters)';
    });

    // Show dialog with the data URL
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('Data URL Generated'),
        content: SizedBox(
          width: 400,
          child: Column(
            mainAxisSize: MainAxisSize.min,
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              const Text('Data URL created successfully!'),
              const SizedBox(height: 16),
              Container(
                padding: const EdgeInsets.all(8),
                decoration: BoxDecoration(
                  color: Colors.grey[200],
                  borderRadius: BorderRadius.circular(4),
                ),
                child: SelectableText(
                  dataUrl.substring(0, 100) + '...',
                  style: const TextStyle(
                    fontFamily: 'monospace',
                    fontSize: 10,
                  ),
                ),
              ),
              const SizedBox(height: 16),
              const Text('Use this URL in:'),
              const Text('• <img src="...">'),
              const Text('• Image.network(...)'),
              const Text('• CSS backgrounds'),
            ],
          ),
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('Close'),
          ),
        ],
      ),
    );
  }

  Future<void> _saveHtmlTable() async {
    _setLoading('Generating HTML table...');

    final headers = ['Employee', 'Department', 'Salary', 'Performance'];
    final rows = [
      ['John Doe', 'Engineering', '\$120,000', 'Excellent'],
      ['Jane Smith', 'Marketing', '\$95,000', 'Outstanding'],
      ['Bob Johnson', 'Sales', '\$110,000', 'Good'],
      ['Alice Brown', 'HR', '\$85,000', 'Excellent'],
      ['Charlie Wilson', 'Engineering', '\$115,000', 'Good'],
    ];

    final result = await FlutterWebFileSaver.saveTableAsHtml(
      headers: headers,
      rows: rows,
      filename: 'employee_table_${DateTime.now().millisecondsSinceEpoch}.html',
      title: 'Employee Performance Report',
    );

    _showResult(result);
  }

  Future<void> _saveAuto() async {
    _setLoading('Auto-detecting format...');

    // Auto-detect JSON
    final jsonData = {
      'feature': 'Auto Format Detection',
      'version': '2.0.0',
      'formats': ['JSON', 'CSV', 'Text'],
      'timestamp': DateTime.now().toIso8601String(),
    };

    final result = await FlutterWebFileSaver.saveAuto(
      data: jsonData,
      filename: 'auto_detected_${DateTime.now().millisecondsSinceEpoch}.json',
    );

    _showResult(result);
  }

  // ==================== DEVELOPER DEMOS ====================

  Future<void> _exportConfigXML() async {
    _setLoading('Exporting configuration...');

    final xml = '''<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <application>
        <name>Flutter Web File Saver Demo</name>
        <version>1.0.0</version>
        <build>20241220</build>
    </application>
    
    <settings>
        <theme>dark</theme>
        <language>en</language>
        <auto_save>true</auto_save>
        <notifications>true</notifications>
    </settings>
    
    <features>
        <feature name="file_export" enabled="true"/>
        <feature name="analytics" enabled="true"/>
        <feature name="offline_mode" enabled="false"/>
        <feature name="cloud_sync" enabled="true"/>
    </features>
    
    <api>
        <endpoint>https://api.example.com</endpoint>
        <timeout>30000</timeout>
        <retry_attempts>3</retry_attempts>
    </api>
    
    <database>
        <name>app_database</name>
        <version>2</version>
        <cache_size>10485760</cache_size>
    </database>
</configuration>''';

    final result = await FlutterWebFileSaver.saveXml(
      xmlContent: xml,
      filename: 'app_config_${DateTime.now().millisecondsSinceEpoch}.xml',
    );

    _showResult(result);
  }

  Future<void> _exportAppLogs() async {
    _setLoading('Exporting application logs...');

    final logs = '''
[2024-12-20 10:15:23] INFO: Application started
[2024-12-20 10:15:24] INFO: Loading configuration...
[2024-12-20 10:15:24] INFO: Configuration loaded successfully
[2024-12-20 10:15:25] INFO: Initializing database...
[2024-12-20 10:15:26] INFO: Database initialized
[2024-12-20 10:15:27] INFO: Starting HTTP server on port 8080
[2024-12-20 10:15:27] INFO: Server started successfully
[2024-12-20 10:16:15] INFO: User login: user@example.com
[2024-12-20 10:16:16] INFO: Session created: session-abc123
[2024-12-20 10:17:45] WARNING: Slow query detected (2.3s): SELECT * FROM large_table
[2024-12-20 10:18:30] INFO: File export requested
[2024-12-20 10:18:31] INFO: File exported successfully: invoice_123.pdf
[2024-12-20 10:19:12] ERROR: Failed to connect to external API
[2024-12-20 10:19:12] ERROR: Retrying connection (attempt 1/3)...
[2024-12-20 10:19:15] INFO: Connection successful
[2024-12-20 10:20:00] INFO: User logout: user@example.com
[2024-12-20 10:20:01] INFO: Session destroyed: session-abc123
[2024-12-20 10:25:00] INFO: Running scheduled backup...
[2024-12-20 10:25:45] INFO: Backup completed successfully
''';

    final result = await FlutterWebFileSaver.saveText(
      content: logs,
      filename: 'app_logs_${DateTime.now().toString().split(' ')[0]}.log',
    );

    _showResult(result);
  }

  Widget _buildDemoContent() {
    switch (_selectedIndex) {
      case 0: // E-Commerce
        return _buildECommerceDemo();
      case 1: // Analytics
        return _buildAnalyticsDemo();
      case 2: // Notes
        return _buildNotesDemo();
      case 3: // Design
        return _buildDesignDemo();
      case 4: // Media
        return _buildMediaDemo();
      case 5: // Advanced
        return _buildAdvancedDemo();
      case 6: // Developer
        return _buildDeveloperDemo();
      default:
        return const Center(child: Text('Select a demo'));
    }
  }

  Widget _buildECommerceDemo() {
    return _buildDemoSection(
      title: 'E-Commerce Exports',
      description: 'Generate invoices, receipts, and order confirmations',
      icon: Icons.shopping_cart,
      color: Colors.orange,
      demos: [
        DemoButton(
          icon: Icons.receipt_long,
          label: 'Generate Invoice (HTML)',
          subtitle: 'Professional invoice with styling',
          onPressed: _generateInvoice,
        ),
        DemoButton(
          icon: Icons.receipt,
          label: 'Export Receipt (TXT)',
          subtitle: 'Plain text receipt for printing',
          onPressed: _exportOrderReceipt,
        ),
      ],
    );
  }

  Widget _buildAnalyticsDemo() {
    return _buildDemoSection(
      title: 'Analytics & Reports',
      description: 'Export sales data, metrics, and analytics reports',
      icon: Icons.bar_chart,
      color: Colors.blue,
      demos: [
        DemoButton(
          icon: Icons.table_chart,
          label: 'Export Sales Data (CSV)',
          subtitle: 'Spreadsheet-ready sales report',
          onPressed: _exportSalesData,
        ),
        DemoButton(
          icon: Icons.analytics,
          label: 'Export Analytics (JSON)',
          subtitle: 'Detailed metrics in JSON format',
          onPressed: _exportAnalyticsJSON,
        ),
      ],
    );
  }

  Widget _buildNotesDemo() {
    return _buildDemoSection(
      title: 'Notes & Documentation',
      description: 'Save meeting notes, documentation, and markdown files',
      icon: Icons.note,
      color: Colors.green,
      demos: [
        DemoButton(
          icon: Icons.edit_note,
          label: 'Save Markdown Note',
          subtitle: 'Formatted note with code snippets',
          onPressed: _saveMarkdownNote,
        ),
        DemoButton(
          icon: Icons.meeting_room,
          label: 'Save Meeting Notes (TXT)',
          subtitle: 'Plain text meeting minutes',
          onPressed: _saveMeetingNotes,
        ),
      ],
    );
  }

  Widget _buildDesignDemo() {
    return _buildDemoSection(
      title: 'Design Assets',
      description: 'Export color palettes, mockups, and design resources',
      icon: Icons.brush,
      color: Colors.purple,
      demos: [
        DemoButton(
          icon: Icons.palette,
          label: 'Save Color Palette (HTML)',
          subtitle: 'Beautiful color palette showcase',
          onPressed: _saveColorPalette,
        ),
        DemoButton(
          icon: Icons.image,
          label: 'Save Pixel Art (PNG)',
          subtitle: 'Export image from data URL',
          onPressed: _savePixelArt,
        ),
      ],
    );
  }

  Widget _buildMediaDemo() {
    return _buildDemoSection(
      title: 'Media Files (Video & Audio)',
      description: 'Save videos, audio recordings, and media streams',
      icon: Icons.videocam,
      color: Colors.red,
      demos: [
        DemoButton(
          icon: Icons.video_file,
          label: 'Save Video from URL',
          subtitle: 'Download video from data URL or blob',
          onPressed: _saveVideoFromUrl,
        ),
        DemoButton(
          icon: Icons.movie,
          label: 'Save Video from Bytes',
          subtitle: 'Generate and save video file',
          onPressed: _saveVideoBytes,
        ),
        DemoButton(
          icon: Icons.audio_file,
          label: 'Save Audio from URL',
          subtitle: 'Download audio from data URL or blob',
          onPressed: _saveAudioFromUrl,
        ),
        DemoButton(
          icon: Icons.audiotrack,
          label: 'Save Audio from Bytes',
          subtitle: 'Generate and save audio file',
          onPressed: _saveAudioBytes,
        ),
      ],
    );
  }

  Widget _buildAdvancedDemo() {
    return _buildDemoSection(
      title: 'Advanced Features',
      description: 'ZIP archives, canvas export, batch operations, and utilities',
      icon: Icons.auto_awesome,
      color: Colors.deepPurple,
      demos: [
        DemoButton(
          icon: Icons.folder_zip,
          label: 'Save as ZIP Archive',
          subtitle: 'Bundle multiple files into one ZIP',
          onPressed: _saveAsZip,
        ),
        DemoButton(
          icon: Icons.camera_alt,
          label: 'Save Canvas/Screenshot',
          subtitle: 'Export widget as image',
          onPressed: _saveCanvas,
        ),
        DemoButton(
          icon: Icons.dynamic_feed,
          label: 'Batch Save (5 Files)',
          subtitle: 'Save multiple files with progress',
          onPressed: _saveBatchFiles,
        ),
        DemoButton(
          icon: Icons.link,
          label: 'Generate Data URL',
          subtitle: 'Create embeddable data URL',
          onPressed: _generateDataUrl,
        ),
        DemoButton(
          icon: Icons.table_chart,
          label: 'Save HTML Table',
          subtitle: 'Generate formatted table',
          onPressed: _saveHtmlTable,
        ),
        DemoButton(
          icon: Icons.auto_fix_high,
          label: 'Auto Format Detection',
          subtitle: 'Automatically detect and save',
          onPressed: _saveAuto,
        ),
      ],
    );
  }

  Widget _buildDeveloperDemo() {
    return _buildDemoSection(
      title: 'Developer Tools',
      description: 'Export configs, logs, and development files',
      icon: Icons.code,
      color: Colors.teal,
      demos: [
        DemoButton(
          icon: Icons.settings,
          label: 'Export Config (XML)',
          subtitle: 'Application configuration file',
          onPressed: _exportConfigXML,
        ),
        DemoButton(
          icon: Icons.bug_report,
          label: 'Export Logs (TXT)',
          subtitle: 'Application log file',
          onPressed: _exportAppLogs,
        ),
      ],
    );
  }

  Widget _buildDemoSection({
    required String title,
    required String description,
    required IconData icon,
    required Color color,
    required List<DemoButton> demos,
  }) {
    return SingleChildScrollView(
      padding: const EdgeInsets.all(24),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Row(
            children: [
              Container(
                padding: const EdgeInsets.all(16),
                decoration: BoxDecoration(
                  color: color.withOpacity(0.1),
                  borderRadius: BorderRadius.circular(12),
                ),
                child: Icon(icon, size: 32, color: color),
              ),
              const SizedBox(width: 16),
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      title,
                      style: const TextStyle(
                        fontSize: 24,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                    const SizedBox(height: 4),
                    Text(
                      description,
                      style: TextStyle(
                        fontSize: 14,
                        color: Colors.grey[600],
                      ),
                    ),
                  ],
                ),
              ),
            ],
          ),
          const SizedBox(height: 32),
          ...demos.map((demo) => Padding(
                padding: const EdgeInsets.only(bottom: 16),
                child: _buildDemoCard(demo),
              )),
        ],
      ),
    );
  }

  Widget _buildDemoCard(DemoButton demo) {
    return Card(
      elevation: 2,
      child: InkWell(
        onTap: _isLoading ? null : demo.onPressed,
        borderRadius: BorderRadius.circular(12),
        child: Padding(
          padding: const EdgeInsets.all(20),
          child: Row(
            children: [
              Container(
                padding: const EdgeInsets.all(12),
                decoration: BoxDecoration(
                  color: Theme.of(context).primaryColor.withOpacity(0.1),
                  borderRadius: BorderRadius.circular(8),
                ),
                child: Icon(
                  demo.icon,
                  color: Theme.of(context).primaryColor,
                ),
              ),
              const SizedBox(width: 16),
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      demo.label,
                      style: const TextStyle(
                        fontSize: 16,
                        fontWeight: FontWeight.w600,
                      ),
                    ),
                    const SizedBox(height: 4),
                    Text(
                      demo.subtitle,
                      style: TextStyle(
                        fontSize: 13,
                        color: Colors.grey[600],
                      ),
                    ),
                  ],
                ),
              ),
              Icon(
                Icons.arrow_forward_ios,
                size: 16,
                color: Colors.grey[400],
              ),
            ],
          ),
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutter Web File Saver Demo'),
        elevation: 0,
      ),
      body: Row(
        children: [
          // Sidebar
          NavigationRail(
            selectedIndex: _selectedIndex,
            onDestinationSelected: (index) {
              setState(() => _selectedIndex = index);
            },
            labelType: NavigationRailLabelType.all,
            destinations: _sections
                .map((section) => NavigationRailDestination(
                      icon: Icon(section.icon),
                      selectedIcon: Icon(section.icon),
                      label: Text(section.title),
                    ))
                .toList(),
          ),
          const VerticalDivider(thickness: 1, width: 1),
          // Main content
          Expanded(
            child: Column(
              children: [
                // Status bar
                Container(
                  width: double.infinity,
                  padding: const EdgeInsets.all(16),
                  color: _isLoading
                      ? Colors.orange.withOpacity(0.1)
                      : Colors.green.withOpacity(0.1),
                  child: Row(
                    children: [
                      if (_isLoading)
                        const SizedBox(
                          width: 20,
                          height: 20,
                          child: CircularProgressIndicator(strokeWidth: 2),
                        ),
                      if (_isLoading) const SizedBox(width: 12),
                      Expanded(
                        child: Text(
                          _statusMessage,
                          style: const TextStyle(
                            fontSize: 14,
                            fontWeight: FontWeight.w500,
                          ),
                        ),
                      ),
                    ],
                  ),
                ),
                // Demo content
                Expanded(
                  child: Column(
                    children: [
                      // Show canvas preview only in Advanced section
                      if (_selectedIndex == 5)
                        Container(
                          margin: const EdgeInsets.all(16),
                          decoration: BoxDecoration(
                            border: Border.all(color: Colors.grey[300]!),
                            borderRadius: BorderRadius.circular(8),
                          ),
                          child: Column(
                            children: [
                              Container(
                                padding: const EdgeInsets.all(12),
                                color: Colors.grey[100],
                                child: Row(
                                  children: [
                                    const Icon(Icons.info_outline, size: 20),
                                    const SizedBox(width: 8),
                                    const Expanded(
                                      child: Text(
                                        'Canvas Preview - Click "Save Canvas/Screenshot" to export this as an image',
                                        style: TextStyle(fontSize: 12),
                                      ),
                                    ),
                                  ],
                                ),
                              ),
                              RepaintBoundary(
                                key: _canvasKey,
                                child: Container(
                                  width: double.infinity,
                                  padding: const EdgeInsets.all(32),
                                  decoration: BoxDecoration(
                                    gradient: LinearGradient(
                                      colors: [
                                        Colors.blue[400]!,
                                        Colors.purple[400]!,
                                      ],
                                    ),
                                  ),
                                  child: Column(
                                    children: [
                                      const Icon(
                                        Icons.auto_awesome,
                                        size: 48,
                                        color: Colors.white,
                                      ),
                                      const SizedBox(height: 16),
                                      const Text(
                                        'Flutter Web File Saver v2.0.0',
                                        style: TextStyle(
                                          fontSize: 24,
                                          fontWeight: FontWeight.bold,
                                          color: Colors.white,
                                        ),
                                      ),
                                      const SizedBox(height: 8),
                                      const Text(
                                        'Canvas Export Demo',
                                        style: TextStyle(
                                          fontSize: 16,
                                          color: Colors.white70,
                                        ),
                                      ),
                                      const SizedBox(height: 24),
                                      Row(
                                        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                                        children: [
                                          _buildStatCard('25+', 'Methods'),
                                          _buildStatCard('v2.0', 'Version'),
                                          _buildStatCard('For', 'Flutter Web'),
                                        ],
                                      ),
                                    ],
                                  ),
                                ),
                              ),
                            ],
                          ),
                        ),
                      Expanded(child: _buildDemoContent()),
                    ],
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildStatCard(String value, String label) {
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
      decoration: BoxDecoration(
        color: Colors.white.withOpacity(0.2),
        borderRadius: BorderRadius.circular(12),
      ),
      child: Column(
        children: [
          Text(
            value,
            style: const TextStyle(
              fontSize: 32,
              fontWeight: FontWeight.bold,
              color: Colors.white,
            ),
          ),
          const SizedBox(height: 4),
          Text(
            label,
            style: const TextStyle(
              fontSize: 14,
              color: Colors.white70,
            ),
          ),
        ],
      ),
    );
  }
}

class DemoSection {
  final String title;
  final IconData icon;
  final Color color;

  DemoSection({
    required this.title,
    required this.icon,
    required this.color,
  });
}

class DemoButton {
  final IconData icon;
  final String label;
  final String subtitle;
  final VoidCallback onPressed;

  DemoButton({
    required this.icon,
    required this.label,
    required this.subtitle,
    required this.onPressed,
  });
}
3
likes
140
points
14
downloads
screenshot

Publisher

unverified uploader

Weekly Downloads

The most comprehensive Flutter web file saver - 25+ methods for text, images, video, audio, ZIP archives, canvas export, batch operations and more!

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

archive, flutter, flutter_web_plugins, web

More

Packages that depend on flutter_web_file_saver

Packages that implement flutter_web_file_saver