From 9196710674a910bf5f734af811e71950d42a2fd7 Mon Sep 17 00:00:00 2001 From: Guillaume Roux Date: Thu, 30 May 2024 10:30:07 +0200 Subject: [PATCH] fix: fixed file info picking --- README.md | 7 ++ example/lib/sample/sample_page.dart | 2 +- lib/image_picker_web.dart | 102 +++++++++++++++--------- lib/src/extensions/file_extensions.dart | 26 ------ lib/src/models/media_info.dart | 15 ++-- lib/src/web_image_picker.dart | 62 -------------- pubspec.yaml | 2 +- 7 files changed, 82 insertions(+), 134 deletions(-) delete mode 100644 lib/src/extensions/file_extensions.dart delete mode 100644 lib/src/web_image_picker.dart diff --git a/README.md b/README.md index 274eab7..2ca4749 100644 --- a/README.md +++ b/README.md @@ -136,3 +136,10 @@ Load videos as `List` objects : ```dart List? videoFiles = await ImagePickerWeb.getMultiVideosAsFile(); ``` + +## Migration Guide + +### From 3.0.0 to 4.0.0 + +* The `WebImagePicker` class has been removed. Use methods from `ImagePickerWeb` class instead. +* `getImageInfo` and `getVideoInfo` are now methods and not getters. Use them like `ImagePickerWeb.getImageInfo()` and `ImagePickerWeb.getVideoInfo()`. \ No newline at end of file diff --git a/example/lib/sample/sample_page.dart b/example/lib/sample/sample_page.dart index b113f9d..ce83217 100644 --- a/example/lib/sample/sample_page.dart +++ b/example/lib/sample/sample_page.dart @@ -47,7 +47,7 @@ class _SamplePageState extends State { } Future _getImgInfo() async { - final infos = await ImagePickerWeb.getImageInfo; + final infos = await ImagePickerWeb.getImageInfo(); final data = infos?.data; if (data != null) { setState(() { diff --git a/lib/image_picker_web.dart b/lib/image_picker_web.dart index 5b618c2..192a862 100644 --- a/lib/image_picker_web.dart +++ b/lib/image_picker_web.dart @@ -1,41 +1,40 @@ library image_picker_web; import 'dart:async'; -import 'dart:convert'; import 'dart:html' as html; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_web_plugins/flutter_web_plugins.dart'; -import 'package:image_picker_web/src/extensions/file_extensions.dart' - show FileModifier; import 'package:image_picker_web/src/models/media_info.dart'; -import 'package:image_picker_web/src/web_image_picker.dart'; export 'src/models/media_info.dart'; class ImagePickerWeb { + const ImagePickerWeb._(); + static void registerWith(Registrar registrar) { - final channel = MethodChannel( - 'image_picker_web', - const StandardMethodCodec(), - registrar, - ); - final instance = WebImagePicker(); - channel.setMethodCallHandler((call) async { + MethodChannel('image_picker_web', const StandardMethodCodec(), registrar) + .setMethodCallHandler((call) { switch (call.method) { case 'pickImage': - return instance.pickImage(); + return getImageAsFile(); case 'pickVideo': - return instance.pickVideo(); + return getVideoAsFile(); + case 'pickMultiImage': + return getMultiImagesAsFile(); + case 'pickMultiVideo': + return getMultiVideosAsFile(); + case 'pickImageInfo': + return getImageInfo(); + case 'pickVideoInfo': + return getVideoInfo(); default: throw MissingPluginException(); } }); } - static const MethodChannel _methodChannel = MethodChannel('image_picker_web'); - static Future _pickFile(String type) async { final completer = Completer?>(); final input = html.FileUploadInputElement()..accept = '$type/*'; @@ -87,8 +86,25 @@ class ImagePickerWeb { return results.first; } + static Future?> _pickFileInfo(String type) async { + final file = await ImagePickerWeb._pickFile(type); + if (file == null) return null; + final reader = html.FileReader()..readAsDataUrl(file); + await reader.onLoad.first; + final encoded = reader.result; + if (encoded is! String) return null; + final stripped = + encoded.replaceFirst(RegExp('data:$type/[^;]+;base64,'), ''); + final fileName = file.name; + return { + 'name': fileName, + 'data': stripped, + 'data_scheme': encoded, + }; + } + /// source: https://stackoverflow.com/a/59420655/9942346 - Future?> _pickMultiFiles(String type) async { + static Future?> _pickMultiFiles(String type) async { final completer = Completer?>(); final input = html.FileUploadInputElement() ..multiple = true @@ -164,9 +180,8 @@ class ImagePickerWeb { /// Help to retrieve further image's informations about your picked source. /// /// Return an object [MediaInfo] containing image's informations. - static Future get getImageInfo async { - final data = - await _methodChannel.invokeMapMethod('pickImage'); + static Future getImageInfo() async { + final data = await _pickFileInfo('image'); if (data == null) return null; return MediaInfo.fromJson(data); } @@ -174,7 +189,7 @@ class ImagePickerWeb { /// Picker that allows multi-image selection and return a [Uint8List] list of /// the selected images. static Future?> getMultiImagesAsBytes() async { - final images = await ImagePickerWeb()._pickMultiFiles('image'); + final images = await _pickMultiFiles('image'); if (images == null) return null; final files = []; for (final img in images) { @@ -186,7 +201,7 @@ class ImagePickerWeb { /// Picker that allows multi-image selection and return an [Image.memory] list /// using the images' bytes. static Future?> getMultiImagesAsWidget() async { - final images = await ImagePickerWeb()._pickMultiFiles('image'); + final images = await _pickMultiFiles('image'); if (images == null) return null; final files = []; for (final img in images) { @@ -199,32 +214,25 @@ class ImagePickerWeb { /// Picker that allows multi-image selection and return a [html.File] list of /// the selected images. static Future?> getMultiImagesAsFile() { - return ImagePickerWeb()._pickMultiFiles('image'); + return _pickMultiFiles('image'); } /// Picker that close after selecting 1 video and return a [Uint8List] of the /// selected video. static Future getVideoAsBytes() async { - final dataMap = - await _methodChannel.invokeMapMethod('pickVideo'); - final data = dataMap?['data']; - if (data == null || data is! String) return null; - final imageData = base64.decode(data); - return imageData; + final video = await _pickFile('video'); + return video?.asBytes(); } /// Picker that close after selecting 1 video and return a [html.File] of the /// selected video. - static Future getVideoAsFile() { - return ImagePickerWeb._pickFile('video'); - } + static Future getVideoAsFile() => _pickFile('video'); /// Help to retrieve further video's informations about your picked source. /// /// Return an object [MediaInfo] containing video's informations. - static Future get getVideoInfo async { - final data = - await _methodChannel.invokeMapMethod('pickVideo'); + static Future getVideoInfo() async { + final data = await _pickFileInfo('video'); if (data == null) return null; return MediaInfo.fromJson(data); } @@ -232,7 +240,7 @@ class ImagePickerWeb { /// Picker that allows multi-video selection and return a [Uint8List] list of /// the selected videos. static Future?> getMultiVideosAsBytes() async { - final videos = await ImagePickerWeb()._pickMultiFiles('video'); + final videos = await _pickMultiFiles('video'); if (videos == null) return null; final files = []; for (final video in videos) { @@ -244,6 +252,28 @@ class ImagePickerWeb { /// Picker that allows multi-video selection and return a [html.File] list of /// the selected videos. static Future?> getMultiVideosAsFile() { - return ImagePickerWeb()._pickMultiFiles('video'); + return _pickMultiFiles('video'); + } +} + +typedef _ByteResult = FutureOr>; + +extension on html.File { + Future asBytes() async { + final bytesFile = Completer>(); + final reader = html.FileReader(); + reader.onLoad.listen( + (_) { + final result = reader.result; + if (result is! _ByteResult?) { + bytesFile.completeError('Result is not a byte result'); + return; + } + + bytesFile.complete(result); + }, + ); + reader.readAsArrayBuffer(this); + return Uint8List.fromList(await bytesFile.future); } } diff --git a/lib/src/extensions/file_extensions.dart b/lib/src/extensions/file_extensions.dart deleted file mode 100644 index b5ad422..0000000 --- a/lib/src/extensions/file_extensions.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'dart:async'; -import 'dart:html' as html; - -import 'dart:typed_data'; - -typedef _ByteResult = FutureOr>; - -extension FileModifier on html.File { - Future asBytes() async { - final bytesFile = Completer>(); - final reader = html.FileReader(); - reader.onLoad.listen( - (_) { - final result = reader.result; - if (result is! _ByteResult?) { - bytesFile.completeError('Result is not a byte result'); - return; - } - - bytesFile.complete(result); - }, - ); - reader.readAsArrayBuffer(this); - return Uint8List.fromList(await bytesFile.future); - } -} diff --git a/lib/src/models/media_info.dart b/lib/src/models/media_info.dart index f5ce151..1f891a7 100644 --- a/lib/src/models/media_info.dart +++ b/lib/src/models/media_info.dart @@ -1,5 +1,4 @@ import 'dart:convert'; - import 'dart:typed_data'; /// Class used to return informations retrieved from an image or video. @@ -9,7 +8,13 @@ class MediaInfo { this.base64, this.base64WithScheme, this.data, - }); + }) : assert( + fileName != null || + base64 != null || + base64WithScheme != null || + data != null, + 'At least one parameter must be not null.', + ); /// Factory constructor to generate [MediaInfo] from a [Map]. factory MediaInfo.fromJson(Map json) { @@ -50,9 +55,3 @@ class MediaInfo { }; } } - -/// Image's type. -enum ImageType { file, bytes, widget } - -/// Video's type. -enum VideoType { file, bytes } diff --git a/lib/src/web_image_picker.dart b/lib/src/web_image_picker.dart deleted file mode 100644 index 33af41d..0000000 --- a/lib/src/web_image_picker.dart +++ /dev/null @@ -1,62 +0,0 @@ -import 'dart:async'; -import 'dart:html' as html; - -class WebImagePicker { - Future?> pickImage() async { - final data = {}; - final input = html.FileUploadInputElement() - ..accept = 'image/*' - ..click(); - - html.document.body?.append(input); - - await input.onChange.first; - - final files = input.files; - if (files == null || files.isEmpty) return null; - - final reader = html.FileReader()..readAsDataUrl(files[0]); - await reader.onLoad.first; - - final encoded = reader.result; - if (encoded is! String) return null; - - final stripped = - encoded.replaceFirst(RegExp('data:image/[^;]+;base64,'), ''); - final imageName = input.files?.first.name; - - data.addAll({'name': imageName, 'data': stripped, 'data_scheme': encoded}); - input.remove(); - - return data; - } - - Future?> pickVideo() async { - final data = {}; - final input = html.FileUploadInputElement() - ..accept = 'video/*' - ..click(); - - html.document.body?.append(input); - - await input.onChange.first; - - final files = input.files; - if (files == null || files.isEmpty) return null; - - final reader = html.FileReader()..readAsDataUrl(files[0]); - await reader.onLoad.first; - - final encoded = reader.result; - if (encoded is! String) return null; - - final stripped = - encoded.replaceFirst(RegExp('data:video/[^;]+;base64,'), ''); - final videoName = input.files?.first.name; - - data.addAll({'name': videoName, 'data': stripped, 'data_scheme': encoded}); - input.remove(); - - return data; - } -} diff --git a/pubspec.yaml b/pubspec.yaml index 6783ef5..a9c0443 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: image_picker_web description: Flutter Web Plugin to pick Images (as Widget, File or Uint8List) and Videos (as File or Uint8List) -version: 3.1.1 +version: 4.0.0 repository: https://github.com/Ahmadre/image_picker_web environment: