easy_media_picker 0.0.1 copy "easy_media_picker: ^0.0.1" to clipboard
easy_media_picker: ^0.0.1 copied to clipboard

A cross-platform media picker for image, video, audio and documents.

example/lib/main.dart

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:easy_media_picker/easy_media_picker.dart';
import 'package:video_player/video_player.dart';
import 'package:file_picker/file_picker.dart';

void main() => runApp(const ExampleApp());

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

  @override
  Widget build(BuildContext context) =>
      const MaterialApp(debugShowCheckedModeBanner: false, home: DemoHome());
}

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

  @override
  State<DemoHome> createState() => _DemoHomeState();
}

class _DemoHomeState extends State<DemoHome> {
  final EasyMediaPicker picker = EasyMediaPicker();

  PickResult? single;
  List<PickResult> multiple = [];

  String? selectedFolder;
  List<FileSystemEntity> folderFiles = [];

  VideoPlayerController? _videoController;

  @override
  void dispose() {
    _videoController?.dispose();
    super.dispose();
  }

  Widget buildGroupTitle(String title) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 6),
      child: Text(
        title,
        style: const TextStyle(
          fontSize: 17,
          fontWeight: FontWeight.w600,
          color: Colors.black87,
        ),
      ),
    );
  }

  Future<void> _loadVideo(File file) async {
    _videoController?.dispose();
    _videoController = VideoPlayerController.file(file);
    await _videoController!.initialize();
    _videoController!.setLooping(true);
    await _videoController!.play();
    setState(() {});
  }

  Widget _singlePreview() {
    if (single == null) {
      return const Text("No file selected", style: TextStyle(fontSize: 16));
    }

    if (single!.type == PickFileType.image && single!.file != null) {
      return Column(
        children: [
          Image.file(single!.file!, width: 220, height: 220, fit: BoxFit.cover),
          const SizedBox(height: 8),
          Text(single!.name),
        ],
      );
    }

    if (single!.type == PickFileType.video && single!.file != null) {
      if (_videoController == null || !_videoController!.value.isInitialized) {
        return const CircularProgressIndicator();
      }
      return Column(
        children: [
          SizedBox(
            width: 320,
            height: 200,
            child: AspectRatio(
              aspectRatio: _videoController!.value.aspectRatio,
              child: VideoPlayer(_videoController!),
            ),
          ),
          const SizedBox(height: 8),
          Text(single!.name),
        ],
      );
    }

    return Column(
      children: [
        Icon(
          single!.type == PickFileType.audio
              ? Icons.audiotrack
              : Icons.insert_drive_file,
          size: 80,
        ),
        const SizedBox(height: 8),
        Text("${single!.type.name}: ${single!.name}"),
      ],
    );
  }

  Widget _multiplePreview() {
    if (multiple.isEmpty) return const SizedBox.shrink();
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        const SizedBox(height: 12),
        Text("Multiple items (${multiple.length}):"),
        const SizedBox(height: 8),
        SizedBox(
          height: 220,
          child: ListView.builder(
            itemCount: multiple.length,
            itemBuilder: (c, i) {
              final f = multiple[i];
              final icon = f.type == PickFileType.image
                  ? Icons.image
                  : f.type == PickFileType.video
                  ? Icons.videocam
                  : f.type == PickFileType.audio
                  ? Icons.audiotrack
                  : Icons.insert_drive_file;
              return ListTile(
                leading: Icon(icon),
                title: Text(f.name),
                subtitle: Text(f.extension),
                onTap: () async {
                  // Show any single item when tapped
                  if (f.type == PickFileType.video && f.file != null) {
                    single = f;
                    await _loadVideo(f.file!);
                    setState(() {});
                  } else {
                    single = f;
                    _videoController?.dispose();
                    setState(() {});
                  }
                },
              );
            },
          ),
        ),
      ],
    );
  }

  Widget _folderPreview() {
    if (selectedFolder == null) {
      return const Text("No folder selected", style: TextStyle(fontSize: 16));
    }

    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Container(
          padding: const EdgeInsets.all(12),
          decoration: BoxDecoration(
            color: Colors.grey.shade200,
            borderRadius: BorderRadius.circular(8),
          ),
          child: Row(
            children: [
              const Icon(Icons.folder, size: 28, color: Colors.amber),
              const SizedBox(width: 10),
              Expanded(
                child: Text(
                  selectedFolder!,
                  style: const TextStyle(fontSize: 15),
                ),
              ),
            ],
          ),
        ),

        const SizedBox(height: 12),

        const Text(
          "Folder Contents:",
          style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
        ),

        const SizedBox(height: 8),

        SizedBox(
          height: 220,
          child: ListView.builder(
            itemCount: folderFiles.length,
            itemBuilder: (context, index) {
              final entity = folderFiles[index];
              final name = entity.path.split("/").last;

              final icon = entity is Directory ? Icons.folder : _fileIcon(name);

              return ListTile(
                leading: Icon(icon, size: 28, color: Colors.blueGrey),
                title: Text(name),
                subtitle: Text(entity.path),
              );
            },
          ),
        ),
      ],
    );
  }

  Future<void> _handlePickImage() async {
    single = await picker.pickImage(const ImagePickOptions());
    multiple = [];
    _videoController?.dispose();
    setState(() {});
  }

  Future<void> _handleCaptureImage() async {
    single = await picker.captureImage();
    multiple = [];
    _videoController?.dispose();
    setState(() {});
  }

  Future<void> _handlePickVideo() async {
    single = await picker.pickVideo(const VideoPickOptions());
    multiple = [];
    if (single?.file != null) await _loadVideo(single!.file!);
    setState(() {});
  }

  Future<void> _handleCaptureVideo() async {
    single = await picker.captureVideo();
    multiple = [];
    if (single?.file != null) await _loadVideo(single!.file!);
    setState(() {});
  }

  Future<void> _handlePickImagesMultiple() async {
    multiple = await picker.pickMultipleImages();
    single = null;
    _videoController?.dispose();
    setState(() {});
  }

  Future<void> _handlePickVideosMultiple() async {
    multiple = await picker.pickMultipleVideos();
    single = null;
    _videoController?.dispose();
    setState(() {});
  }

  Future<void> _handlePickAnyFile() async {
    multiple = await picker.pickAnyFile(allowMultiple: true);
    single = null;
    _videoController?.dispose();
    setState(() {});
  }

  Future<void> _handlePickFolder() async {
    final folderPath = await FilePicker.platform.getDirectoryPath();

    if (folderPath == null) {
      setState(() {
        selectedFolder = null;
        folderFiles = [];
      });
      return;
    }

    selectedFolder = folderPath;

    // βœ… Pick all files inside selected folder using FilePicker SAF
    final result = await FilePicker.platform.pickFiles(
      allowMultiple: true,
      initialDirectory: folderPath, // THIS is the fix!
      type: FileType.any,
    );

    if (result == null) {
      setState(() => folderFiles = []);
      return;
    }

    // Convert to FileSystemEntity-like structure
    folderFiles = result.paths.whereType<String>().map((p) => File(p)).toList();

    setState(() {});
  }

  Future<void> _handlePickMediaMixed() async {
    multiple = await picker.pickMedia();
    single = null;
    _videoController?.dispose();
    setState(() {});
  }

  IconData _fileIcon(String path) {
    final ext = path.split(".").last.toLowerCase();

    if (["png", "jpg", "jpeg", "gif", "webp"].contains(ext)) return Icons.image;
    if (["mp4", "mov", "mkv", "avi", "webm"].contains(ext))
      return Icons.video_file;
    if (["mp3", "wav", "aac", "m4a"].contains(ext)) return Icons.audiotrack;
    if (["pdf"].contains(ext)) return Icons.picture_as_pdf;
    return Icons.insert_drive_file;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("EasyMediaPicker β€” Demo")),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: SingleChildScrollView(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              const Text(
                "πŸ“Έ Media Picker Controls",
                style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
              ),
              const SizedBox(height: 12),

              // ---------------- BUTTON GROUPS ----------------
              buildGroupTitle("β–Ά Images"),
              Wrap(
                spacing: 10,
                runSpacing: 10,
                children: [
                  ElevatedButton(
                    onPressed: _handlePickImage,
                    child: const Text("Pick Image"),
                  ),
                  ElevatedButton(
                    onPressed: _handleCaptureImage,
                    child: const Text("Capture Image"),
                  ),
                  ElevatedButton(
                    onPressed: _handlePickImagesMultiple,
                    child: const Text("Pick Multiple Images"),
                  ),
                ],
              ),

              const SizedBox(height: 20),
              buildGroupTitle("πŸŽ₯ Videos"),
              Wrap(
                spacing: 10,
                runSpacing: 10,
                children: [
                  ElevatedButton(
                    onPressed: _handlePickVideo,
                    child: const Text("Pick Video"),
                  ),
                  ElevatedButton(
                    onPressed: _handleCaptureVideo,
                    child: const Text("Capture Video"),
                  ),
                  ElevatedButton(
                    onPressed: _handlePickVideosMultiple,
                    child: const Text("Pick Multiple Videos"),
                  ),
                ],
              ),

              const SizedBox(height: 20),
              buildGroupTitle("🎡 Audio & πŸ“‘ Documents"),
              Wrap(
                spacing: 10,
                runSpacing: 10,
                children: [
                  ElevatedButton(
                    onPressed: () async {
                      multiple = await picker.pickAudio(
                        const AudioPickOptions(allowMultiple: true),
                      );
                      single = null;
                      _videoController?.dispose();
                      setState(() {});
                    },
                    child: const Text("Pick Audio (multi)"),
                  ),
                  ElevatedButton(
                    onPressed: () async {
                      multiple = await picker.pickDocument(
                        const DocumentPickOptions(allowMultiple: true),
                      );
                      single = null;
                      _videoController?.dispose();
                      setState(() {});
                    },
                    child: const Text("Pick Document"),
                  ),
                  ElevatedButton(
                    onPressed: () async {
                      multiple = await picker.pickDocument(
                        const DocumentPickOptions(
                          allowMultiple: true,
                          extensions: ['json', 'apk', 'zip'],
                        ),
                      );
                      single = null;
                      _videoController?.dispose();
                      setState(() {});
                    },
                    child: const Text("Document (custom ext)"),
                  ),
                ],
              ),

              const SizedBox(height: 20),
              buildGroupTitle("πŸ“ Folder / Any File / Mixed Media"),
              Wrap(
                spacing: 10,
                runSpacing: 10,
                children: [
                  ElevatedButton(
                    onPressed: _handlePickAnyFile,
                    child: const Text("Pick Any File"),
                  ),
                  ElevatedButton(
                    onPressed: _handlePickFolder,
                    child: const Text("Pick Folder"),
                  ),
                  ElevatedButton(
                    onPressed: _handlePickMediaMixed,
                    child: const Text("Pick Media (mixed)"),
                  ),
                ],
              ),

              const SizedBox(height: 20),
              Center(
                child: ElevatedButton(
                  onPressed: () {
                    single = null;
                    multiple = [];
                    _videoController?.dispose();
                    selectedFolder = null;
                    folderFiles = [];
                    setState(() {});
                  },
                  style: ElevatedButton.styleFrom(
                    backgroundColor: Colors.indigo,
                  ),
                  child: const Text(
                    "Clear All",
                    style: TextStyle(color: Colors.white),
                  ),
                ),
              ),

              const SizedBox(height: 20),
              const Divider(height: 30),

              // ---------------- PREVIEWS ----------------
              const Text(
                "πŸ“Œ Single File Preview",
                style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
              ),
              const SizedBox(height: 10),
              _singlePreview(),

              const SizedBox(height: 25),
              const Divider(height: 30),

              const Text(
                "πŸ“‚ Multiple Files Preview",
                style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
              ),
              const SizedBox(height: 10),
              _multiplePreview(),

              const Divider(height: 30),

              const Text(
                "πŸ“ Folder Preview",
                style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
              ),
              SizedBox(height: 10),
              _folderPreview(),

              const SizedBox(height: 25),
            ],
          ),
        ),
      ),
    );
  }
}
3
likes
160
points
150
downloads

Publisher

verified publisherronak-vasoliya.devservers.site

Weekly Downloads

A cross-platform media picker for image, video, audio and documents.

Homepage

Documentation

API reference

License

MIT (license)

Dependencies

file_picker, flutter, flutter_plugin_android_lifecycle, image_picker, path, permission_handler, video_player

More

Packages that depend on easy_media_picker