You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			299 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			Dart
		
	
			
		
		
	
	
			299 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			Dart
		
	
import 'dart:io';
 | 
						|
 | 
						|
import 'package:file_picker/file_picker.dart';
 | 
						|
import 'package:flutter/material.dart';
 | 
						|
import 'package:fluttertoast/fluttertoast.dart';
 | 
						|
import 'package:image_picker/image_picker.dart';
 | 
						|
import 'package:test_sa/extensions/context_extension.dart';
 | 
						|
import 'package:test_sa/extensions/int_extensions.dart';
 | 
						|
import 'package:test_sa/extensions/text_extensions.dart';
 | 
						|
import 'package:test_sa/extensions/widget_extensions.dart';
 | 
						|
import 'package:test_sa/new_views/app_style/app_color.dart';
 | 
						|
 | 
						|
import '../../../new_views/common_widgets/app_dashed_button.dart';
 | 
						|
import 'multi_image_picker_item.dart';
 | 
						|
 | 
						|
class MultiFilesPickerModel {
 | 
						|
  int id;
 | 
						|
  File file;
 | 
						|
 | 
						|
  MultiFilesPickerModel(this.id, this.file);
 | 
						|
}
 | 
						|
 | 
						|
class NewMultiFilesPicker extends StatefulWidget {
 | 
						|
  final String label;
 | 
						|
  final bool error;
 | 
						|
  final List<MultiFilesPickerModel> files;
 | 
						|
  final bool enabled, onlyImages;
 | 
						|
  double? buttonHeight;
 | 
						|
  Widget? buttonIcon;
 | 
						|
  Color? buttonColor;
 | 
						|
  final Function(List<MultiFilesPickerModel>)? onChange;
 | 
						|
  final bool showAsGrid;
 | 
						|
 | 
						|
  NewMultiFilesPicker(
 | 
						|
      {Key? key,
 | 
						|
      this.files = const <MultiFilesPickerModel>[],
 | 
						|
      required this.label,
 | 
						|
      this.error = false,
 | 
						|
      this.buttonHeight,
 | 
						|
      this.buttonIcon,
 | 
						|
      this.enabled = true,
 | 
						|
      this.onlyImages = false,
 | 
						|
      this.onChange,
 | 
						|
      this.showAsGrid = false,
 | 
						|
      this.buttonColor})
 | 
						|
      : super(key: key);
 | 
						|
 | 
						|
  @override
 | 
						|
  State<NewMultiFilesPicker> createState() => _MultiFilesPickerState();
 | 
						|
}
 | 
						|
 | 
						|
