Atoms

Input File Picker

filepicker

How to use?

const InputFilePicker(
    label: 'Pick File',
),

Pass callback function to get response when user selects file(s).

InputFilePicker(
    label: 'Pick File',
    callback: (List<PlatformFile>? files) {
        if (files == null) return;
        if (files.isEmpty) return;
        Log.info(files.length, disableCloudLogging: true);
    },
),

Set withData to true to get file(s) with data.

const InputFilePicker(
    label: 'Pick File',
    withData: true,
),

Set allowMultiple to true to allow user to select multiple files.

const InputFilePicker(
    label: 'Pick File',
    allowMultiple: true,
),

Set fileType to allow specific file types. Valid values are FileType.image, FileType.media, FileType.audio, FileType.video, FileType.any. To allow specific extensions only, check below segment.

const InputFilePicker(
    label: 'Pick File',
    fileType: FileType.image,
),

Set fileType to FileType.custom and pass allowedExtensions.

const InputFilePicker(
    label: 'Pick File',
    fileType: FileType.custom,
    allowedExtensions: ['pdf'],
),

Paas padding parameter to set custom padding in input field.

InputFilePicker(
    label: 'Pick File',
    padding: horizontalPadding8 + verticalPadding4,
),

Paas isEnabled parameter to enable/ disable picker.

const InputFilePicker(
    label: 'Pick File',
    isEnabled: false,
),

Paas size parameter to change size of field. Available input sizes are enum InputSize { extraSmall, small, medium, large, extraLarge }

const InputFilePicker(
    label: 'Pick File',
    size: InputSize.extraSmall,
),

Paas iconBackgroundColor and iconColor parameter to change appereance of icon.

const InputFilePicker(
    label: 'Pick File',
    iconColor: Colors.white,
    iconBackgroundColor: Colors.pink,
),

Paas iconBackgroundColor and iconColor parameters to change appereance of icon.

const InputFilePicker(
    label: 'Pick File',
    iconColor: Colors.white,
    iconBackgroundColor: Colors.pink,
),

Pass validator and autoValidateMode parameters for validation.

InputFilePicker(
    label: 'Pick File',
    validator: (value) {
        if (value! == 'Pick File') return 'Please select file!';
        return null;
    },
    autoValidateMode: AutovalidateMode.always,
),

Source code

import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:team/vaahextendflutter/app_theme.dart';
import 'package:team/vaahextendflutter/helpers/constants.dart';
import 'package:team/vaahextendflutter/helpers/enums.dart';

class InputFilePicker extends StatefulWidget {
  final String label;
  final EdgeInsets padding;
  final double borderRadius;
  final bool isEnabled;
  final InputSize size;
  final Color? iconBackgroundColor;
  final Color? iconColor;
  final String? Function(String?)? validator;
  final AutovalidateMode? autoValidateMode;
  final Function(List<PlatformFile>?)? callback;
  final String? dialogTitle;
  final bool withData;
  final bool allowMultiple;
  final FileType fileType;
  final List<String>? allowedExtensions;

  const InputFilePicker({
    super.key,
    required this.label,
    this.padding = allPadding12,
    this.borderRadius = defaultPadding / 2,
    this.isEnabled = true,
    this.size = InputSize.medium,
    this.iconBackgroundColor,
    this.iconColor,
    this.validator,
    this.autoValidateMode,
    this.callback,
    this.dialogTitle,
    this.withData = false,
    this.allowMultiple = false,
    this.fileType = FileType.any,
    this.allowedExtensions,
  });

  @override
  State<InputFilePicker> createState() => _InputFilePickerState();
}

class _InputFilePickerState extends State<InputFilePicker> {
  final TextEditingController _controller = TextEditingController();

  @override
  void initState() {
    _controller.text = widget.label;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return TextFormField(
      onTap: _onTap,
      decoration: InputDecoration(
        contentPadding: widget.padding,
        border: border(AppTheme.colors['black']!.shade400),
        enabledBorder: border(AppTheme.colors['black']!.shade400),
        disabledBorder: border(AppTheme.colors['black']!.shade300),
        focusedBorder: border(AppTheme.colors['black']!.shade400),
        errorBorder: border(AppTheme.colors['danger']!.shade400),
        focusedErrorBorder: border(AppTheme.colors['danger']!.shade400),
        errorStyle: TextStyle(color: AppTheme.colors['danger']!.shade400),
        suffixIcon: InkWell(
          child: Container(
            decoration: BoxDecoration(
              borderRadius: BorderRadius.only(
                topRight: Radius.circular(widget.borderRadius),
                bottomRight: Radius.circular(widget.borderRadius),
              ),
              color: widget.iconBackgroundColor ?? AppTheme.colors['primary'],
            ),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                FaIcon(
                  asset(),
                  size: getFontSize() * 1.3,
                  color: widget.iconColor ?? AppTheme.colors['white'],
                ),
              ],
            ),
          ),
        ),
      ),
      controller: _controller,
      readOnly: true,
      style: TextStyle(
        fontSize: getFontSize(),
        color: widget.isEnabled
            ? AppTheme.colors['black']!.shade400
            : AppTheme.colors['black']!.shade300,
      ),
      enabled: widget.isEnabled,
      validator: widget.validator,
      autovalidateMode: widget.autoValidateMode,
    );
  }

  void _onTap() async {
    FilePickerResult? result = await FilePicker.platform.pickFiles(
      allowedExtensions: widget.allowedExtensions,
      dialogTitle: widget.dialogTitle,
      type: widget.fileType,
      allowMultiple: widget.allowMultiple,
      withData: widget.withData,
    );

    if (result != null) {
      List<PlatformFile> files = result.files;
      setState(() {
        _controller.text = files.map((element) => element.name).toList().join(', ');
      });
      if (widget.callback != null) widget.callback!(files);
    } else {
      // User canceled the picker
    }
  }

  OutlineInputBorder border(Color color) {
    return OutlineInputBorder(
      borderRadius: BorderRadius.circular(widget.borderRadius),
      borderSide: BorderSide(
        width: 1,
        color: color,
      ),
    );
  }

  double getFontSize() {
    switch (widget.size) {
      case InputSize.extraSmall:
        return AppTheme.extraSmall;
      case InputSize.small:
        return AppTheme.small;
      case InputSize.large:
        return AppTheme.large;
      case InputSize.extraLarge:
        return AppTheme.extraLarge;
      default:
        return AppTheme.medium;
    }
  }

  IconData asset() {
    return FontAwesomeIcons.file;
  }
}

Copyright © 2024