flutter_media_compress 1.1.0
flutter_media_compress: ^1.1.0 copied to clipboard
Powerful Flutter package to compress images, videos, audio, and documents with a unified API, batch processing, quality presets, FFmpeg audio, and auto detection.
example/lib/main.dart
import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter_media_compress/flutter_media_compress.dart';
void main() => runApp(const MyApp());
/// Simple demo app showcasing flutter_media_compress usage.
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'flutter_media_compress Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.deepPurple,
scaffoldBackgroundColor: const Color(0xFFF4F5F7),
),
home: const Home(),
);
}
}
/// Home screen with buttons for single/multiple compression.
class Home extends StatefulWidget {
const Home({super.key});
@override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
bool _loading = false;
String _log = '';
/// Append a line to the in-app log view.
void _append(String text) {
setState(() => _log = '$text\n$_log');
}
/// Pick a single file of [type] and compress it.
Future<void> _single(MediaType type) async {
final res = await FilePicker.platform.pickFiles();
if (res == null || res.files.first.path == null) return;
setState(() => _loading = true);
final r = await FlutterMediaCompress.compressSingle(
file: File(res.files.first.path!),
config: CompressionConfig(mediaType: type),
);
if (!mounted) return;
setState(() => _loading = false);
_append(_formatLog("SINGLE", r));
_showResult(context, r);
}
/// Pick multiple files of [type] and compress them all.
Future<void> _multiple(MediaType type) async {
final res = await FilePicker.platform.pickFiles(allowMultiple: true);
if (res == null) return;
setState(() => _loading = true);
final results = await FlutterMediaCompress.compressMultiple(
files: res.paths.whereType<String>().map(File.new).toList(),
config: CompressionConfig(mediaType: type),
);
setState(() => _loading = false);
for (final r in results) {
_append(_formatLog("MULTI", r));
}
}
/// Build a pretty log line for a [CompressionResult].
String _formatLog(String mode, CompressionResult r) {
return "[$mode] ${r.mediaType.name.toUpperCase()} | "
"Saved: ${_bytes(r.bytesSaved)} | "
"Ratio: ${(r.ratio * 100).toStringAsFixed(1)}%";
}
/// Convert bytes to a human-readable string.
String _bytes(int bytes) {
final kb = bytes / 1024;
if (kb < 1024) return '${kb.toStringAsFixed(2)} KB';
final mb = kb / 1024;
return '${mb.toStringAsFixed(2)} MB';
}
/// Show a dialog with the main stats for a compression result.
void _showResult(BuildContext ctx, CompressionResult r) {
showDialog(
context: ctx,
builder: (_) => AlertDialog(
title: const Text("Compression Result"),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_info("Type", r.mediaType.name),
_info("Original", _bytes(r.originalSizeBytes)),
_info("Compressed", _bytes(r.compressedSizeBytes)),
_info("Saved", _bytes(r.bytesSaved)),
_info("Ratio", "${(r.ratio * 100).toStringAsFixed(1)}%"),
_info("Status", r.isSuccess ? "Success" : "Failed"),
],
),
actions: [
TextButton(
onPressed: () => Navigator.pop(ctx),
child: const Text('OK'),
),
],
),
);
}
/// Helper widget for a key/value row in the dialog.
Widget _info(String t, String v) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Row(
children: [
SizedBox(width: 90, child: Text("$t:")),
Expanded(
child: Text(v, style: const TextStyle(fontWeight: FontWeight.bold)),
),
],
),
);
}
/// Card section with title + icon + button row.
Widget _section(String icon, String title, List<Widget> buttons) {
return Card(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
elevation: 2,
margin: const EdgeInsets.symmetric(vertical: 8),
child: Padding(
padding: const EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(icon, style: const TextStyle(fontSize: 20)),
const SizedBox(width: 6),
Text(
title,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
],
),
const Divider(),
Wrap(spacing: 8, children: buttons),
],
),
),
);
}
/// Shortcut to build an [ElevatedButton].
Widget _btn(String label, VoidCallback onTap) {
return ElevatedButton(onPressed: onTap, child: Text(label));
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('flutter_media_compress'),
centerTitle: true,
),
body: Stack(
children: [
ListView(
padding: const EdgeInsets.all(14),
children: [
_section("πΌ", "Image Compression", [
_btn("Single Image", () => _single(MediaType.image)),
_btn("Multiple Images", () => _multiple(MediaType.image)),
]),
_section("π¬", "Video Compression", [
_btn("Single Video", () => _single(MediaType.video)),
_btn("Multiple Videos", () => _multiple(MediaType.video)),
]),
_section("π§", "Audio Compression", [
_btn("Single Audio", () => _single(MediaType.audio)),
_btn("Multiple Audio", () => _multiple(MediaType.audio)),
]),
_section("π", "Document Compression", [
_btn("Single Document", () => _single(MediaType.document)),
_btn("Multiple Documents", () => _multiple(MediaType.document)),
]),
const SizedBox(height: 10),
const Text("Logs", style: TextStyle(fontWeight: FontWeight.bold)),
const SizedBox(height: 4),
Container(
height: 170,
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.black87,
borderRadius: BorderRadius.circular(10),
),
child: SingleChildScrollView(
reverse: true,
child: Text(
_log.isEmpty ? "No logs yet..." : _log,
style: const TextStyle(color: Colors.white, fontSize: 12),
),
),
),
],
),
// Full-screen loading overlay.
if (_loading)
Container(
color: const Color.fromRGBO(0, 0, 0, 0.3),
child: const Center(child: CircularProgressIndicator()),
),
],
),
);
}
}