class _MultiFilesPickerState extends State<NewMultiFilesPicker> {
 | 
						|
  @override
 | 
						|
  Widget build(BuildContext context) {
 | 
						|
    return Column(
 | 
						|
      crossAxisAlignment: CrossAxisAlignment.start,
 | 
						|
      children: [
 | 
						|
        AppDashedButton(
 | 
						|
            title: widget.label,
 | 
						|
            height: widget.buttonHeight,
 | 
						|
            buttonColor: widget.buttonColor,
 | 
						|
            icon: widget.buttonIcon,
 | 
						|
            onPressed: (widget.enabled == false)
 | 
						|
                ? () {}
 | 
						|
                : widget.showAsGrid
 | 
						|
                    ? showFileSourceSheet
 | 
						|
                    : onFilePicker),
 | 
						|
        16.height,
 | 
						|
        if (widget.files.isNotEmpty)
 | 
						|
          Wrap(
 | 
						|
            spacing: 8.toScreenWidth,
 | 
						|
            children: List.generate(
 | 
						|
              widget.files!.length,
 | 
						|
              (index) {
 | 
						|
                File image = widget.files[index].file;
 | 
						|
                return MultiFilesPickerItem(
 | 
						|
                  file: image,
 | 
						|
                  enabled: widget.enabled,
 | 
						|
                  onRemoveTap: (image) {
 | 
						|
                    if (!widget.enabled) {
 | 
						|
                      return;
 | 
						|
                    }
 | 
						|
                    widget.files.remove(image);
 | 
						|
                    if (widget.onChange != null) {
 | 
						|
                      widget.onChange!(widget.files);
 | 
						|
                    }
 | 
						|
                    setState(() {});
 | 
						|
                  },
 | 
						|
                  onRemove: () {
 | 
						|
                    widget.files.removeAt(index);
 | 
						|
                    if (widget.onChange != null) {
 | 
						|
                      widget.onChange!(widget.files);
 | 
						|
                    }
 | 
						|
                    setState(() {});
 | 
						|
                  },
 | 
						|
                );
 | 
						|
              },
 | 
						|
            ),
 | 
						|
          ),
 | 
						|
      ],
 | 
						|
    );
 | 
						|
  }
 | 
						|
 | 
						|
  fromFilePicker() async {
 | 
						|
    FilePickerResult? result = await FilePicker.platform.pickFiles(
 | 
						|
      type: FileType.custom,
 | 
						|
      allowMultiple: true,
 | 
						|
      allowedExtensions: widget.onlyImages ? ['jpg', 'jpeg', 'png'] : ['jpg', 'jpeg', 'png', 'pdf', 'doc', 'docx', 'xlsx', 'pptx'],
 | 
						|
    );
 | 
						|
    if (result != null) {
 | 
						|
      for (var path in result.paths) {
 | 
						|
        widget.files.add(MultiFilesPickerModel(0, File(path!)));
 | 
						|
      }
 | 
						|
      setState(() {});
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  void showFileSourceSheet() async {
 | 
						|
    if (widget.files.length >= 5) {
 | 
						|
      Fluttertoast.showToast(msg: context.translation.maxImagesNumberIs5);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    ImageSource source = (await showModalBottomSheet(
 | 
						|
      context: context,
 | 
						|
      shape: const RoundedRectangleBorder(
 | 
						|
        borderRadius: BorderRadius.vertical(
 | 
						|
          top: Radius.circular(20),
 | 
						|
        ),
 | 
						|
      ),
 | 
						|
      clipBehavior: Clip.antiAliasWithSaveLayer,
 | 
						|
      builder: (BuildContext context) => Column(
 | 
						|
        mainAxisSize: MainAxisSize.min,
 | 
						|
        crossAxisAlignment: CrossAxisAlignment.start,
 | 
						|
        children: [
 | 
						|
          "Attach File".heading4(context),
 | 
						|
          12.height,
 | 
						|
          GridView(
 | 
						|
            padding: EdgeInsets.all(0),
 | 
						|
            shrinkWrap: true,
 | 
						|
            physics: const NeverScrollableScrollPhysics(),
 | 
						|
            gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, childAspectRatio: 1, crossAxisSpacing: 12, mainAxisSpacing: 12),
 | 
						|
            children: <Widget>[
 | 
						|
              gridItem(Icons.camera_enhance_rounded, context.translation.pickFromCamera).onPress(() => Navigator.of(context).pop(ImageSource.camera)),
 | 
						|
              gridItem(Icons.image_rounded, context.translation.pickFromGallery).onPress(() => Navigator.of(context).pop(ImageSource.gallery)),
 | 
						|
              gridItem(Icons.file_present_rounded, context.translation.pickFromFiles).onPress(() async {
 | 
						|
                await fromFilePicker();
 | 
						|
                Navigator.pop(context);
 | 
						|
              }),
 | 
						|
            ],
 | 
						|
          ),
 | 
						|
          12.height,
 | 
						|
        ],
 | 
						|
      ).paddingAll(21),
 | 
						|
    )) as ImageSource;
 | 
						|
 | 
						|
    if (source == null) return;
 | 
						|
 | 
						|
    final pickedFile = await ImagePicker().pickImage(source: source, imageQuality: 70, maxWidth: 800, maxHeight: 800);
 | 
						|
 | 
						|
    if (pickedFile != null) {
 | 
						|
      File fileImage = File(pickedFile.path);
 | 
						|
      if (fileImage != null) {
 | 
						|
        widget.files.add(MultiFilesPickerModel(0, fileImage));
 | 
						|
        if (widget.onChange != null) {
 | 
						|
          widget.onChange!(widget.files);
 | 
						|
        }
 | 
						|
        setState(() {});
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  Widget gridItem(IconData iconData, String title) {
 | 
						|
    return Container(
 | 
						|
      padding: EdgeInsets.all(12),
 | 
						|
      decoration: BoxDecoration(
 | 
						|
        color: Colors.white,
 | 
						|
        borderRadius: BorderRadius.circular(12),
 | 
						|
        border: Border.all(color: Color(0xffF1F1F1), width: 1),
 | 
						|
      ),
 | 
						|
      child: Column(
 | 
						|
        crossAxisAlignment: CrossAxisAlignment.start,
 | 
						|
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
 | 
						|
        children: [
 | 
						|
          Icon(iconData, color: Color(0xff7D859A), size: 36),
 | 
						|
          Text(
 | 
						|
            title,
 | 
						|
            style: TextStyle(fontSize: 12, fontWeight: FontWeight.w500),
 | 
						|
          ),
 | 
						|
        ],
 | 
						|
      ),
 | 
						|
    );
 | 
						|
  }
 | 
						|
 | 
						|
  onFilePicker() async {
 | 
						|
    if (widget.files.length >= 5) {
 | 
						|
      Fluttertoast.showToast(msg: context.translation.maxImagesNumberIs5);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    ImageSource? source = await showModalBottomSheet<ImageSource>(
 | 
						|
      context: context,
 | 
						|
      builder: (BuildContext context) {
 | 
						|
        Widget listCard({required String icon, required String label, required VoidCallback onTap}) {
 | 
						|
          return GestureDetector(
 | 
						|
            onTap: onTap,
 | 
						|
            child: Container(
 | 
						|
              constraints: BoxConstraints(minWidth: 111.toScreenWidth, minHeight: 111.toScreenHeight),
 | 
						|
              padding: EdgeInsets.symmetric(horizontal: 12.toScreenWidth, vertical: 12.toScreenHeight),
 | 
						|
              decoration: BoxDecoration(borderRadius: BorderRadius.circular(12), border: Border.all(width: 1, color: AppColor.white70)),
 | 
						|
              child: Column(
 | 
						|
                mainAxisSize: MainAxisSize.min,
 | 
						|
                crossAxisAlignment: CrossAxisAlignment.start,
 | 
						|
                children: [
 | 
						|
                  icon.toSvgAsset(),
 | 
						|
                  24.height,
 | 
						|
                  label.bodyText2(context).custom(color: AppColor.black20),
 | 
						|
                ],
 | 
						|
              ),
 | 
						|
            ),
 | 
						|
          );
 | 
						|
        }
 | 
						|
 | 
						|
        return Container(
 | 
						|
          padding: const EdgeInsets.all(16.0),
 | 
						|
          child: Row(
 | 
						|
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
 | 
						|
            children: <Widget>[
 | 
						|
              listCard(
 | 
						|
                icon: 'camera_icon',
 | 
						|
                label: '${context.translation.open}\n${context.translation.camera}',
 | 
						|
                onTap: () {
 | 
						|
                  Navigator.of(context).pop(ImageSource.camera);
 | 
						|
                },
 | 
						|
              ),
 | 
						|
              listCard(
 | 
						|
                icon: 'gallery_icon',
 | 
						|
                label: '${context.translation.open}\n${context.translation.gallery}',
 | 
						|
                onTap: () {
 | 
						|
                  Navigator.of(context).pop(ImageSource.gallery);
 | 
						|
                },
 | 
						|
              ),
 | 
						|
              listCard(
 | 
						|
                icon: 'file_icon',
 | 
						|
                label: '${context.translation.open}\n${context.translation.files}',
 | 
						|
                onTap: () async {
 | 
						|
                  await fromFilePicker();
 | 
						|
                  Navigator.pop(context);
 | 
						|
                },
 | 
						|
              ),
 | 
						|
            ],
 | 
						|
          ),
 | 
						|
        );
 | 
						|
      },
 | 
						|
    );
 | 
						|
    // ImageSource source = await showDialog(
 | 
						|
    //   context: context,
 | 
						|
    //   builder: (dialogContext) => CupertinoAlertDialog(
 | 
						|
    //     actions: <Widget>[
 | 
						|
    //       TextButton(
 | 
						|
    //         child: Text(context.translation.pickFromCamera),
 | 
						|
    //         onPressed: () {
 | 
						|
    //           Navigator.of(dialogContext).pop(ImageSource.camera);
 | 
						|
    //         },
 | 
						|
    //       ),
 | 
						|
    //       TextButton(
 | 
						|
    //         child: Text(context.translation.pickFromGallery),
 | 
						|
    //         onPressed: () {
 | 
						|
    //           Navigator.of(dialogContext).pop(ImageSource.gallery);
 | 
						|
    //         },
 | 
						|
    //       ),
 | 
						|
    //       TextButton(
 | 
						|
    //         child: Text(context.translation.pickFromFiles),
 | 
						|
    //         onPressed: () async {
 | 
						|
    //           await fromFilePicker();
 | 
						|
    //           Navigator.pop(context);
 | 
						|
    //         },
 | 
						|
    //       ),
 | 
						|
    //     ],
 | 
						|
    //   ),
 | 
						|
    // );
 | 
						|
    if (source == null) return;
 | 
						|
 | 
						|
    final pickedFile = await ImagePicker().pickImage(source: source, imageQuality: 70, maxWidth: 800, maxHeight: 800);
 | 
						|
 | 
						|
    if (pickedFile != null) {
 | 
						|
      File fileImage = File(pickedFile.path);
 | 
						|
      if (fileImage != null) {
 | 
						|
        widget.files.add(MultiFilesPickerModel(0, fileImage));
 | 
						|
        if (widget.onChange != null) {
 | 
						|
          widget.onChange!(widget.files);
 | 
						|
        }
 | 
						|
        setState(() {});
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    setState(() {});
 | 
						|
  }
 | 
						|
}
 |