firebase_uploader_plus 1.0.0 copy "firebase_uploader_plus: ^1.0.0" to clipboard
firebase_uploader_plus: ^1.0.0 copied to clipboard

All-in-One Firebase File & Metadata Uploader with Firestore integration, real-time streams, and smart auto-pathing. Upload files with progress tracking, camera capture, and automatic metadata management.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_uploader_plus/firebase_uploader_plus.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Firebase Uploader Plus Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        useMaterial3: true,
      ),
      home: const AuthWrapper(),
    );
  }
}

class AuthWrapper extends StatelessWidget {
  const AuthWrapper({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<User?>(
      stream: FirebaseAuth.instance.authStateChanges(),
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const Scaffold(
            body: Center(child: CircularProgressIndicator()),
          );
        }

        if (snapshot.hasData) {
          return const HomeScreen();
        }

        return const LoginScreen();
      },
    );
  }
}

class LoginScreen extends StatelessWidget {
  const LoginScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Firebase Uploader Plus Demo'),
      ),
      body: Center(
        child: Padding(
          padding: const EdgeInsets.all(24),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              const Icon(
                Icons.cloud_upload,
                size: 64,
                color: Colors.blue,
              ),
              const SizedBox(height: 24),
              const Text(
                'Firebase Uploader Plus',
                style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
              ),
              const SizedBox(height: 8),
              const Text(
                'All-in-One Firebase File & Metadata Uploader',
                style: TextStyle(fontSize: 16),
                textAlign: TextAlign.center,
              ),
              const SizedBox(height: 48),
              SizedBox(
                width: double.infinity,
                child: ElevatedButton(
                  onPressed: () => _signInAnonymously(context),
                  child: const Text('Sign In Anonymously'),
                ),
              ),
              const SizedBox(height: 16),
              TextButton(
                onPressed: () => _showEmailSignIn(context),
                child: const Text('Sign In with Email'),
              ),
            ],
          ),
        ),
      ),
    );
  }

  Future<void> _signInAnonymously(BuildContext context) async {
    try {
      await FirebaseAuth.instance.signInAnonymously();
    } catch (e) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Failed to sign in: $e')),
      );
    }
  }

  void _showEmailSignIn(BuildContext context) {
    // Simple email/password implementation
    showDialog(
      context: context,
      builder: (context) => const EmailSignInDialog(),
    );
  }
}

class EmailSignInDialog extends StatefulWidget {
  const EmailSignInDialog({Key? key}) : super(key: key);

  @override
  State<EmailSignInDialog> createState() => _EmailSignInDialogState();
}

class _EmailSignInDialogState extends State<EmailSignInDialog> {
  final _emailController = TextEditingController();
  final _passwordController = TextEditingController();
  bool _isSignUp = false;
  bool _isLoading = false;

  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      title: Text(_isSignUp ? 'Sign Up' : 'Sign In'),
      content: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          TextField(
            controller: _emailController,
            decoration: const InputDecoration(labelText: 'Email'),
            keyboardType: TextInputType.emailAddress,
          ),
          TextField(
            controller: _passwordController,
            decoration: const InputDecoration(labelText: 'Password'),
            obscureText: true,
          ),
          const SizedBox(height: 16),
          TextButton(
            onPressed: () {
              setState(() {
                _isSignUp = !_isSignUp;
              });
            },
            child: Text(_isSignUp 
                ? 'Already have account? Sign In' 
                : 'Need account? Sign Up'),
          ),
        ],
      ),
      actions: [
        TextButton(
          onPressed: () => Navigator.pop(context),
          child: const Text('Cancel'),
        ),
        ElevatedButton(
          onPressed: _isLoading ? null : _handleAuth,
          child: _isLoading 
              ? const SizedBox(
                  width: 16, 
                  height: 16, 
                  child: CircularProgressIndicator(strokeWidth: 2),
                )
              : Text(_isSignUp ? 'Sign Up' : 'Sign In'),
        ),
      ],
    );
  }

  Future<void> _handleAuth() async {
    setState(() {
      _isLoading = true;
    });

    try {
      if (_isSignUp) {
        await FirebaseAuth.instance.createUserWithEmailAndPassword(
          email: _emailController.text.trim(),
          password: _passwordController.text,
        );
      } else {
        await FirebaseAuth.instance.signInWithEmailAndPassword(
          email: _emailController.text.trim(),
          password: _passwordController.text,
        );
      }
      Navigator.pop(context);
    } catch (e) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Authentication failed: $e')),
      );
    } finally {
      setState(() {
        _isLoading = false;
      });
    }
  }
}

