flutter_web_file_saver 2.0.0
flutter_web_file_saver: ^2.0.0 copied to clipboard
The most comprehensive Flutter web file saver - 25+ methods for text, images, video, audio, ZIP archives, canvas export, batch operations and more!
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,
});
}