From 133f3225bf6a16f3f9b0256a6b3b7e17bbb41e79 Mon Sep 17 00:00:00 2001 From: bymoye Date: Sat, 20 Jul 2024 23:20:46 +0800 Subject: [PATCH 1/5] feat: support wasm --- .../big_video_upload_view.dart | 14 +- .../multi_video_upload.dart | 16 +- example/lib/sample/sample_page.dart | 2 +- example/pubspec.yaml | 1 + lib/image_picker_web.dart | 162 ++++++++++++------ pubspec.yaml | 1 + 6 files changed, 127 insertions(+), 69 deletions(-) diff --git a/example/lib/big_video_upload/big_video_upload_view.dart b/example/lib/big_video_upload/big_video_upload_view.dart index 37040b8..5074491 100644 --- a/example/lib/big_video_upload/big_video_upload_view.dart +++ b/example/lib/big_video_upload/big_video_upload_view.dart @@ -1,4 +1,5 @@ -import 'dart:html' as html; +import 'dart:js_interop'; +import 'package:web/web.dart' as web; import 'dart:typed_data'; import 'package:flutter/material.dart'; @@ -16,17 +17,18 @@ class _BigVideoUploadViewState extends State { VideoPlayerController? _controller; Future _createVideo(Uint8List bytes) async { - final blob = html.Blob([bytes]); - final url = html.Url.createObjectUrlFromBlob(blob); + final blob = web.Blob(bytes.map((int byte) => byte.toJS).toList().toJS); + final url = web.URL.createObjectURL(blob); + // final url = html.Url.createObjectUrlFromBlob(blob); _controller = VideoPlayerController.networkUrl(Uri.parse(url)); await _controller?.initialize(); setState(() {}); } - Future _load(html.File file) async { - final reader = html.FileReader(); + Future _load(web.File file) async { + final reader = web.FileReader(); reader.readAsArrayBuffer(file); - await reader.onLoad.first; + await reader.onLoadEnd.first; reader.onLoadEnd; return reader.result as Uint8List; } diff --git a/example/lib/multi_video_upload/multi_video_upload.dart b/example/lib/multi_video_upload/multi_video_upload.dart index 81e9737..12f7943 100644 --- a/example/lib/multi_video_upload/multi_video_upload.dart +++ b/example/lib/multi_video_upload/multi_video_upload.dart @@ -1,4 +1,7 @@ -import 'dart:html' as html; +// import 'dart:html' as html; +import 'dart:js_interop'; + +import 'package:web/web.dart' as web; import 'dart:typed_data'; import 'package:flutter/material.dart'; @@ -17,8 +20,8 @@ class _MultiVideoUploadViewState extends State { Future _createVideos(List bytesList) async { for (final bytes in bytesList) { - final blob = html.Blob([bytes]); - final url = html.Url.createObjectUrlFromBlob(blob); + final blob = web.Blob(bytes.map((int byte) => byte.toJS).toList().toJS); + final url = web.URL.createObjectURL(blob); final controller = VideoPlayerController.networkUrl(Uri.parse(url)); await controller.initialize(); _controllers.add(controller); @@ -26,10 +29,11 @@ class _MultiVideoUploadViewState extends State { setState(() {}); } - Future _load(html.File file) async { - final reader = html.FileReader(); + Future _load(web.File file) async { + final reader = web.FileReader(); reader.readAsArrayBuffer(file); - await reader.onLoad.first; + await reader.onLoadEnd.first; + // await reader.onLoad.first; reader.onLoadEnd; return reader.result as Uint8List; } diff --git a/example/lib/sample/sample_page.dart b/example/lib/sample/sample_page.dart index ce83217..a7b7cce 100644 --- a/example/lib/sample/sample_page.dart +++ b/example/lib/sample/sample_page.dart @@ -43,7 +43,7 @@ class _SamplePageState extends State { Future _getImgFile() async { final infos = await ImagePickerWeb.getImageAsFile(); setState(() => _imageInfo = - 'Name: ${infos?.name}\nRelative Path: ${infos?.relativePath}'); + 'Name: ${infos?.name}\nRelative Path: ${infos?.webkitRelativePath}'); } Future _getImgInfo() async { diff --git a/example/pubspec.yaml b/example/pubspec.yaml index fe87bf9..8497530 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -9,6 +9,7 @@ dependencies: flutter: sdk: flutter video_player: ^2.7.0 + web: ^1.0.0 dev_dependencies: flutter_test: diff --git a/lib/image_picker_web.dart b/lib/image_picker_web.dart index 192a862..272fd02 100644 --- a/lib/image_picker_web.dart +++ b/lib/image_picker_web.dart @@ -1,8 +1,11 @@ library image_picker_web; import 'dart:async'; -import 'dart:html' as html; - +import 'dart:js_interop'; +import 'dart:typed_data'; +// import 'dart:html' as html; +import 'package:web/web.dart' as web; +import 'dart:js_util' as js_util; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_web_plugins/flutter_web_plugins.dart'; @@ -10,6 +13,15 @@ import 'package:image_picker_web/src/models/media_info.dart'; export 'src/models/media_info.dart'; +/// Adds a `toList` method to [web.FileList] objects. +extension WebFileListToDartList on web.FileList { + /// Converts a [web.FileList] into a [List] of [web.File]. + /// + /// This method makes a copy. + List get toList => + [for (int i = 0; i < length; i++) item(i)!]; +} + class ImagePickerWeb { const ImagePickerWeb._(); @@ -35,19 +47,32 @@ class ImagePickerWeb { }); } - static Future _pickFile(String type) async { - final completer = Completer?>(); - final input = html.FileUploadInputElement()..accept = '$type/*'; + static Future _pickFile(String type) async { + final completer = Completer?>(); + + final input = web.HTMLInputElement() + ..accept = '$type/*' + ..type = 'file'; + // final input = web.FileUploadInputElement()..accept = '$type/*'; bool changeEventTriggered = false; - void changeEventListener(html.Event e) { + void changeEventListener(web.Event e) { if (changeEventTriggered) return; changeEventTriggered = true; - - final files = input.files ?? []; - final resultFuture = files.map>((file) async { - final reader = html.FileReader()..readAsDataUrl(file); - reader.onError.listen(completer.completeError); + final web.FileList? files = input.files; + if (files == null) return completer.complete(null); + + /// 生成迭代器 + final resultFuture = files.toList.map>((file) async { + web.FileReader() + ..readAsDataURL(file) + ..addEventListener( + 'error', + (JSAny event) { + completer.completeError('Error reading file: $event'); + }.toJS, + ); + // reader.onError.listen(completer.completeError); return file; }); @@ -56,8 +81,8 @@ class ImagePickerWeb { // Cancel event management inspired by: // https://github.com/miguelpruivo/flutter_file_picker/blob/master/lib/src/file_picker_web.dart - void cancelledEventListener(html.Event e) { - html.window.removeEventListener('focus', cancelledEventListener); + void cancelledEventListener(web.Event e) { + web.window.removeEventListener('focus', cancelledEventListener.toJS); // This listener is called before the input changed event, // and the `uploadInput.files` value is still null @@ -71,15 +96,15 @@ class ImagePickerWeb { } input.onChange.listen(changeEventListener); - input.addEventListener('change', changeEventListener); + input.addEventListener('change', changeEventListener.toJS); // Listen focus event for cancelled - html.window.addEventListener('focus', cancelledEventListener); + web.window.addEventListener('focus', cancelledEventListener.toJS); input.click(); // Need to append on mobile Safari. - html.document.body?.append(input); + web.document.body?.append(input); final results = await completer.future; if (results == null || results.isEmpty) return null; @@ -89,12 +114,14 @@ class ImagePickerWeb { 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 reader = web.FileReader()..readAsDataURL(file); + // await reader.onLoad.first; + await reader.onLoadEnd.first; final encoded = reader.result; if (encoded is! String) return null; - final stripped = - encoded.replaceFirst(RegExp('data:$type/[^;]+;base64,'), ''); + // final dartEncoded = encoded; + final stripped = (encoded! as String) + .replaceFirst(RegExp('data:$type/[^;]+;base64,'), ''); final fileName = file.name; return { 'name': fileName, @@ -104,21 +131,31 @@ class ImagePickerWeb { } /// source: https://stackoverflow.com/a/59420655/9942346 - static Future?> _pickMultiFiles(String type) async { - final completer = Completer?>(); - final input = html.FileUploadInputElement() - ..multiple = true - ..accept = '$type/*'; + static Future?> _pickMultiFiles(String type) async { + final completer = Completer?>(); + final input = web.HTMLInputElement() + ..accept = '$type/*' + ..type = 'file' + ..multiple = true; var changeEventTriggered = false; - void changeEventListener(html.Event e) { + void changeEventListener(web.Event e) { if (changeEventTriggered) return; changeEventTriggered = true; - final files = input.files ?? []; - final resultsFutures = files.map>((file) async { - final reader = html.FileReader()..readAsDataUrl(file); - reader.onError.listen(completer.completeError); + final web.FileList? files = input.files; + if (files == null) return completer.complete(null); + final resultsFutures = files.toList.map>((file) async { + web.FileReader() + ..readAsDataURL(file) + ..addEventListener( + 'error', + (JSAny event) { + completer.completeError('Error reading file: $event'); + }.toJS, + ); + + // reader.onError.listen(completer.completeError); return file; }); Future.wait(resultsFutures).then(completer.complete); @@ -126,8 +163,8 @@ class ImagePickerWeb { // Cancel event management inspired by: // https://github.com/miguelpruivo/flutter_file_picker/blob/master/lib/src/file_picker_web.dart - void cancelledEventListener(html.Event e) { - html.window.removeEventListener('focus', cancelledEventListener); + void cancelledEventListener(web.Event e) { + web.window.removeEventListener('focus', cancelledEventListener.toJS); // This listener is called before the input changed event, // and the `uploadInput.files` value is still null @@ -141,15 +178,15 @@ class ImagePickerWeb { } input.onChange.listen(changeEventListener); - input.addEventListener('change', changeEventListener); + input.addEventListener('change', changeEventListener.toJS); // Listen focus event for cancelled - html.window.addEventListener('focus', cancelledEventListener); + web.window.addEventListener('focus', cancelledEventListener.toJS); input.click(); // Need to append on mobile Safari. - html.document.body?.append(input); + web.document.body?.append(input); final results = await completer.future; if (results == null || results.isEmpty) return null; return results; @@ -158,7 +195,7 @@ class ImagePickerWeb { /// Picker that close after selecting 1 image and return a [Uint8List] of the /// selected image. static Future getImageAsBytes() async { - final file = await ImagePickerWeb._pickFile('image'); + final web.File? file = await ImagePickerWeb._pickFile('image'); return file?.asBytes(); } @@ -173,7 +210,7 @@ class ImagePickerWeb { /// Picker that close after selecting 1 image and return a [html.File] of the /// selected image. - static Future getImageAsFile() { + static Future getImageAsFile() { return ImagePickerWeb._pickFile('image'); } @@ -213,7 +250,7 @@ class ImagePickerWeb { /// Picker that allows multi-image selection and return a [html.File] list of /// the selected images. - static Future?> getMultiImagesAsFile() { + static Future?> getMultiImagesAsFile() { return _pickMultiFiles('image'); } @@ -226,7 +263,7 @@ class ImagePickerWeb { /// Picker that close after selecting 1 video and return a [html.File] of the /// selected video. - static Future getVideoAsFile() => _pickFile('video'); + static Future getVideoAsFile() => _pickFile('video'); /// Help to retrieve further video's informations about your picked source. /// @@ -249,31 +286,44 @@ class ImagePickerWeb { return files.isEmpty ? null : files; } - /// Picker that allows multi-video selection and return a [html.File] list of + /// Picker that allows multi-video selection and return a [web.File] list of /// the selected videos. - static Future?> getMultiVideosAsFile() { + static Future?> getMultiVideosAsFile() { return _pickMultiFiles('video'); } } -typedef _ByteResult = FutureOr>; +// typedef _ByteResult = FutureOr>; +// typedef _ByteResult = FutureOr; -extension on html.File { +extension on web.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); + final reader = web.FileReader(); + reader + ..addEventListener( + 'load', + (JSAny event) { + final result = reader.result; + if (result is! ByteBuffer) { + bytesFile.completeError('Result is not a byte result'); + return; + } + bytesFile.complete((result! as ByteBuffer).asUint8List()); + }.toJS, + ) + // reader.onLoad.listen( + // (_) { + // final result = reader.result; + // if (result is! _ByteResult?) { + // bytesFile.completeError('Result is not a byte result'); + // return; + // } + + // bytesFile.complete(result); + // }, + // ); + ..readAsArrayBuffer(this); return Uint8List.fromList(await bytesFile.future); } } diff --git a/pubspec.yaml b/pubspec.yaml index a9c0443..e520480 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -13,6 +13,7 @@ dependencies: sdk: flutter flutter_web_plugins: sdk: flutter + web: ^1.0.0 dev_dependencies: custom_lint: ^0.5.0 From facb9a6d45a5a19c9dd10a19f872b3b8d1ddcd8d Mon Sep 17 00:00:00 2001 From: bymoye Date: Sat, 20 Jul 2024 23:29:52 +0800 Subject: [PATCH 2/5] fix: example --- example/.gitignore | 1 - example/pubspec.yaml | 8 ++++++-- lib/image_picker_web.dart | 6 +++--- pubspec.yaml | 4 ++-- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/example/.gitignore b/example/.gitignore index ae1f183..c42f173 100644 --- a/example/.gitignore +++ b/example/.gitignore @@ -31,7 +31,6 @@ /build/ # Web related -lib/generated_plugin_registrant.dart # Exceptions to above rules. !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 8497530..fed0735 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -3,12 +3,16 @@ description: Demonstrates how to use the image_picker_web plugin. publish_to: "none" environment: - sdk: ">=3.0.0 <4.0.0" + sdk: ">=3.3.0 <4.0.0" dependencies: flutter: sdk: flutter - video_player: ^2.7.0 + video_player: ^2.9.1 + web: ^1.0.0 + +dependency_overrides: + video_player_web: ^2.3.1 web: ^1.0.0 dev_dependencies: diff --git a/lib/image_picker_web.dart b/lib/image_picker_web.dart index 272fd02..ce520b6 100644 --- a/lib/image_picker_web.dart +++ b/lib/image_picker_web.dart @@ -3,13 +3,13 @@ library image_picker_web; import 'dart:async'; import 'dart:js_interop'; import 'dart:typed_data'; -// import 'dart:html' as html; -import 'package:web/web.dart' as web; -import 'dart:js_util' as js_util; + 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/models/media_info.dart'; +// import 'dart:html' as html; +import 'package:web/web.dart' as web; export 'src/models/media_info.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index e520480..32927d3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,8 +5,8 @@ version: 4.0.0 repository: https://github.com/Ahmadre/image_picker_web environment: - sdk: ">=3.0.0 <4.0.0" - flutter: ">=1.20.0" + sdk: ">=3.3.0 <4.0.0" + flutter: ">=3.19.0" dependencies: flutter: From 0699b6ed64ed5bedd8db2bd4506665fc3c94be72 Mon Sep 17 00:00:00 2001 From: bymoye Date: Sun, 21 Jul 2024 00:13:39 +0800 Subject: [PATCH 3/5] fix: example --- .../big_video_upload_view.dart | 19 +++++++------- .../multi_video_upload.dart | 26 +++++++++---------- .../photo_history/photo_history_add_view.dart | 1 - example/pubspec.yaml | 4 +-- lib/image_picker_web.dart | 5 ++-- pubspec.yaml | 2 +- 6 files changed, 28 insertions(+), 29 deletions(-) diff --git a/example/lib/big_video_upload/big_video_upload_view.dart b/example/lib/big_video_upload/big_video_upload_view.dart index 5074491..595f091 100644 --- a/example/lib/big_video_upload/big_video_upload_view.dart +++ b/example/lib/big_video_upload/big_video_upload_view.dart @@ -16,21 +16,22 @@ class BigVideoUploadView extends StatefulWidget { class _BigVideoUploadViewState extends State { VideoPlayerController? _controller; - Future _createVideo(Uint8List bytes) async { - final blob = web.Blob(bytes.map((int byte) => byte.toJS).toList().toJS); - final url = web.URL.createObjectURL(blob); + Future _createVideo(web.File file) async { + // final blob = web.Blob(bytes.map((int byte) => byte.toJS).toList().toJS); + final url = web.URL.createObjectURL(file); // final url = html.Url.createObjectUrlFromBlob(blob); _controller = VideoPlayerController.networkUrl(Uri.parse(url)); + await _controller?.initialize(); setState(() {}); } - Future _load(web.File file) async { - final reader = web.FileReader(); - reader.readAsArrayBuffer(file); - await reader.onLoadEnd.first; - reader.onLoadEnd; - return reader.result as Uint8List; + Future _load(web.File file) async { + // final reader = web.FileReader()..readAsArrayBuffer(file); + // await reader.onLoadEnd.first; + // return (reader.result as JSArrayBuffer).toDart.asUint8List(); + // return reader.result as JSArrayBuffer; + return file; } Future _pickAndLoadVideo() async { diff --git a/example/lib/multi_video_upload/multi_video_upload.dart b/example/lib/multi_video_upload/multi_video_upload.dart index 12f7943..bf620b5 100644 --- a/example/lib/multi_video_upload/multi_video_upload.dart +++ b/example/lib/multi_video_upload/multi_video_upload.dart @@ -1,8 +1,4 @@ -// import 'dart:html' as html; -import 'dart:js_interop'; - import 'package:web/web.dart' as web; -import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:image_picker_web/image_picker_web.dart'; @@ -18,10 +14,10 @@ class MultiVideoUploadView extends StatefulWidget { class _MultiVideoUploadViewState extends State { final _controllers = []; - Future _createVideos(List bytesList) async { + Future _createVideos(List bytesList) async { for (final bytes in bytesList) { - final blob = web.Blob(bytes.map((int byte) => byte.toJS).toList().toJS); - final url = web.URL.createObjectURL(blob); + // final blob = web.Blob(bytes.map((int byte) => byte.toJS).toList().toJS); + final url = web.URL.createObjectURL(bytes); final controller = VideoPlayerController.networkUrl(Uri.parse(url)); await controller.initialize(); _controllers.add(controller); @@ -29,13 +25,15 @@ class _MultiVideoUploadViewState extends State { setState(() {}); } - Future _load(web.File file) async { - final reader = web.FileReader(); - reader.readAsArrayBuffer(file); - await reader.onLoadEnd.first; - // await reader.onLoad.first; - reader.onLoadEnd; - return reader.result as Uint8List; + Future _load(web.File file) async { + // final reader = web.FileReader(); + // reader.readAsArrayBuffer(file); + // await reader.onLoadEnd.first; + // // await reader.onLoad.first; + // reader.onLoadEnd; + + // return reader.result as JSArrayBuffer; + return file; } Future _pickAndLoadVideos() async { diff --git a/example/lib/photo_history/photo_history_add_view.dart b/example/lib/photo_history/photo_history_add_view.dart index 508a9d4..3a390fa 100644 --- a/example/lib/photo_history/photo_history_add_view.dart +++ b/example/lib/photo_history/photo_history_add_view.dart @@ -103,7 +103,6 @@ class _ImagePickerWidgetState extends State { }); final image = await ImagePickerWeb.getImageAsWidget(); - print(image); if (image != null) { setState(() { diff --git a/example/pubspec.yaml b/example/pubspec.yaml index fed0735..0f55c13 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -9,11 +9,11 @@ dependencies: flutter: sdk: flutter video_player: ^2.9.1 - web: ^1.0.0 + web: ">=0.5.1" dependency_overrides: video_player_web: ^2.3.1 - web: ^1.0.0 + # web: ^1.0.0 dev_dependencies: flutter_test: diff --git a/lib/image_picker_web.dart b/lib/image_picker_web.dart index ce520b6..5f2ee1e 100644 --- a/lib/image_picker_web.dart +++ b/lib/image_picker_web.dart @@ -298,7 +298,8 @@ class ImagePickerWeb { extension on web.File { Future asBytes() async { - final bytesFile = Completer>(); + // final bytesFile = Completer>(); + final bytesFile = Completer(); final reader = web.FileReader(); reader ..addEventListener( @@ -324,6 +325,6 @@ extension on web.File { // }, // ); ..readAsArrayBuffer(this); - return Uint8List.fromList(await bytesFile.future); + return bytesFile.future; } } diff --git a/pubspec.yaml b/pubspec.yaml index 32927d3..2e1fadb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: sdk: flutter flutter_web_plugins: sdk: flutter - web: ^1.0.0 + web: ">=0.5.1" dev_dependencies: custom_lint: ^0.5.0 From 1e3e96be4a3adf3273836acddde14d17bdc7d4c2 Mon Sep 17 00:00:00 2001 From: bymoye Date: Tue, 6 Aug 2024 22:00:46 +0800 Subject: [PATCH 4/5] chore: remove commented-out code and improve variable naming and comments --- .../big_video_upload_view.dart | 23 +---- example/lib/main.dart | 10 +- .../multi_video_upload.dart | 29 ++---- .../photo_history/photo_history_add_view.dart | 33 ++++--- example/lib/sample/sample_page.dart | 93 +++++++++++-------- example/pubspec.yaml | 1 - lib/image_picker_web.dart | 49 +++------- 7 files changed, 97 insertions(+), 141 deletions(-) diff --git a/example/lib/big_video_upload/big_video_upload_view.dart b/example/lib/big_video_upload/big_video_upload_view.dart index 595f091..6ad9039 100644 --- a/example/lib/big_video_upload/big_video_upload_view.dart +++ b/example/lib/big_video_upload/big_video_upload_view.dart @@ -1,13 +1,10 @@ -import 'dart:js_interop'; -import 'package:web/web.dart' as web; -import 'dart:typed_data'; - import 'package:flutter/material.dart'; import 'package:image_picker_web/image_picker_web.dart'; import 'package:video_player/video_player.dart'; +import 'package:web/web.dart' as web; class BigVideoUploadView extends StatefulWidget { - const BigVideoUploadView({Key? key}) : super(key: key); + const BigVideoUploadView({super.key}); @override State createState() => _BigVideoUploadViewState(); @@ -17,28 +14,17 @@ class _BigVideoUploadViewState extends State { VideoPlayerController? _controller; Future _createVideo(web.File file) async { - // final blob = web.Blob(bytes.map((int byte) => byte.toJS).toList().toJS); final url = web.URL.createObjectURL(file); - // final url = html.Url.createObjectUrlFromBlob(blob); _controller = VideoPlayerController.networkUrl(Uri.parse(url)); await _controller?.initialize(); setState(() {}); } - Future _load(web.File file) async { - // final reader = web.FileReader()..readAsArrayBuffer(file); - // await reader.onLoadEnd.first; - // return (reader.result as JSArrayBuffer).toDart.asUint8List(); - // return reader.result as JSArrayBuffer; - return file; - } - Future _pickAndLoadVideo() async { final file = await ImagePickerWeb.getVideoAsFile(); if (file != null) { - final bytes = await _load(file); - await _createVideo(bytes); + await _createVideo(file); } } @@ -70,7 +56,6 @@ class _BigVideoUploadViewState extends State { body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, children: [ if (controller != null && controller.value.isInitialized) AspectRatio( @@ -79,7 +64,7 @@ class _BigVideoUploadViewState extends State { ), ElevatedButton( onPressed: _pickAndLoadVideo, - child: Text('Load Video with FileReader'), + child: const Text('Load Video with FileReader'), ), ], ), diff --git a/example/lib/main.dart b/example/lib/main.dart index 08bca4d..99361f7 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -10,11 +10,11 @@ class HomePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: Text('Home')), + appBar: AppBar(title: const Text('Home')), body: Center( child: SeparatedColumn( mainAxisAlignment: MainAxisAlignment.center, - separator: SizedBox(height: 8), + separator: const SizedBox(height: 8), children: [ _Button( label: 'Sample 1', @@ -24,11 +24,11 @@ class HomePage extends StatelessWidget { label: 'Photo History', page: PhotosHistoryAddPage(), ), - _Button( + const _Button( label: 'Big Video Upload', page: BigVideoUploadView(), ), - _Button( + const _Button( page: MultiVideoUploadView(), label: 'Upload Multi Videos', ), @@ -53,7 +53,7 @@ class _Button extends StatelessWidget { return ElevatedButton( onPressed: () => Navigator.push( context, - MaterialPageRoute(builder: (_) => page), + MaterialPageRoute(builder: (_) => page), ), child: Text(label), ); diff --git a/example/lib/multi_video_upload/multi_video_upload.dart b/example/lib/multi_video_upload/multi_video_upload.dart index bf620b5..03b5d6e 100644 --- a/example/lib/multi_video_upload/multi_video_upload.dart +++ b/example/lib/multi_video_upload/multi_video_upload.dart @@ -1,8 +1,7 @@ -import 'package:web/web.dart' as web; - import 'package:flutter/material.dart'; import 'package:image_picker_web/image_picker_web.dart'; import 'package:video_player/video_player.dart'; +import 'package:web/web.dart' as web; class MultiVideoUploadView extends StatefulWidget { const MultiVideoUploadView({super.key}); @@ -14,34 +13,22 @@ class MultiVideoUploadView extends StatefulWidget { class _MultiVideoUploadViewState extends State { final _controllers = []; - Future _createVideos(List bytesList) async { - for (final bytes in bytesList) { - // final blob = web.Blob(bytes.map((int byte) => byte.toJS).toList().toJS); - final url = web.URL.createObjectURL(bytes); - final controller = VideoPlayerController.networkUrl(Uri.parse(url)); + Future _createVideos(List files) async { + for (final file in files) { + final String url = web.URL.createObjectURL(file); + final VideoPlayerController controller = + VideoPlayerController.networkUrl(Uri.parse(url)); await controller.initialize(); _controllers.add(controller); } setState(() {}); } - Future _load(web.File file) async { - // final reader = web.FileReader(); - // reader.readAsArrayBuffer(file); - // await reader.onLoadEnd.first; - // // await reader.onLoad.first; - // reader.onLoadEnd; - - // return reader.result as JSArrayBuffer; - return file; - } - Future _pickAndLoadVideos() async { setState(_disposeControllers); final files = await ImagePickerWeb.getMultiVideosAsFile(); if (files != null) { - final bytesList = await Future.wait(files.map(_load)); - await _createVideos(bytesList); + await _createVideos(files); } } @@ -65,7 +52,7 @@ class _MultiVideoUploadViewState extends State { ), ElevatedButton( onPressed: _pickAndLoadVideos, - child: Text('Pick videos'), + child: const Text('Pick videos'), ), ], ), diff --git a/example/lib/photo_history/photo_history_add_view.dart b/example/lib/photo_history/photo_history_add_view.dart index 3a390fa..ed9e0fa 100644 --- a/example/lib/photo_history/photo_history_add_view.dart +++ b/example/lib/photo_history/photo_history_add_view.dart @@ -13,7 +13,7 @@ enum PageStatus { loading, error, loaded } class ImagePickerWidget extends StatefulWidget { @override - _ImagePickerWidgetState createState() => _ImagePickerWidgetState(); + State createState() => _ImagePickerWidgetState(); } class _ImagePickerWidgetState extends State { @@ -23,10 +23,9 @@ class _ImagePickerWidgetState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: Text('Photo History')), + appBar: AppBar(title: const Text('Photo History')), body: Column( crossAxisAlignment: CrossAxisAlignment.stretch, - mainAxisAlignment: MainAxisAlignment.start, children: [ Container( height: 100, @@ -37,16 +36,17 @@ class _ImagePickerWidgetState extends State { if (index == 0) { return _buildAddPhoto(); } - var image = _photos[index - 1]; + final image = _photos[index - 1]; return Stack( children: [ InkWell( child: Container( - margin: EdgeInsets.all(5), - height: 100, - width: 100, - color: kLightGray, - child: image), + margin: const EdgeInsets.all(5), + height: 100, + width: 100, + color: kLightGray, + child: image, + ), ), ], ); @@ -55,12 +55,12 @@ class _ImagePickerWidgetState extends State { ), if (_pageStatus == PageStatus.loaded) Container( - margin: EdgeInsets.all(16), + margin: const EdgeInsets.all(16), child: ElevatedButton( onPressed: () {}, - child: Text('Save'), + child: const Text('Save'), ), - ) + ), ], ), ); @@ -69,24 +69,23 @@ class _ImagePickerWidgetState extends State { InkWell _buildAddPhoto() { if (_pageStatus == PageStatus.loading) { return InkWell( - onTap: () => null, child: Container( - margin: EdgeInsets.all(5), + margin: const EdgeInsets.all(5), height: 100, width: 100, color: kDarkGray, - child: Center(child: Text('Please wait..')), + child: const Center(child: Text('Please wait..')), ), ); } else { return InkWell( onTap: () => _onAddPhotoClicked(context), child: Container( - margin: EdgeInsets.all(5), + margin: const EdgeInsets.all(5), height: 100, width: 100, color: kDarkGray, - child: Center( + child: const Center( child: Icon( Icons.add_to_photos, color: kLightGray, diff --git a/example/lib/sample/sample_page.dart b/example/lib/sample/sample_page.dart index a7b7cce..839c7a0 100644 --- a/example/lib/sample/sample_page.dart +++ b/example/lib/sample/sample_page.dart @@ -1,3 +1,5 @@ +import 'dart:typed_data'; + import 'package:flutter/material.dart'; import 'package:image_picker_web/image_picker_web.dart'; @@ -16,18 +18,20 @@ class _SamplePageState extends State { final fromPicker = await ImagePickerWeb.getImageAsWidget(); if (fromPicker != null) { setState(() { - _pickedImages.clear(); - _pickedImages.add(fromPicker); + _pickedImages + ..clear() + ..add(fromPicker); }); } } Future _pickVideo() async { - final videoMetaData = await ImagePickerWeb.getVideoAsBytes(); + final Uint8List? videoMetaData = await ImagePickerWeb.getVideoAsBytes(); if (videoMetaData != null) { setState(() { - _pickedVideos.clear(); - _pickedVideos.add(videoMetaData); + _pickedVideos + ..clear() + ..add(videoMetaData); }); } } @@ -42,8 +46,10 @@ class _SamplePageState extends State { Future _getImgFile() async { final infos = await ImagePickerWeb.getImageAsFile(); - setState(() => _imageInfo = - 'Name: ${infos?.name}\nRelative Path: ${infos?.webkitRelativePath}'); + setState( + () => _imageInfo = + 'Name: ${infos?.name}\nRelative Path: ${infos?.webkitRelativePath}', + ); } Future _getImgInfo() async { @@ -51,8 +57,9 @@ class _SamplePageState extends State { final data = infos?.data; if (data != null) { setState(() { - _pickedImages.clear(); - _pickedImages.add(Image.memory(data, semanticLabel: infos?.fileName)); + _pickedImages + ..clear() + ..add(Image.memory(data, semanticLabel: infos?.fileName)); _imageInfo = '${infos?.toJson()}'; }); } @@ -66,39 +73,41 @@ class _SamplePageState extends State { ), body: Center( child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - Wrap( - // spacing: 15.0, - children: [ - AnimatedSwitcher( - duration: const Duration(milliseconds: 300), - switchInCurve: Curves.easeIn, - child: SizedBox( - width: 500, - height: 200, - child: ListView.builder( - scrollDirection: Axis.horizontal, - itemCount: _pickedImages.length, - itemBuilder: (_, index) => _pickedImages[index]), + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Wrap( + // spacing: 15.0, + children: [ + AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + switchInCurve: Curves.easeIn, + child: SizedBox( + width: 500, + height: 200, + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: _pickedImages.length, + itemBuilder: (_, index) => _pickedImages[index], ), ), - Container( - height: 200, - width: 200, - child: Text(_imageInfo, overflow: TextOverflow.ellipsis), + ), + Container( + height: 200, + width: 200, + child: Text(_imageInfo, overflow: TextOverflow.ellipsis), + ), + ..._pickedVideos.map( + (e) => Text( + e.toString(), + overflow: TextOverflow.ellipsis, ), - ..._pickedVideos - .map((e) => Text( - e.toString(), - overflow: TextOverflow.ellipsis, - )) - .toList(), - ], - ), - ButtonBar(alignment: MainAxisAlignment.center, children: [ + ), + ], + ), + OverflowBar( + alignment: MainAxisAlignment.center, + children: [ ElevatedButton( onPressed: _pickImage, child: const Text('Select Image'), @@ -119,8 +128,10 @@ class _SamplePageState extends State { onPressed: _getImgInfo, child: const Text('Get Image Info'), ), - ]), - ]), + ], + ), + ], + ), ), ); } diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 0f55c13..7a9c940 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -13,7 +13,6 @@ dependencies: dependency_overrides: video_player_web: ^2.3.1 - # web: ^1.0.0 dev_dependencies: flutter_test: diff --git a/lib/image_picker_web.dart b/lib/image_picker_web.dart index 5f2ee1e..5335ad7 100644 --- a/lib/image_picker_web.dart +++ b/lib/image_picker_web.dart @@ -18,8 +18,7 @@ extension WebFileListToDartList on web.FileList { /// Converts a [web.FileList] into a [List] of [web.File]. /// /// This method makes a copy. - List get toList => - [for (int i = 0; i < length; i++) item(i)!]; + List toList() => [for (int i = 0; i < length; i++) item(i)!]; } class ImagePickerWeb { @@ -53,7 +52,6 @@ class ImagePickerWeb { final input = web.HTMLInputElement() ..accept = '$type/*' ..type = 'file'; - // final input = web.FileUploadInputElement()..accept = '$type/*'; bool changeEventTriggered = false; void changeEventListener(web.Event e) { @@ -62,8 +60,7 @@ class ImagePickerWeb { final web.FileList? files = input.files; if (files == null) return completer.complete(null); - /// 生成迭代器 - final resultFuture = files.toList.map>((file) async { + final resultFuture = files.toList().map>((file) async { web.FileReader() ..readAsDataURL(file) ..addEventListener( @@ -72,7 +69,6 @@ class ImagePickerWeb { completer.completeError('Error reading file: $event'); }.toJS, ); - // reader.onError.listen(completer.completeError); return file; }); @@ -115,11 +111,9 @@ class ImagePickerWeb { final file = await ImagePickerWeb._pickFile(type); if (file == null) return null; final reader = web.FileReader()..readAsDataURL(file); - // await reader.onLoad.first; await reader.onLoadEnd.first; final encoded = reader.result; if (encoded is! String) return null; - // final dartEncoded = encoded; final stripped = (encoded! as String) .replaceFirst(RegExp('data:$type/[^;]+;base64,'), ''); final fileName = file.name; @@ -145,7 +139,7 @@ class ImagePickerWeb { final web.FileList? files = input.files; if (files == null) return completer.complete(null); - final resultsFutures = files.toList.map>((file) async { + final resultsFutures = files.toList().map>((file) async { web.FileReader() ..readAsDataURL(file) ..addEventListener( @@ -154,8 +148,6 @@ class ImagePickerWeb { completer.completeError('Error reading file: $event'); }.toJS, ); - - // reader.onError.listen(completer.completeError); return file; }); Future.wait(resultsFutures).then(completer.complete); @@ -208,7 +200,7 @@ class ImagePickerWeb { : null; } - /// Picker that close after selecting 1 image and return a [html.File] of the + /// Picker that close after selecting 1 image and return a [web.File] of the /// selected image. static Future getImageAsFile() { return ImagePickerWeb._pickFile('image'); @@ -228,10 +220,9 @@ class ImagePickerWeb { static Future?> getMultiImagesAsBytes() async { final images = await _pickMultiFiles('image'); if (images == null) return null; - final files = []; - for (final img in images) { - files.add(await img.asBytes()); - } + final files = [ + for (final img in images) await img.asBytes(), + ]; return files.isEmpty ? null : files; } @@ -240,15 +231,14 @@ class ImagePickerWeb { static Future?> getMultiImagesAsWidget() async { final images = await _pickMultiFiles('image'); if (images == null) return null; - final files = []; - for (final img in images) { - files.add(await img.asBytes()); - } + final files = [ + for (final img in images) await img.asBytes(), + ]; if (files.isEmpty) return null; return files.map(Image.memory).toList(); } - /// Picker that allows multi-image selection and return a [html.File] list of + /// Picker that allows multi-image selection and return a [web.File] list of /// the selected images. static Future?> getMultiImagesAsFile() { return _pickMultiFiles('image'); @@ -261,7 +251,7 @@ class ImagePickerWeb { return video?.asBytes(); } - /// Picker that close after selecting 1 video and return a [html.File] of the + /// Picker that close after selecting 1 video and return a [web.File] of the /// selected video. static Future getVideoAsFile() => _pickFile('video'); @@ -293,12 +283,8 @@ class ImagePickerWeb { } } -// typedef _ByteResult = FutureOr>; -// typedef _ByteResult = FutureOr; - extension on web.File { Future asBytes() async { - // final bytesFile = Completer>(); final bytesFile = Completer(); final reader = web.FileReader(); reader @@ -313,17 +299,6 @@ extension on web.File { bytesFile.complete((result! as ByteBuffer).asUint8List()); }.toJS, ) - // reader.onLoad.listen( - // (_) { - // final result = reader.result; - // if (result is! _ByteResult?) { - // bytesFile.completeError('Result is not a byte result'); - // return; - // } - - // bytesFile.complete(result); - // }, - // ); ..readAsArrayBuffer(this); return bytesFile.future; } From 648587c5829d98ccef8884b0e95c819467736bf2 Mon Sep 17 00:00:00 2001 From: bymoye Date: Tue, 6 Aug 2024 22:08:13 +0800 Subject: [PATCH 5/5] delete a commented code --- lib/image_picker_web.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/image_picker_web.dart b/lib/image_picker_web.dart index 5335ad7..036a192 100644 --- a/lib/image_picker_web.dart +++ b/lib/image_picker_web.dart @@ -8,7 +8,6 @@ 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/models/media_info.dart'; -// import 'dart:html' as html; import 'package:web/web.dart' as web; export 'src/models/media_info.dart';