file_picker_slider 0.0.5 copy "file_picker_slider: ^0.0.5" to clipboard
file_picker_slider: ^0.0.5 copied to clipboard

Cross-platform Flutter file picker with standard input-style UI, optional previews, and mobile camera/image support.

example/lib/main.dart

import 'package:file_picker_slider/file_picker_slider.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  ThemeMode _themeMode = ThemeMode.system;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'File Picker Slider',
      themeMode: _themeMode,
      theme: _buildTheme(Brightness.light),
      darkTheme: _buildTheme(Brightness.dark),
      home: _ExampleHome(
        themeMode: _themeMode,
        onToggleTheme: _toggleThemeMode,
      ),
    );
  }

  ThemeData _buildTheme(Brightness brightness) {
    final isDark = brightness == Brightness.dark;
    final seed = isDark ? const Color(0xFF56C4D6) : const Color(0xFF0D9488);
    final scheme = ColorScheme.fromSeed(
      seedColor: seed,
      brightness: brightness,
    );

    return ThemeData(
      colorScheme: scheme,
      useMaterial3: true,
      scaffoldBackgroundColor:
          isDark ? const Color(0xFF0B1720) : const Color(0xFFF4F7F5),
      appBarTheme: AppBarTheme(
        backgroundColor: Colors.transparent,
        foregroundColor: scheme.onSurface,
        elevation: 0,
      ),
      chipTheme: ChipThemeData(
        backgroundColor: scheme.surface,
        side: BorderSide(color: scheme.outlineVariant),
      ),
      extensions: <ThemeExtension<dynamic>>[
        FilePickerSliderThemeData(
          backgroundColor:
              isDark ? const Color(0xFF10202A) : const Color(0xFFFFFFFF),
          borderColor:
              isDark ? const Color(0xFF1F3A45) : const Color(0xFFD1E6E3),
          accentColor:
              isDark ? const Color(0xFF56C4D6) : const Color(0xFF0D9488),
          accentForegroundColor: Colors.white,
          overlayColor: Colors.black.withOpacity(0.42),
          fileChipColor:
              isDark ? const Color(0xFF17303A) : const Color(0xFFE7F5F3),
          fileChipForegroundColor:
              isDark ? const Color(0xFFE5FBFF) : const Color(0xFF154B46),
          indicatorColor:
              isDark ? const Color(0xFF9AE8F4) : const Color(0xFF0F766E),
          inactiveIndicatorColor:
              isDark ? const Color(0xFF2A505B) : const Color(0xFFB7D7D3),
          backgroundGradient: LinearGradient(
            begin: Alignment.topLeft,
            end: Alignment.bottomRight,
            colors: isDark
                ? const <Color>[Color(0xFF10202A), Color(0xFF163241)]
                : const <Color>[Color(0xFFFFFFFF), Color(0xFFE8F7F3)],
          ),
        ),
      ],
    );
  }

  void _toggleThemeMode() {
    setState(() {
      _themeMode =
          _themeMode == ThemeMode.dark ? ThemeMode.light : ThemeMode.dark;
    });
  }
}

class _ExampleHome extends StatefulWidget {
  const _ExampleHome({
    required this.themeMode,
    required this.onToggleTheme,
  });

  final ThemeMode themeMode;
  final VoidCallback onToggleTheme;

  @override
  State<_ExampleHome> createState() => _ExampleHomeState();
}

class _ExampleHomeState extends State<_ExampleHome> {
  List<AppFile> _selectedFiles = <AppFile>[];
  List<AppFile> _customFiles = <AppFile>[];

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final textTheme = theme.textTheme;
    final colors = theme.colorScheme;

