flutter_image_picker_pro 1.0.0
flutter_image_picker_pro: ^1.0.0 copied to clipboard
A versatile Flutter package for picking and handling images with compression, and adding timestamps
example/lib/main.dart
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_image_compress/flutter_image_compress.dart';
import 'package:flutter_image_picker_pro/flutter_image_picker_pro.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:image/image.dart';
import 'package:image_picker/image_picker.dart';
import 'package:image/image.dart' as img;
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(const ProviderScope(child: MyApp()));
}
class MyApp extends ConsumerWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: PictureScreen(),
);
}
}
class PictureScreen extends ConsumerStatefulWidget {
const PictureScreen({super.key});
@override
_PictureScreenState createState() => _PictureScreenState();
}
class _PictureScreenState extends ConsumerState<PictureScreen> {
final FlutterImagePickerPro mediaPicker = FlutterImagePickerPro();
XFile? _mediaFile;
List<XFile>? _mediaFileList = [];
bool _isProcessing = false;
XFile? randomFile;
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
Future<void> _pickMedia({
CompressionLevel? compressionLevel,
required bool isNeedTimeStamp,
required bool isSourceCamera,
required bool isCompressionRequired,
}) async {
final XFile? pickedFile = await FlutterImagePickerPro.getSingleMedia(
compressionLevel: compressionLevel ?? CompressionLevel.high,
isSourceCamera: isSourceCamera,
context: context,
ref: ref,
isCompressionRequired: isCompressionRequired,
isNeedTimeStamp: isNeedTimeStamp,
onProcessing: (bool isProcessing) {
setState(() {
_isProcessing = isProcessing;
});
},
);
if (pickedFile != null) {
setState(() {
_mediaFile = pickedFile;
});
}
}
Future<void> _pickMultiMedia({
CompressionLevel? compressionLevel,
required bool isNeedTimeStamp,
required bool isVideo,
required bool isAudio,
required bool isRecording,
required bool isStartRecording,
required bool isSourceCamera,
required bool isCompressionRequired,
}) async {
final List<XFile>? pickedFileList =
await FlutterImagePickerPro.getMultiMedia(
compressionLevel: compressionLevel ?? CompressionLevel.high,
isAudio: isAudio,
context: context,
isVideo: isVideo,
ref: ref,
isCompressionRequired: isCompressionRequired,
isNeedTimeStamp: isNeedTimeStamp,
onProcessing: (bool isProcessing) {
setState(() {
_isProcessing = isProcessing;
});
},
);
if (pickedFileList != null) {
setState(() {
_mediaFileList = pickedFileList;
});
}
if (kDebugMode) {
print('Media File List:::::: ${_mediaFileList}');
}
setState(() {});
}
final PageController _pageController = PageController();
int _activePage = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Row(
children: [
Icon(Icons.perm_media, color: Colors.white), // General media icon
SizedBox(width: 12), // Spacing between icon and title
Text(
'Flutter Image Picker Pro',
style: TextStyle(color: Colors.white, fontSize: 18),
),
],
),
backgroundColor: Colors.deepPurpleAccent,
actions: [
IconButton(
icon: const Icon(
Icons.info_outline,
color: Colors.white,
),
onPressed: () {
// Handle info action (e.g., show package information)
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text(
'About Image Picker Pro',
style:
TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
),
content: const Text(
'The Flutter Image Picker Pro package is a versatile solution for Flutter developers, enabling users to pick images from their device gallery or capture images from camera. It includes features like image compression, adding timestamps to images etc. The package is designed to simplify media handling in Flutter apps, providing a smooth and efficient user experience.',
style: TextStyle(fontSize: 14),
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('Close'),
),
],
),
);
},
),
],
),
body: PageView.builder(
physics: const NeverScrollableScrollPhysics(),
controller: _pageController,
itemCount: 4,
onPageChanged: (int page) {
setState(() {
_activePage = page;
_mediaFile = null;
_mediaFileList?.clear();
if (kDebugMode) {
print(_activePage);
}
});
},
itemBuilder: (BuildContext context, int index) {
if (kDebugMode) {
print('index : $index');
}
if (_activePage == 0) {
return SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
_isProcessing
? const Center(child: CircularProgressIndicator())
: (_mediaFile == null &&
(_mediaFileList == null ||
(_mediaFileList!.isEmpty)))
? Container(
height: 200,
width: double.infinity,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(8),
),
child: const Center(
child: Text(
'No media selected!',
style: TextStyle(
fontSize: 18,
),
),
))
: (_mediaFileList != null &&
(_mediaFileList!.isNotEmpty))
? Container(
height: 500,
child: ListView.builder(
itemCount: _mediaFileList?.length,
scrollDirection: Axis.horizontal,
shrinkWrap: true,
padding: const EdgeInsets.all(10.0),
itemBuilder: (context, index) {
return Padding(
padding:
const EdgeInsets.all(8.0),
child: Container(
child: mediaPicker.displayImage(
File((_mediaFileList?[index]
.path)
.toString())),
),
);
}),
)
: mediaPicker.displayImage(
File((_mediaFile?.path).toString())),
const SizedBox(height: 20),
Wrap(
crossAxisAlignment: WrapCrossAlignment.start,
spacing: 10,
runSpacing: 10,
children: [
_buildMediaButton(
icon: Icons.camera_alt,
label: 'Capture Image',
onPressed: () {
_mediaFile = null;
_mediaFileList?.clear();
_pickMedia(
isNeedTimeStamp: false,
isSourceCamera: true,
isCompressionRequired: false);
},
),
_buildMediaButton(
icon: Icons.image,
label: 'Pick Image',
onPressed: () {
_mediaFile = null;
_mediaFileList?.clear();
_pickMedia(
isNeedTimeStamp: false,
isSourceCamera: false,
isCompressionRequired: false);
},
),
_buildMediaButton(
showSecondIcon: true,
secondIcon: Icons.compress,
icon: Icons.image,
label: 'Pick & Compress Image',
onPressed: () {
_mediaFile = null;
_mediaFileList?.clear();
showCompressionDialog(
isSourceCamera: false,
isTimeStampNeeded: false);
/*_pickMedia(
isVideo: false,
isAudio: false,
isRecording: false,
isStartRecording: false,
isNeedTimeStamp: false,
isSourceCamera: false,
isCompressionRequired: true);*/
},
),
_buildMediaButton(
icon: Icons.camera_alt,
showSecondIcon: true,
secondIcon: Icons.compress,
label: 'Pick & Compress Image',
onPressed: () {
_mediaFile = null;
_mediaFileList?.clear();
showCompressionDialog(
isSourceCamera: true,
isTimeStampNeeded: false);
/*_pickMedia(
isVideo: false,
isAudio: false,
isRecording: false,
isStartRecording: false,
isNeedTimeStamp: false,
isSourceCamera: true,
isCompressionRequired: true);*/
},
),
_buildMediaButton(
icon: Icons.access_time,
label: 'Add Timestamp on Gallery Image',
onPressed: () {
_mediaFile = null;
_mediaFileList?.clear();
_pickMedia(
isNeedTimeStamp: true,
isSourceCamera: false,
isCompressionRequired: false);
},
),
_buildMediaButton(
icon: Icons.access_time,
label: 'Add Timestamp on Camera Image',
//color: Colors.white,
onPressed: () {
_mediaFile = null;
_mediaFileList?.clear();
_pickMedia(
isNeedTimeStamp: true,
isSourceCamera: true,
isCompressionRequired: false);
},
),
_buildMediaButton(
icon: Icons.access_time,
showSecondIcon: true,
secondIcon: Icons.compress,
label: 'Add Timestamp & Compress Camera Image',
//color: Colors.white,
onPressed: () {
_mediaFile = null;
_mediaFileList?.clear();
showCompressionDialog(
isSourceCamera: true,
isTimeStampNeeded: true);
},
),
_buildMediaButton(
icon: Icons.access_time,
showSecondIcon: true,
secondIcon: Icons.compress,
label: 'Add Timestamp & Compress Gallery Image',
//color: Colors.white,
onPressed: () {
showCompressionDialog(
isSourceCamera: false,
isTimeStampNeeded: true);
},
),
_buildMediaButton(
icon: Icons.access_time,
showSecondIcon: true,
secondIcon: Icons.compress,
label: 'Add Timestamp & Compress Gallery Image',
//color: Colors.white,
onPressed: () {
_mediaFile = null;
_mediaFileList?.clear();
showCompressionDialog(
isSourceCamera: false,
isTimeStampNeeded: true);
},
),
_buildMediaButton(
icon: Icons.access_time,
showSecondIcon: true,
secondIcon: Icons.compress,
label: 'Pick Multiple Images',
//color: Colors.white,
onPressed: () {
_mediaFile = null;
_mediaFileList?.clear();
_pickMultiMedia(
isVideo: false,
isAudio: false,
isRecording: false,
isStartRecording: false,
isNeedTimeStamp: false,
isSourceCamera: false,
isCompressionRequired: false);
},
),
_buildMediaButton(
icon: Icons.access_time,
showSecondIcon: true,
secondIcon: Icons.compress,
label: 'Pick Multiple Images With Compression',
//color: Colors.white,
onPressed: () {
_mediaFile = null;
_mediaFileList?.clear();
_pickMultiMedia(
isVideo: false,
isAudio: false,
isRecording: false,
isStartRecording: false,
isNeedTimeStamp: false,
isSourceCamera: false,
isCompressionRequired: true);
},
),
_buildMediaButton(
icon: Icons.access_time,
showSecondIcon: true,
secondIcon: Icons.compress,
label: 'Pick Multiple Images With TimeStamp',
//color: Colors.white,
onPressed: () {
_mediaFile = null;
_mediaFileList?.clear();
_pickMultiMedia(
isVideo: false,
isAudio: false,
isRecording: false,
isStartRecording: false,
isNeedTimeStamp: true,
isSourceCamera: false,
isCompressionRequired: true);
},
),
_buildMediaButton(
icon: Icons.access_time,
showSecondIcon: true,
secondIcon: Icons.compress,
label:
'Pick & Compress Multiple Images With Timestamp',
//color: Colors.white,
onPressed: () {
_mediaFile = null;
_mediaFileList?.clear();
_pickMultiMedia(
isVideo: false,
isAudio: false,
isRecording: false,
isStartRecording: false,
isNeedTimeStamp: true,
isSourceCamera: false,
isCompressionRequired: true);
},
),
],
),
],
),
),
);
} else {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
if (_isProcessing)
const CircularProgressIndicator()
else if (randomFile == null &&
((_mediaFileList ?? []).isEmpty ||
_mediaFileList == null))
const SizedBox()
else if (_mediaFileList != null &&
((_mediaFileList ?? []).isNotEmpty))
SizedBox(
height: 150,
child: ListView.builder(
itemCount: _mediaFileList?.length,
scrollDirection: Axis.horizontal,
shrinkWrap: true,
padding: const EdgeInsets.all(10.0),
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(color: Colors.blue)),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'Picked File Path: ${(_mediaFileList?[index].path).toString()}',
textAlign: TextAlign.center,
),
),
),
),
);
}),
)
else
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'Picked File Path: ${(randomFile?.path).toString()}',
textAlign: TextAlign.center,
),
),
_buildMediaButton(
icon: Icons.file_present_outlined,
label: 'Pick File',
onPressed: () async {
randomFile = null;
_mediaFileList?.clear();
randomFile = await FlutterImagePickerPro.getSingleMedia(
isFile: true,
isSourceCamera: true,
context: context,
ref: ref,
isCompressionRequired: false,
isNeedTimeStamp: false,
onProcessing: (bool isProcessing) {
setState(() {
_isProcessing = isProcessing;
});
},
);
},
),
_buildMediaButton(
icon: Icons.file_present_outlined,
label: 'Pick Multiple File',
onPressed: () async {
randomFile = null;
_mediaFileList?.clear();
_mediaFileList =
await FlutterImagePickerPro.getMultiMedia(
isFile: true,
isAudio: false,
context: context,
isVideo: false,
ref: ref,
isCompressionRequired: false,
isNeedTimeStamp: false,
onProcessing: (bool isProcessing) {
setState(() {
_isProcessing = isProcessing;
});
},
);
},
),
],
);
}
},
),
);
}
Widget _buildMediaButton({
required IconData icon,
IconData? secondIcon,
bool showSecondIcon = false,
required String label,
Color? color,
required VoidCallback onPressed,
}) {
return ElevatedButton.icon(
onPressed: onPressed,
icon: Row(
children: [
Icon(
icon,
color: Colors.white,
size: 14,
),
showSecondIcon
? Row(
children: [
const Padding(
padding: EdgeInsets.symmetric(horizontal: 5.0),
child: Text('+'),
),
Icon(
secondIcon,
color: Colors.white,
size: 14,
),
],
)
: const SizedBox()
],
),
label: Text(label,
style: const TextStyle(color: Colors.white, fontSize: 12)),
style: ElevatedButton.styleFrom(
foregroundColor: Colors.white,
backgroundColor: Colors.deepPurpleAccent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
elevation: 2,
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
),
);
}
Future<void> showCompressionDialog(
{bool isVideo = false,
bool isSourceCamera = false,
bool isTimeStampNeeded = false}) async {
CompressionLevel? selectedLevel = CompressionLevel.high;
await showDialog<void>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text(
'Select Compression Level',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
content: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
RadioListTile<CompressionLevel>(
title: const Text('High'),
value: CompressionLevel.high,
groupValue: selectedLevel,
onChanged: (CompressionLevel? value) {
setState(() {
selectedLevel = value;
});
},
),
RadioListTile<CompressionLevel>(
title: const Text('Medium'),
value: CompressionLevel.medium,
groupValue: selectedLevel,
onChanged: (CompressionLevel? value) {
setState(() {
selectedLevel = value;
});
},
),
RadioListTile<CompressionLevel>(
title: const Text('Low'),
value: CompressionLevel.low,
groupValue: selectedLevel,
onChanged: (CompressionLevel? value) {
setState(() {
selectedLevel = value;
});
},
),
],
);
},
),
actions: <Widget>[
TextButton(
child: const Text('Cancel'),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: const Text('OK'),
onPressed: () {
Navigator.of(context).pop();
if (selectedLevel != null) {
_pickMedia(
isNeedTimeStamp: isTimeStampNeeded,
isSourceCamera: isSourceCamera,
isCompressionRequired: true,
compressionLevel: selectedLevel,
);
}
},
),
],
);
},
);
}
}