class HomeScreen extends StatefulWidget {
  const HomeScreen({Key? key}) : super(key: key);

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> with TickerProviderStateMixin {
  late TabController _tabController;

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: 3, vsync: this);
  }

  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final user = FirebaseAuth.instance.currentUser;
    
    return Scaffold(
      appBar: AppBar(
        title: const Text('Firebase Uploader Plus'),
        actions: [
          PopupMenuButton<String>(
            onSelected: (value) {
              if (value == 'logout') {
                FirebaseAuth.instance.signOut();
              }
            },
            itemBuilder: (context) => [
              PopupMenuItem(
                value: 'logout',
                child: Text('Sign Out (${user?.email ?? 'Anonymous'})'),
              ),
            ],
          ),
        ],
        bottom: TabBar(
          controller: _tabController,
          tabs: const [
            Tab(text: 'All Files', icon: Icon(Icons.folder)),
            Tab(text: 'Images', icon: Icon(Icons.image)),
            Tab(text: 'Documents', icon: Icon(Icons.description)),
          ],
        ),
      ),
      body: TabBarView(
        controller: _tabController,
        children: [
          // All Files Tab
          FirebaseUploader(
            firestorePath: 'user_uploads',
            firebaseStoragePath: 'uploads/users',
            enablePreview: true,
            enableCamera: true,
            enableMultipleFiles: true,
            maxFileSize: 10 * 1024 * 1024, // 10MB
            onUploadComplete: (metadata) {
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(
                  content: Text('Uploaded: ${metadata.fileName}'),
                  backgroundColor: Colors.green,
                ),
              );
            },
            onUploadError: (error) {
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(
                  content: Text('Upload error: $error'),
                  backgroundColor: Colors.red,
                ),
              );
            },
            customMetadata: {
              'app_version': '1.0.0',
              'platform': 'flutter_demo',
            },
          ),

          // Images Only Tab
          FirebaseUploader(
            allowedExtensions: const ['jpg', 'jpeg', 'png', 'gif', 'webp'],
            firestorePath: 'image_uploads',
            firebaseStoragePath: 'uploads/images',
            enablePreview: true,
            enableCamera: true,
            enableMultipleFiles: true,
            maxFileSize: 5 * 1024 * 1024, // 5MB
            onUploadComplete: (metadata) {
              print('Image uploaded: ${metadata.downloadUrl}');
            },
            headerBuilder: (context) => Container(
              padding: const EdgeInsets.all(16),
              child: Column(
                children: [
                  const Text(
                    'Image Gallery',
                    style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
                  ),
                  const SizedBox(height: 8),
                  Row(
                    children: [
                      Expanded(
                        child: ElevatedButton.icon(
                          onPressed: () {
                            // Custom image picker logic
                          },
                          icon: const Icon(Icons.photo_library),
                          label: const Text('Gallery'),
                        ),
                      ),
                      const SizedBox(width: 8),
                      Expanded(
                        child: ElevatedButton.icon(
                          onPressed: () {
                            // Custom camera logic
                          },
                          icon: const Icon(Icons.camera_alt),
                          label: const Text('Camera'),
                        ),
                      ),
                    ],
                  ),
                ],
              ),
            ),
          ),

          // Documents Only Tab
          FirebaseUploader(
            allowedExtensions: const ['pdf', 'doc', 'docx', 'txt'],
            firestorePath: 'document_uploads',
            firebaseStoragePath: 'uploads/documents',
            enablePreview: false,
            enableCamera: false,
            enableMultipleFiles: true,
            maxFileSize: 25 * 1024 * 1024, // 25MB
            onUploadComplete: (metadata) {
              print('Document uploaded: ${metadata.fileName}');
            },
            fileTileBuilder: (context, upload) => Card(
              margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
              child: ListTile(
                leading: CircleAvatar(
                  backgroundColor: Colors.blue[100],
                  child: Icon(
                    Icons.description,
                    color: Colors.blue[700],
                  ),
                ),
                title: Text(upload.fileName),
                subtitle: Text(
                  '${upload.formattedFileSize} • ${upload.fileType.toUpperCase()}',
                ),
                trailing: Row(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    IconButton(
                      icon: const Icon(Icons.download),
                      onPressed: () {
                        // Handle download
                        print('Download: ${upload.downloadUrl}');
                      },
                    ),
                    IconButton(
                      icon: const Icon(Icons.share),
                      onPressed: () {
                        // Handle share
                        print('Share: ${upload.fileName}');
                      },
                    ),
                  ],
                ),
              ),
            ),
            emptyStateBuilder: (context) => const Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Icon(
                    Icons.description,
                    size: 64,
                    color: Colors.grey,
                  ),
                  SizedBox(height: 16),
                  Text(
                    'No documents uploaded',
                    style: TextStyle(fontSize: 18),
                  ),
                  SizedBox(height: 8),
                  Text(
                    'Upload PDFs, Word docs, and text files',
                    style: TextStyle(color: Colors.grey),
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }
}
1
likes
130
points
29
downloads

Publisher

verified publishervipulflutter.dev

Weekly Downloads

All-in-One Firebase File & Metadata Uploader with Firestore integration, real-time streams, and smart auto-pathing. Upload files with progress tracking, camera capture, and automatic metadata management.

Repository (GitHub)
View/report issues
Contributing

Topics

#firebase #storage #firestore #upload #file-picker

Documentation

Documentation
API reference

Funding

Consider supporting this project:

paypal.me

License

MIT (license)

Dependencies

cached_network_image, cloud_firestore, connectivity_plus, file_picker, firebase_auth, firebase_core, firebase_storage, flutter, image_picker, mime, path

More

Packages that depend on firebase_uploader_plus