    return Scaffold(
      appBar: AppBar(
        title: const Text('File Picker Slider'),
        actions: <Widget>[
          IconButton(
            onPressed: widget.onToggleTheme,
            icon: Icon(
              widget.themeMode == ThemeMode.dark
                  ? Icons.light_mode_rounded
                  : Icons.dark_mode_rounded,
            ),
            tooltip: 'Toggle theme',
          ),
        ],
      ),
      body: SafeArea(
        child: Center(
          child: ConstrainedBox(
            constraints: const BoxConstraints(maxWidth: 840),
            child: ListView(
              padding: const EdgeInsets.all(20),
              children: <Widget>[
                Text(
                  'HTML-style file input',
                  style: textTheme.headlineSmall?.copyWith(
                    fontWeight: FontWeight.w700,
                    color: colors.onSurface,
                  ),
                ),
                const SizedBox(height: 8),
                Text(
                  'This default layout now behaves like a normal file input on web and mobile, while still giving you optional previews and theme control.',
                  style: textTheme.bodyLarge?.copyWith(
                    color: colors.onSurfaceVariant,
                    height: 1.45,
                  ),
                ),
                const SizedBox(height: 20),
                FilePickerWidget(
                  pickButtonLabel: 'Select files',
                  placeholderWidget: Container(
                    padding: const EdgeInsets.symmetric(
                      vertical: 12,
                      horizontal: 16,
                    ),
                    decoration: BoxDecoration(
                      color: colors.primaryContainer,
                      borderRadius: BorderRadius.circular(8),
                    ),
                    child: Text(
                      'Tap to select files',
                      style: textTheme.bodyMedium?.copyWith(
                        color: colors.onPrimaryContainer,
                      ),
                    ),
                  ),
                  title: 'Product gallery',
                  subtitle:
                      'Choose one or more files. On mobile you also get a camera shortcut when single image mode is used.',
                  allowMultiple: true,
                  height: 320,
                  onFilePicked: (files) {
                    setState(() {
                      _selectedFiles = files;
                    });
                  },
                ),
                const SizedBox(height: 16),
                Text(
                  _selectedFiles.isEmpty
                      ? 'No files selected yet.'
                      : '${_selectedFiles.length} file(s) selected',
                  style: textTheme.titleMedium?.copyWith(
                    fontWeight: FontWeight.w600,
                    color: colors.onSurface,
                  ),
                ),
                const SizedBox(height: 24),
                Text(
                  'Custom widget trigger',
                  style: textTheme.headlineSmall?.copyWith(
                    fontWeight: FontWeight.w700,
                    color: colors.onSurface,
                  ),
                ),
                const SizedBox(height: 8),
                Text(
                  'Use customBuilder when you want your own widget but still want the same picker logic underneath.',
                  style: textTheme.bodyLarge?.copyWith(
                    color: colors.onSurfaceVariant,
                    height: 1.45,
                  ),
                ),
                const SizedBox(height: 16),
                FilePickerWidget(
                  showPreview: false,
                  onFilePicked: (files) {
                    setState(() {
                      _customFiles = files;
                    });
                  },
                  customBuilder: (context, state) {
                    final label = state.hasFiles
                        ? state.activeFile!.displayName
                        : 'Upload agreement';
                    final localTheme = Theme.of(context);

                    return DecoratedBox(
                      decoration: BoxDecoration(
                        color: localTheme.colorScheme.surface,
                        borderRadius: BorderRadius.circular(18),
                        border: Border.all(
                          color: localTheme.colorScheme.outlineVariant,
                        ),
                      ),
                      child: ListTile(
                        leading: const Icon(Icons.file_upload_outlined),
                        title: Text(label),
                        subtitle: Text(
                          state.hasFiles
                              ? 'Tap to replace the selected file'
                              : 'Tap to open the picker',
                        ),
                        trailing: Wrap(
                          spacing: 8,
                          crossAxisAlignment: WrapCrossAlignment.center,
                          children: <Widget>[
                            if (state.canOpenFullscreen)
                              IconButton(
                                onPressed: () => state.openFullscreen!(),
                                tooltip: 'View fullscreen',
                                icon: const Icon(Icons.fullscreen_rounded),
                              ),
                            FilledButton(
                              onPressed: state.isBusy
                                  ? null
                                  : () => state.openPicker(),
                              child: const Text('Browse'),
                            ),
                          ],
                        ),
                        onTap: state.isBusy ? null : () => state.openPicker(),
                      ),
                    );
                  },
                ),
                if (_customFiles.isNotEmpty) ...<Widget>[
                  const SizedBox(height: 12),
                  Text(
                    'Custom picker selection: ${_customFiles.first.displayName}',
                    style: textTheme.bodyLarge?.copyWith(
                      color: colors.onSurface,
                    ),
                  ),
                ],
              ],
            ),
          ),
        ),
      ),
    );
  }
}
2
likes
120
points
73
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Cross-platform Flutter file picker with standard input-style UI, optional previews, and mobile camera/image support.

Homepage

Topics

#flutter #file-picker #image-picker #upload #widget

License

MIT (license)

Dependencies

cross_file, file_picker, flutter, image_picker

More

Packages that depend on file_picker_slider