From 1c971fb0b23cc371418e22385c21d201bc6b7bf8 Mon Sep 17 00:00:00 2001 From: wuxinglong Date: Tue, 12 May 2026 11:35:21 +0800 Subject: [PATCH 1/4] =?UTF-8?q?fix:=E4=BC=98=E5=8C=96=E5=9B=BE=E7=89=87?= =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E7=BB=84=E4=BB=B6=EF=BC=8C=E8=A7=A3=E5=86=B3?= =?UTF-8?q?png=E5=9B=BE=E7=89=87=E6=8A=A5=E9=94=99=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .dart_tool/package_config.json | 380 +++++++++++------------ .flutter-plugins-dependencies | 2 +- .idea/flutter_common.iml | 6 + .idea/libraries/Dart_Packages.xml | 16 +- .idea/libraries/Flutter_Plugins.xml | 106 +++---- lib/upload_image/ossUtil.dart | 25 +- lib/upload_image/upload_images_tool.dart | 160 ++++++++-- 7 files changed, 417 insertions(+), 278 deletions(-) diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json index 7e6d617..7b526f3 100644 --- a/.dart_tool/package_config.json +++ b/.dart_tool/package_config.json @@ -3,1129 +3,1129 @@ "packages": [ { "name": "archive", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/archive-4.0.9", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/archive-4.0.9", "packageUri": "lib/", "languageVersion": "3.0" }, { "name": "args", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/args-2.7.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/args-2.7.0", "packageUri": "lib/", "languageVersion": "3.3" }, { "name": "async", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/async-2.13.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/async-2.13.1", "packageUri": "lib/", "languageVersion": "3.4" }, { "name": "boolean_selector", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/boolean_selector-2.1.2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/boolean_selector-2.1.2", "packageUri": "lib/", "languageVersion": "3.1" }, { "name": "cached_network_image", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/cached_network_image-3.4.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/cached_network_image-3.4.1", "packageUri": "lib/", "languageVersion": "3.0" }, { "name": "cached_network_image_platform_interface", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/cached_network_image_platform_interface-4.1.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/cached_network_image_platform_interface-4.1.1", "packageUri": "lib/", "languageVersion": "3.0" }, { "name": "cached_network_image_web", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/cached_network_image_web-1.3.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/cached_network_image_web-1.3.1", "packageUri": "lib/", "languageVersion": "3.0" }, { "name": "characters", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/characters-1.4.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/characters-1.4.0", "packageUri": "lib/", "languageVersion": "3.4" }, { "name": "clock", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/clock-1.1.2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/clock-1.1.2", "packageUri": "lib/", "languageVersion": "3.4" }, { "name": "code_assets", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/code_assets-1.0.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/code_assets-1.0.0", "packageUri": "lib/", "languageVersion": "3.9" }, { "name": "collection", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/collection-1.19.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/collection-1.19.1", "packageUri": "lib/", "languageVersion": "3.4" }, { "name": "colorfilter_generator", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/colorfilter_generator-0.0.8", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/colorfilter_generator-0.0.8", "packageUri": "lib/", "languageVersion": "2.15" }, { "name": "common_utils", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/common_utils-2.1.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/common_utils-2.1.0", "packageUri": "lib/", "languageVersion": "2.12" }, { "name": "convert", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/convert-3.1.2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/convert-3.1.2", "packageUri": "lib/", "languageVersion": "3.4" }, { "name": "cross_file", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/cross_file-0.3.5+2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/cross_file-0.3.5+2", "packageUri": "lib/", "languageVersion": "3.8" }, { "name": "crypto", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/crypto-3.0.7", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/crypto-3.0.7", "packageUri": "lib/", "languageVersion": "3.4" }, { "name": "csslib", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/csslib-1.0.2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/csslib-1.0.2", "packageUri": "lib/", "languageVersion": "3.1" }, { "name": "dbus", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/dbus-0.7.12", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/dbus-0.7.12", "packageUri": "lib/", "languageVersion": "2.17" }, { "name": "decimal", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/decimal-3.2.4", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/decimal-3.2.4", "packageUri": "lib/", "languageVersion": "3.3" }, { "name": "device_info_plus", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/device_info_plus-11.5.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/device_info_plus-11.5.0", "packageUri": "lib/", "languageVersion": "3.7" }, { "name": "device_info_plus_platform_interface", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/device_info_plus_platform_interface-7.0.3", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/device_info_plus_platform_interface-7.0.3", "packageUri": "lib/", "languageVersion": "3.7" }, { "name": "dio", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/dio-5.9.2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/dio-5.9.2", "packageUri": "lib/", "languageVersion": "2.18" }, { "name": "dio_web_adapter", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/dio_web_adapter-2.1.2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/dio_web_adapter-2.1.2", "packageUri": "lib/", "languageVersion": "3.3" }, { "name": "easy_debounce", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/easy_debounce-2.0.3", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/easy_debounce-2.0.3", "packageUri": "lib/", "languageVersion": "2.12" }, { "name": "extended_image", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/extended_image-8.3.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/extended_image-8.3.1", "packageUri": "lib/", "languageVersion": "2.18" }, { "name": "extended_image_library", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/extended_image_library-4.0.6", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/extended_image_library-4.0.6", "packageUri": "lib/", "languageVersion": "3.2" }, { "name": "fake_async", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/fake_async-1.3.3", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/fake_async-1.3.3", "packageUri": "lib/", "languageVersion": "3.3" }, { "name": "ffi", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/ffi-2.2.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/ffi-2.2.0", "packageUri": "lib/", "languageVersion": "3.7" }, { "name": "file", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/file-7.0.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/file-7.0.1", "packageUri": "lib/", "languageVersion": "3.0" }, { "name": "file_selector_linux", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/file_selector_linux-0.9.4", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/file_selector_linux-0.9.4", "packageUri": "lib/", "languageVersion": "3.8" }, { "name": "file_selector_macos", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/file_selector_macos-0.9.5", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/file_selector_macos-0.9.5", "packageUri": "lib/", "languageVersion": "3.9" }, { "name": "file_selector_platform_interface", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/file_selector_platform_interface-2.7.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/file_selector_platform_interface-2.7.0", "packageUri": "lib/", "languageVersion": "3.7" }, { "name": "file_selector_windows", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/file_selector_windows-0.9.3+5", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/file_selector_windows-0.9.3+5", "packageUri": "lib/", "languageVersion": "3.8" }, { "name": "fixnum", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/fixnum-1.1.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/fixnum-1.1.1", "packageUri": "lib/", "languageVersion": "3.1" }, { "name": "flex_color_picker", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flex_color_picker-3.8.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flex_color_picker-3.8.0", "packageUri": "lib/", "languageVersion": "3.6" }, { "name": "flex_seed_scheme", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flex_seed_scheme-4.0.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flex_seed_scheme-4.0.1", "packageUri": "lib/", "languageVersion": "3.6" }, { "name": "flustars_flutter3", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flustars_flutter3-3.0.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flustars_flutter3-3.0.0", "packageUri": "lib/", "languageVersion": "2.12" }, { "name": "flutter", - "rootUri": "file:///Users/threeone/flutter/packages/flutter", + "rootUri": "file:///Users/wxl/Desktop/flutter/packages/flutter", "packageUri": "lib/", "languageVersion": "3.8" }, { "name": "flutter_cache_manager", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flutter_cache_manager-3.4.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flutter_cache_manager-3.4.1", "packageUri": "lib/", "languageVersion": "3.0" }, { "name": "flutter_easyloading", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flutter_easyloading-3.0.5", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flutter_easyloading-3.0.5", "packageUri": "lib/", "languageVersion": "2.12" }, { "name": "flutter_image_compress", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flutter_image_compress-2.4.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flutter_image_compress-2.4.0", "packageUri": "lib/", "languageVersion": "2.12" }, { "name": "flutter_image_compress_common", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flutter_image_compress_common-1.0.6", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flutter_image_compress_common-1.0.6", "packageUri": "lib/", "languageVersion": "2.12" }, { "name": "flutter_image_compress_macos", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flutter_image_compress_macos-1.0.3", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flutter_image_compress_macos-1.0.3", "packageUri": "lib/", "languageVersion": "2.12" }, { "name": "flutter_image_compress_ohos", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flutter_image_compress_ohos-0.0.3", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flutter_image_compress_ohos-0.0.3", "packageUri": "lib/", "languageVersion": "2.12" }, { "name": "flutter_image_compress_platform_interface", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flutter_image_compress_platform_interface-1.0.5", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flutter_image_compress_platform_interface-1.0.5", "packageUri": "lib/", "languageVersion": "2.12" }, { "name": "flutter_image_compress_web", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flutter_image_compress_web-0.1.5", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flutter_image_compress_web-0.1.5", "packageUri": "lib/", "languageVersion": "2.12" }, { "name": "flutter_inappwebview", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flutter_inappwebview-6.1.5", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flutter_inappwebview-6.1.5", "packageUri": "lib/", "languageVersion": "3.5" }, { "name": "flutter_inappwebview_android", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flutter_inappwebview_android-1.1.3", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flutter_inappwebview_android-1.1.3", "packageUri": "lib/", "languageVersion": "3.5" }, { "name": "flutter_inappwebview_internal_annotations", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flutter_inappwebview_internal_annotations-1.3.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flutter_inappwebview_internal_annotations-1.3.0", "packageUri": "lib/", "languageVersion": "3.7" }, { "name": "flutter_inappwebview_ios", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flutter_inappwebview_ios-1.1.2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flutter_inappwebview_ios-1.1.2", "packageUri": "lib/", "languageVersion": "3.5" }, { "name": "flutter_inappwebview_macos", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flutter_inappwebview_macos-1.1.2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flutter_inappwebview_macos-1.1.2", "packageUri": "lib/", "languageVersion": "3.5" }, { "name": "flutter_inappwebview_platform_interface", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flutter_inappwebview_platform_interface-1.3.0+1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flutter_inappwebview_platform_interface-1.3.0+1", "packageUri": "lib/", "languageVersion": "3.5" }, { "name": "flutter_inappwebview_web", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flutter_inappwebview_web-1.1.2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flutter_inappwebview_web-1.1.2", "packageUri": "lib/", "languageVersion": "3.5" }, { "name": "flutter_inappwebview_windows", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flutter_inappwebview_windows-0.6.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flutter_inappwebview_windows-0.6.0", "packageUri": "lib/", "languageVersion": "3.5" }, { "name": "flutter_lints", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flutter_lints-5.0.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flutter_lints-5.0.0", "packageUri": "lib/", "languageVersion": "3.5" }, { "name": "flutter_plugin_android_lifecycle", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flutter_plugin_android_lifecycle-2.0.34", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flutter_plugin_android_lifecycle-2.0.34", "packageUri": "lib/", "languageVersion": "3.9" }, { "name": "flutter_screenutil", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flutter_screenutil-5.9.3", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flutter_screenutil-5.9.3", "packageUri": "lib/", "languageVersion": "2.17" }, { "name": "flutter_spinkit", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flutter_spinkit-5.2.2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flutter_spinkit-5.2.2", "packageUri": "lib/", "languageVersion": "2.12" }, { "name": "flutter_staggered_grid_view", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flutter_staggered_grid_view-0.7.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flutter_staggered_grid_view-0.7.0", "packageUri": "lib/", "languageVersion": "2.12" }, { "name": "flutter_test", - "rootUri": "file:///Users/threeone/flutter/packages/flutter_test", + "rootUri": "file:///Users/wxl/Desktop/flutter/packages/flutter_test", "packageUri": "lib/", "languageVersion": "3.8" }, { "name": "flutter_web_plugins", - "rootUri": "file:///Users/threeone/flutter/packages/flutter_web_plugins", + "rootUri": "file:///Users/wxl/Desktop/flutter/packages/flutter_web_plugins", "packageUri": "lib/", "languageVersion": "3.8" }, { "name": "flutter_widget_from_html_core", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flutter_widget_from_html_core-0.16.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flutter_widget_from_html_core-0.16.1", "packageUri": "lib/", "languageVersion": "3.4" }, { "name": "font_awesome_flutter", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/font_awesome_flutter-10.12.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/font_awesome_flutter-10.12.0", "packageUri": "lib/", "languageVersion": "3.9" }, { "name": "get", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/get-4.7.3", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/get-4.7.3", "packageUri": "lib/", "languageVersion": "2.15" }, { "name": "glob", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/glob-2.1.3", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/glob-2.1.3", "packageUri": "lib/", "languageVersion": "3.3" }, { "name": "hand_signature", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/hand_signature-3.1.0+2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/hand_signature-3.1.0+2", "packageUri": "lib/", "languageVersion": "3.0" }, { "name": "hooks", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/hooks-1.0.2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/hooks-1.0.2", "packageUri": "lib/", "languageVersion": "3.10" }, { "name": "html", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/html-0.15.6", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/html-0.15.6", "packageUri": "lib/", "languageVersion": "3.2" }, { "name": "http", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/http-1.6.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/http-1.6.0", "packageUri": "lib/", "languageVersion": "3.4" }, { "name": "http_client_helper", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/http_client_helper-3.0.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/http_client_helper-3.0.0", "packageUri": "lib/", "languageVersion": "2.12" }, { "name": "http_parser", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/http_parser-4.1.2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/http_parser-4.1.2", "packageUri": "lib/", "languageVersion": "3.4" }, { "name": "image", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/image-4.8.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/image-4.8.0", "packageUri": "lib/", "languageVersion": "3.0" }, { "name": "image_editor_plus", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/image_editor_plus-1.0.6", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/image_editor_plus-1.0.6", "packageUri": "lib/", "languageVersion": "2.17" }, { "name": "image_gallery_saver_plus", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/image_gallery_saver_plus-4.0.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/image_gallery_saver_plus-4.0.1", "packageUri": "lib/", "languageVersion": "3.5" }, { "name": "image_picker", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/image_picker-1.2.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/image_picker-1.2.1", "packageUri": "lib/", "languageVersion": "3.7" }, { "name": "image_picker_android", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/image_picker_android-0.8.13+16", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/image_picker_android-0.8.13+16", "packageUri": "lib/", "languageVersion": "3.9" }, { "name": "image_picker_for_web", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/image_picker_for_web-3.1.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/image_picker_for_web-3.1.1", "packageUri": "lib/", "languageVersion": "3.8" }, { "name": "image_picker_ios", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/image_picker_ios-0.8.13+6", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/image_picker_ios-0.8.13+6", "packageUri": "lib/", "languageVersion": "3.10" }, { "name": "image_picker_linux", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/image_picker_linux-0.2.2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/image_picker_linux-0.2.2", "packageUri": "lib/", "languageVersion": "3.6" }, { "name": "image_picker_macos", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/image_picker_macos-0.2.2+1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/image_picker_macos-0.2.2+1", "packageUri": "lib/", "languageVersion": "3.9" }, { "name": "image_picker_platform_interface", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/image_picker_platform_interface-2.11.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/image_picker_platform_interface-2.11.1", "packageUri": "lib/", "languageVersion": "3.7" }, { "name": "image_picker_windows", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/image_picker_windows-0.2.2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/image_picker_windows-0.2.2", "packageUri": "lib/", "languageVersion": "3.6" }, { "name": "intl", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/intl-0.20.2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/intl-0.20.2", "packageUri": "lib/", "languageVersion": "3.3" }, { "name": "jni", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/jni-1.0.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/jni-1.0.0", "packageUri": "lib/", "languageVersion": "3.3" }, { "name": "jni_flutter", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/jni_flutter-1.0.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/jni_flutter-1.0.1", "packageUri": "lib/", "languageVersion": "3.3" }, { "name": "js", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/js-0.7.2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/js-0.7.2", "packageUri": "lib/", "languageVersion": "3.7" }, { "name": "leak_tracker", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/leak_tracker-11.0.2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/leak_tracker-11.0.2", "packageUri": "lib/", "languageVersion": "3.2" }, { "name": "leak_tracker_flutter_testing", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/leak_tracker_flutter_testing-3.0.10", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/leak_tracker_flutter_testing-3.0.10", "packageUri": "lib/", "languageVersion": "3.2" }, { "name": "leak_tracker_testing", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/leak_tracker_testing-3.0.2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/leak_tracker_testing-3.0.2", "packageUri": "lib/", "languageVersion": "3.2" }, { "name": "lints", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/lints-5.1.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/lints-5.1.1", "packageUri": "lib/", "languageVersion": "3.6" }, { "name": "logging", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/logging-1.3.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/logging-1.3.0", "packageUri": "lib/", "languageVersion": "3.4" }, { "name": "matcher", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/matcher-0.12.17", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/matcher-0.12.17", "packageUri": "lib/", "languageVersion": "3.4" }, { "name": "material_color_utilities", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/material_color_utilities-0.11.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/material_color_utilities-0.11.1", "packageUri": "lib/", "languageVersion": "2.17" }, { "name": "matrix2d", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/matrix2d-1.0.4", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/matrix2d-1.0.4", "packageUri": "lib/", "languageVersion": "2.12" }, { "name": "meta", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/meta-1.17.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/meta-1.17.0", "packageUri": "lib/", "languageVersion": "3.5" }, { "name": "mime", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/mime-2.0.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/mime-2.0.0", "packageUri": "lib/", "languageVersion": "3.2" }, { "name": "native_toolchain_c", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/native_toolchain_c-0.17.6", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/native_toolchain_c-0.17.6", "packageUri": "lib/", "languageVersion": "3.10" }, { "name": "nested", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/nested-1.0.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/nested-1.0.0", "packageUri": "lib/", "languageVersion": "2.12" }, { "name": "objective_c", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/objective_c-9.3.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/objective_c-9.3.0", "packageUri": "lib/", "languageVersion": "3.10" }, { "name": "octo_image", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/octo_image-2.1.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/octo_image-2.1.0", "packageUri": "lib/", "languageVersion": "3.0" }, { "name": "package_config", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/package_config-2.2.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/package_config-2.2.0", "packageUri": "lib/", "languageVersion": "3.4" }, { "name": "package_info_plus", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/package_info_plus-9.0.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/package_info_plus-9.0.1", "packageUri": "lib/", "languageVersion": "3.3" }, { "name": "package_info_plus_platform_interface", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/package_info_plus_platform_interface-3.2.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/package_info_plus_platform_interface-3.2.1", "packageUri": "lib/", "languageVersion": "2.18" }, { "name": "path", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/path-1.9.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/path-1.9.1", "packageUri": "lib/", "languageVersion": "3.4" }, { "name": "path_provider", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/path_provider-2.1.5", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/path_provider-2.1.5", "packageUri": "lib/", "languageVersion": "3.4" }, { "name": "path_provider_android", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/path_provider_android-2.3.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/path_provider_android-2.3.1", "packageUri": "lib/", "languageVersion": "3.9" }, { "name": "path_provider_foundation", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/path_provider_foundation-2.6.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/path_provider_foundation-2.6.0", "packageUri": "lib/", "languageVersion": "3.10" }, { "name": "path_provider_linux", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/path_provider_linux-2.2.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/path_provider_linux-2.2.1", "packageUri": "lib/", "languageVersion": "2.19" }, { "name": "path_provider_platform_interface", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/path_provider_platform_interface-2.1.2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/path_provider_platform_interface-2.1.2", "packageUri": "lib/", "languageVersion": "3.0" }, { "name": "path_provider_windows", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/path_provider_windows-2.3.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/path_provider_windows-2.3.0", "packageUri": "lib/", "languageVersion": "3.2" }, { "name": "permission_handler", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/permission_handler-11.4.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/permission_handler-11.4.0", "packageUri": "lib/", "languageVersion": "3.5" }, { "name": "permission_handler_android", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/permission_handler_android-12.1.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/permission_handler_android-12.1.0", "packageUri": "lib/", "languageVersion": "3.5" }, { "name": "permission_handler_apple", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/permission_handler_apple-9.4.7", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/permission_handler_apple-9.4.7", "packageUri": "lib/", "languageVersion": "2.18" }, { "name": "permission_handler_html", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/permission_handler_html-0.1.3+5", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/permission_handler_html-0.1.3+5", "packageUri": "lib/", "languageVersion": "3.3" }, { "name": "permission_handler_platform_interface", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/permission_handler_platform_interface-4.3.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/permission_handler_platform_interface-4.3.0", "packageUri": "lib/", "languageVersion": "3.5" }, { "name": "permission_handler_windows", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/permission_handler_windows-0.2.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/permission_handler_windows-0.2.1", "packageUri": "lib/", "languageVersion": "2.12" }, { "name": "petitparser", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/petitparser-7.0.2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/petitparser-7.0.2", "packageUri": "lib/", "languageVersion": "3.8" }, { "name": "photo_manager", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/photo_manager-3.9.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/photo_manager-3.9.0", "packageUri": "lib/", "languageVersion": "2.13" }, { "name": "photo_manager_image_provider", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/photo_manager_image_provider-2.2.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/photo_manager_image_provider-2.2.0", "packageUri": "lib/", "languageVersion": "2.13" }, { "name": "photo_view", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/photo_view-0.15.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/photo_view-0.15.0", "packageUri": "lib/", "languageVersion": "2.12" }, { "name": "platform", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/platform-3.1.6", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/platform-3.1.6", "packageUri": "lib/", "languageVersion": "3.2" }, { "name": "plugin_platform_interface", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/plugin_platform_interface-2.1.8", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/plugin_platform_interface-2.1.8", "packageUri": "lib/", "languageVersion": "3.0" }, { "name": "posix", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/posix-6.5.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/posix-6.5.0", "packageUri": "lib/", "languageVersion": "3.0" }, { "name": "provider", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/provider-6.1.5+1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/provider-6.1.5+1", "packageUri": "lib/", "languageVersion": "2.12" }, { "name": "pub_semver", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/pub_semver-2.2.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/pub_semver-2.2.0", "packageUri": "lib/", "languageVersion": "3.4" }, { "name": "pull_to_refresh", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/pull_to_refresh-2.0.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/pull_to_refresh-2.0.0", "packageUri": "lib/", "languageVersion": "2.12" }, { "name": "rational", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/rational-2.2.3", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/rational-2.2.3", "packageUri": "lib/", "languageVersion": "2.14" }, { "name": "reorderables", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/reorderables-0.6.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/reorderables-0.6.0", "packageUri": "lib/", "languageVersion": "2.12" }, { "name": "rxdart", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/rxdart-0.28.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/rxdart-0.28.0", "packageUri": "lib/", "languageVersion": "2.12" }, { "name": "screen_brightness", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/screen_brightness-2.1.7", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/screen_brightness-2.1.7", "packageUri": "lib/", "languageVersion": "3.0" }, { "name": "screen_brightness_android", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/screen_brightness_android-2.1.3", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/screen_brightness_android-2.1.3", "packageUri": "lib/", "languageVersion": "3.0" }, { "name": "screen_brightness_ios", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/screen_brightness_ios-2.1.2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/screen_brightness_ios-2.1.2", "packageUri": "lib/", "languageVersion": "3.0" }, { "name": "screen_brightness_macos", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/screen_brightness_macos-2.1.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/screen_brightness_macos-2.1.1", "packageUri": "lib/", "languageVersion": "3.0" }, { "name": "screen_brightness_ohos", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/screen_brightness_ohos-2.1.2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/screen_brightness_ohos-2.1.2", "packageUri": "lib/", "languageVersion": "3.0" }, { "name": "screen_brightness_platform_interface", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/screen_brightness_platform_interface-2.1.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/screen_brightness_platform_interface-2.1.0", "packageUri": "lib/", "languageVersion": "3.0" }, { "name": "screen_brightness_windows", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/screen_brightness_windows-2.1.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/screen_brightness_windows-2.1.0", "packageUri": "lib/", "languageVersion": "3.0" }, { "name": "screenshot", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/screenshot-3.0.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/screenshot-3.0.0", "packageUri": "lib/", "languageVersion": "2.12" }, { "name": "shared_preferences", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences-2.5.5", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences-2.5.5", "packageUri": "lib/", "languageVersion": "3.9" }, { "name": "shared_preferences_android", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_android-2.4.23", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_android-2.4.23", "packageUri": "lib/", "languageVersion": "3.9" }, { "name": "shared_preferences_foundation", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_foundation-2.5.6", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_foundation-2.5.6", "packageUri": "lib/", "languageVersion": "3.9" }, { "name": "shared_preferences_linux", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_linux-2.4.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_linux-2.4.1", "packageUri": "lib/", "languageVersion": "3.3" }, { "name": "shared_preferences_platform_interface", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_platform_interface-2.4.2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_platform_interface-2.4.2", "packageUri": "lib/", "languageVersion": "3.9" }, { "name": "shared_preferences_web", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_web-2.4.3", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_web-2.4.3", "packageUri": "lib/", "languageVersion": "3.4" }, { "name": "shared_preferences_windows", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_windows-2.4.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_windows-2.4.1", "packageUri": "lib/", "languageVersion": "3.3" }, { "name": "sky_engine", - "rootUri": "file:///Users/threeone/flutter/bin/cache/pkg/sky_engine", + "rootUri": "file:///Users/wxl/Desktop/flutter/bin/cache/pkg/sky_engine", "packageUri": "lib/", "languageVersion": "3.8" }, { "name": "source_span", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/source_span-1.10.2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/source_span-1.10.2", "packageUri": "lib/", "languageVersion": "3.1" }, { "name": "sp_util", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/sp_util-2.0.3", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/sp_util-2.0.3", "packageUri": "lib/", "languageVersion": "2.12" }, { "name": "sqflite", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/sqflite-2.4.2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/sqflite-2.4.2", "packageUri": "lib/", "languageVersion": "3.7" }, { "name": "sqflite_android", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/sqflite_android-2.4.2+3", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/sqflite_android-2.4.2+3", "packageUri": "lib/", "languageVersion": "3.10" }, { "name": "sqflite_common", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/sqflite_common-2.5.6", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/sqflite_common-2.5.6", "packageUri": "lib/", "languageVersion": "3.8" }, { "name": "sqflite_darwin", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/sqflite_darwin-2.4.2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/sqflite_darwin-2.4.2", "packageUri": "lib/", "languageVersion": "3.7" }, { "name": "sqflite_platform_interface", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/sqflite_platform_interface-2.4.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/sqflite_platform_interface-2.4.0", "packageUri": "lib/", "languageVersion": "3.5" }, { "name": "stack_trace", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/stack_trace-1.12.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/stack_trace-1.12.1", "packageUri": "lib/", "languageVersion": "3.4" }, { "name": "sticky_headers", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/sticky_headers-0.3.0+2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/sticky_headers-0.3.0+2", "packageUri": "lib/", "languageVersion": "2.17" }, { "name": "stream_channel", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/stream_channel-2.1.4", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/stream_channel-2.1.4", "packageUri": "lib/", "languageVersion": "3.3" }, { "name": "string_scanner", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/string_scanner-1.4.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/string_scanner-1.4.1", "packageUri": "lib/", "languageVersion": "3.1" }, { "name": "synchronized", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/synchronized-3.4.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/synchronized-3.4.0", "packageUri": "lib/", "languageVersion": "3.8" }, { "name": "term_glyph", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/term_glyph-1.2.2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/term_glyph-1.2.2", "packageUri": "lib/", "languageVersion": "3.1" }, { "name": "test_api", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/test_api-0.7.7", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/test_api-0.7.7", "packageUri": "lib/", "languageVersion": "3.5" }, { "name": "transparent_image", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/transparent_image-2.0.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/transparent_image-2.0.1", "packageUri": "lib/", "languageVersion": "2.12" }, { "name": "typed_data", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/typed_data-1.4.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/typed_data-1.4.0", "packageUri": "lib/", "languageVersion": "3.5" }, { "name": "url_launcher", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/url_launcher-6.3.2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/url_launcher-6.3.2", "packageUri": "lib/", "languageVersion": "3.6" }, { "name": "url_launcher_android", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_android-6.3.29", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_android-6.3.29", "packageUri": "lib/", "languageVersion": "3.9" }, { "name": "url_launcher_ios", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_ios-6.4.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_ios-6.4.1", "packageUri": "lib/", "languageVersion": "3.10" }, { "name": "url_launcher_linux", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_linux-3.2.2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_linux-3.2.2", "packageUri": "lib/", "languageVersion": "3.8" }, { "name": "url_launcher_macos", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_macos-3.2.5", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_macos-3.2.5", "packageUri": "lib/", "languageVersion": "3.9" }, { "name": "url_launcher_platform_interface", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_platform_interface-2.3.2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_platform_interface-2.3.2", "packageUri": "lib/", "languageVersion": "3.1" }, { "name": "url_launcher_web", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_web-2.4.2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_web-2.4.2", "packageUri": "lib/", "languageVersion": "3.10" }, { "name": "url_launcher_windows", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_windows-3.1.5", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_windows-3.1.5", "packageUri": "lib/", "languageVersion": "3.8" }, { "name": "uuid", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/uuid-4.5.3", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/uuid-4.5.3", "packageUri": "lib/", "languageVersion": "3.0" }, { "name": "vector_math", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/vector_math-2.2.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/vector_math-2.2.0", "packageUri": "lib/", "languageVersion": "3.1" }, { "name": "video_player", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/video_player-2.11.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/video_player-2.11.1", "packageUri": "lib/", "languageVersion": "3.10" }, { "name": "video_player_android", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/video_player_android-2.9.5", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/video_player_android-2.9.5", "packageUri": "lib/", "languageVersion": "3.9" }, { "name": "video_player_avfoundation", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/video_player_avfoundation-2.9.4", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/video_player_avfoundation-2.9.4", "packageUri": "lib/", "languageVersion": "3.10" }, { "name": "video_player_platform_interface", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/video_player_platform_interface-6.6.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/video_player_platform_interface-6.6.0", "packageUri": "lib/", "languageVersion": "3.7" }, { "name": "video_player_web", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/video_player_web-2.4.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/video_player_web-2.4.0", "packageUri": "lib/", "languageVersion": "3.6" }, { "name": "visibility_detector", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/visibility_detector-0.4.0+2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/visibility_detector-0.4.0+2", "packageUri": "lib/", "languageVersion": "2.12" }, { "name": "vm_service", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/vm_service-15.1.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/vm_service-15.1.0", "packageUri": "lib/", "languageVersion": "3.5" }, { "name": "wakelock_plus", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/wakelock_plus-1.5.2", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/wakelock_plus-1.5.2", "packageUri": "lib/", "languageVersion": "3.10" }, { "name": "wakelock_plus_platform_interface", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/wakelock_plus_platform_interface-1.4.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/wakelock_plus_platform_interface-1.4.0", "packageUri": "lib/", "languageVersion": "3.10" }, { "name": "web", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/web-1.1.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/web-1.1.1", "packageUri": "lib/", "languageVersion": "3.4" }, { "name": "wechat_assets_picker", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/wechat_assets_picker-10.1.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/wechat_assets_picker-10.1.1", "packageUri": "lib/", "languageVersion": "3.6" }, { "name": "wechat_picker_library", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/wechat_picker_library-1.0.7", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/wechat_picker_library-1.0.7", "packageUri": "lib/", "languageVersion": "3.4" }, { "name": "win32", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/win32-5.15.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/win32-5.15.0", "packageUri": "lib/", "languageVersion": "3.8" }, { "name": "win32_registry", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/win32_registry-2.1.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/win32_registry-2.1.0", "packageUri": "lib/", "languageVersion": "3.7" }, { "name": "xdg_directories", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/xdg_directories-1.1.0", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/xdg_directories-1.1.0", "packageUri": "lib/", "languageVersion": "3.3" }, { "name": "xml", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/xml-6.6.1", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/xml-6.6.1", "packageUri": "lib/", "languageVersion": "3.8" }, { "name": "yaml", - "rootUri": "file:///Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/yaml-3.1.3", + "rootUri": "file:///Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/yaml-3.1.3", "packageUri": "lib/", "languageVersion": "3.4" }, @@ -1138,7 +1138,7 @@ ], "generator": "pub", "generatorVersion": "3.10.4", - "flutterRoot": "file:///Users/threeone/flutter", + "flutterRoot": "file:///Users/wxl/Desktop/flutter", "flutterVersion": "3.38.5", - "pubCache": "file:///Users/threeone/.pub-cache" + "pubCache": "file:///Users/wxl/.pub-cache" } diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 4e49bdc..7174843 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"device_info_plus","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/device_info_plus-11.5.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_image_compress_common","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flutter_image_compress_common-1.0.6/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_inappwebview_ios","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flutter_inappwebview_ios-1.1.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"image_gallery_saver_plus","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/image_gallery_saver_plus-4.0.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"image_picker_ios","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/image_picker_ios-0.8.13+6/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/package_info_plus-9.0.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/path_provider_foundation-2.6.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"permission_handler_apple","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/permission_handler_apple-9.4.7/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"photo_manager","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/photo_manager-3.9.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"screen_brightness_ios","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/screen_brightness_ios-2.1.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_foundation-2.5.6/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"sqflite_darwin","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/sqflite_darwin-2.4.2/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_ios","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_ios-6.4.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"video_player_avfoundation","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/video_player_avfoundation-2.9.4/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"wakelock_plus","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/wakelock_plus-1.5.2/","native_build":true,"dependencies":["package_info_plus"],"dev_dependency":false}],"android":[{"name":"device_info_plus","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/device_info_plus-11.5.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_image_compress_common","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flutter_image_compress_common-1.0.6/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_inappwebview_android","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flutter_inappwebview_android-1.1.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_plugin_android_lifecycle","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flutter_plugin_android_lifecycle-2.0.34/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"image_gallery_saver_plus","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/image_gallery_saver_plus-4.0.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"image_picker_android","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/image_picker_android-0.8.13+16/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"],"dev_dependency":false},{"name":"jni","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/jni-1.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"jni_flutter","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/jni_flutter-1.0.1/","native_build":true,"dependencies":["jni"],"dev_dependency":false},{"name":"package_info_plus","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/package_info_plus-9.0.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_android","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/path_provider_android-2.3.1/","native_build":false,"dependencies":["jni","jni_flutter"],"dev_dependency":false},{"name":"permission_handler_android","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/permission_handler_android-12.1.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"photo_manager","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/photo_manager-3.9.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"screen_brightness_android","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/screen_brightness_android-2.1.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_android","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_android-2.4.23/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"sqflite_android","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/sqflite_android-2.4.2+3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_android","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_android-6.3.29/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"video_player_android","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/video_player_android-2.9.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"wakelock_plus","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/wakelock_plus-1.5.2/","native_build":true,"dependencies":["package_info_plus"],"dev_dependency":false}],"macos":[{"name":"device_info_plus","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/device_info_plus-11.5.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_selector_macos","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/file_selector_macos-0.9.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_image_compress_macos","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flutter_image_compress_macos-1.0.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_inappwebview_macos","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flutter_inappwebview_macos-1.1.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"image_picker_macos","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/image_picker_macos-0.2.2+1/","native_build":false,"dependencies":["file_selector_macos"],"dev_dependency":false},{"name":"package_info_plus","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/package_info_plus-9.0.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/path_provider_foundation-2.6.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"photo_manager","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/photo_manager-3.9.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"screen_brightness_macos","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/screen_brightness_macos-2.1.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_foundation-2.5.6/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"sqflite_darwin","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/sqflite_darwin-2.4.2/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_macos","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_macos-3.2.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"video_player_avfoundation","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/video_player_avfoundation-2.9.4/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"wakelock_plus","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/wakelock_plus-1.5.2/","native_build":true,"dependencies":["package_info_plus"],"dev_dependency":false}],"linux":[{"name":"device_info_plus","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/device_info_plus-11.5.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"file_selector_linux","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/file_selector_linux-0.9.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"image_picker_linux","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/image_picker_linux-0.2.2/","native_build":false,"dependencies":["file_selector_linux"],"dev_dependency":false},{"name":"jni","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/jni-1.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/package_info_plus-9.0.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"path_provider_linux","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/path_provider_linux-2.2.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_linux","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_linux-2.4.1/","native_build":false,"dependencies":["path_provider_linux"],"dev_dependency":false},{"name":"url_launcher_linux","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_linux-3.2.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"wakelock_plus","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/wakelock_plus-1.5.2/","native_build":false,"dependencies":["package_info_plus"],"dev_dependency":false}],"windows":[{"name":"device_info_plus","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/device_info_plus-11.5.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"file_selector_windows","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/file_selector_windows-0.9.3+5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_inappwebview_windows","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flutter_inappwebview_windows-0.6.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"image_picker_windows","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/image_picker_windows-0.2.2/","native_build":false,"dependencies":["file_selector_windows"],"dev_dependency":false},{"name":"jni","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/jni-1.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/package_info_plus-9.0.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"path_provider_windows","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/path_provider_windows-2.3.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"permission_handler_windows","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/permission_handler_windows-0.2.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"screen_brightness_windows","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/screen_brightness_windows-2.1.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_windows","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_windows-2.4.1/","native_build":false,"dependencies":["path_provider_windows"],"dev_dependency":false},{"name":"url_launcher_windows","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_windows-3.1.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"wakelock_plus","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/wakelock_plus-1.5.2/","native_build":false,"dependencies":["package_info_plus"],"dev_dependency":false}],"web":[{"name":"device_info_plus","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/device_info_plus-11.5.0/","dependencies":[],"dev_dependency":false},{"name":"flutter_image_compress_web","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flutter_image_compress_web-0.1.5/","dependencies":[],"dev_dependency":false},{"name":"flutter_inappwebview_web","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/flutter_inappwebview_web-1.1.2/","dependencies":[],"dev_dependency":false},{"name":"image_picker_for_web","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/image_picker_for_web-3.1.1/","dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/package_info_plus-9.0.1/","dependencies":[],"dev_dependency":false},{"name":"permission_handler_html","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/permission_handler_html-0.1.3+5/","dependencies":[],"dev_dependency":false},{"name":"shared_preferences_web","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_web-2.4.3/","dependencies":[],"dev_dependency":false},{"name":"url_launcher_web","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_web-2.4.2/","dependencies":[],"dev_dependency":false},{"name":"video_player_web","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/video_player_web-2.4.0/","dependencies":[],"dev_dependency":false},{"name":"wakelock_plus","path":"/Users/threeone/.pub-cache/hosted/pub.flutter-io.cn/wakelock_plus-1.5.2/","dependencies":["package_info_plus"],"dev_dependency":false}]},"dependencyGraph":[{"name":"device_info_plus","dependencies":[]},{"name":"file_selector_linux","dependencies":[]},{"name":"file_selector_macos","dependencies":[]},{"name":"file_selector_windows","dependencies":[]},{"name":"flutter_image_compress","dependencies":["flutter_image_compress_common","flutter_image_compress_web","flutter_image_compress_macos","flutter_image_compress_ohos"]},{"name":"flutter_image_compress_common","dependencies":[]},{"name":"flutter_image_compress_macos","dependencies":[]},{"name":"flutter_image_compress_ohos","dependencies":[]},{"name":"flutter_image_compress_web","dependencies":[]},{"name":"flutter_inappwebview","dependencies":["flutter_inappwebview_android","flutter_inappwebview_ios","flutter_inappwebview_macos","flutter_inappwebview_web","flutter_inappwebview_windows"]},{"name":"flutter_inappwebview_android","dependencies":[]},{"name":"flutter_inappwebview_ios","dependencies":[]},{"name":"flutter_inappwebview_macos","dependencies":[]},{"name":"flutter_inappwebview_web","dependencies":[]},{"name":"flutter_inappwebview_windows","dependencies":[]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"image_gallery_saver_plus","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios","image_picker_linux","image_picker_macos","image_picker_windows"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"image_picker_linux","dependencies":["file_selector_linux"]},{"name":"image_picker_macos","dependencies":["file_selector_macos"]},{"name":"image_picker_windows","dependencies":["file_selector_windows"]},{"name":"jni","dependencies":[]},{"name":"jni_flutter","dependencies":["jni"]},{"name":"package_info_plus","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":["jni","jni_flutter"]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_html","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_html","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"photo_manager","dependencies":[]},{"name":"screen_brightness","dependencies":["screen_brightness_android","screen_brightness_ios","screen_brightness_macos","screen_brightness_windows","screen_brightness_ohos"]},{"name":"screen_brightness_android","dependencies":[]},{"name":"screen_brightness_ios","dependencies":[]},{"name":"screen_brightness_macos","dependencies":[]},{"name":"screen_brightness_ohos","dependencies":[]},{"name":"screen_brightness_windows","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]},{"name":"sqflite","dependencies":["sqflite_android","sqflite_darwin"]},{"name":"sqflite_android","dependencies":[]},{"name":"sqflite_darwin","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"wakelock_plus","dependencies":["package_info_plus"]}],"date_created":"2026-04-16 10:41:18.088597","version":"3.38.5","swift_package_manager_enabled":{"ios":false,"macos":false}} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"device_info_plus","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/device_info_plus-11.5.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_image_compress_common","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flutter_image_compress_common-1.0.6/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_inappwebview_ios","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flutter_inappwebview_ios-1.1.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"image_gallery_saver_plus","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/image_gallery_saver_plus-4.0.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"image_picker_ios","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/image_picker_ios-0.8.13+6/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/package_info_plus-9.0.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/path_provider_foundation-2.6.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"permission_handler_apple","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/permission_handler_apple-9.4.7/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"photo_manager","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/photo_manager-3.9.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"screen_brightness_ios","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/screen_brightness_ios-2.1.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_foundation-2.5.6/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"sqflite_darwin","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/sqflite_darwin-2.4.2/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_ios","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_ios-6.4.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"video_player_avfoundation","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/video_player_avfoundation-2.9.4/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"wakelock_plus","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/wakelock_plus-1.5.2/","native_build":true,"dependencies":["package_info_plus"],"dev_dependency":false}],"android":[{"name":"device_info_plus","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/device_info_plus-11.5.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_image_compress_common","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flutter_image_compress_common-1.0.6/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_inappwebview_android","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flutter_inappwebview_android-1.1.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_plugin_android_lifecycle","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flutter_plugin_android_lifecycle-2.0.34/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"image_gallery_saver_plus","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/image_gallery_saver_plus-4.0.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"image_picker_android","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/image_picker_android-0.8.13+16/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"],"dev_dependency":false},{"name":"jni","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/jni-1.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"jni_flutter","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/jni_flutter-1.0.1/","native_build":true,"dependencies":["jni"],"dev_dependency":false},{"name":"package_info_plus","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/package_info_plus-9.0.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_android","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/path_provider_android-2.3.1/","native_build":false,"dependencies":["jni","jni_flutter"],"dev_dependency":false},{"name":"permission_handler_android","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/permission_handler_android-12.1.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"photo_manager","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/photo_manager-3.9.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"screen_brightness_android","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/screen_brightness_android-2.1.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_android","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_android-2.4.23/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"sqflite_android","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/sqflite_android-2.4.2+3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_android","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_android-6.3.29/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"video_player_android","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/video_player_android-2.9.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"wakelock_plus","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/wakelock_plus-1.5.2/","native_build":true,"dependencies":["package_info_plus"],"dev_dependency":false}],"macos":[{"name":"device_info_plus","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/device_info_plus-11.5.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_selector_macos","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/file_selector_macos-0.9.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_image_compress_macos","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flutter_image_compress_macos-1.0.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_inappwebview_macos","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flutter_inappwebview_macos-1.1.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"image_picker_macos","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/image_picker_macos-0.2.2+1/","native_build":false,"dependencies":["file_selector_macos"],"dev_dependency":false},{"name":"package_info_plus","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/package_info_plus-9.0.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/path_provider_foundation-2.6.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"photo_manager","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/photo_manager-3.9.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"screen_brightness_macos","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/screen_brightness_macos-2.1.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_foundation-2.5.6/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"sqflite_darwin","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/sqflite_darwin-2.4.2/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_macos","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_macos-3.2.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"video_player_avfoundation","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/video_player_avfoundation-2.9.4/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"wakelock_plus","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/wakelock_plus-1.5.2/","native_build":true,"dependencies":["package_info_plus"],"dev_dependency":false}],"linux":[{"name":"device_info_plus","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/device_info_plus-11.5.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"file_selector_linux","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/file_selector_linux-0.9.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"image_picker_linux","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/image_picker_linux-0.2.2/","native_build":false,"dependencies":["file_selector_linux"],"dev_dependency":false},{"name":"jni","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/jni-1.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/package_info_plus-9.0.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"path_provider_linux","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/path_provider_linux-2.2.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_linux","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_linux-2.4.1/","native_build":false,"dependencies":["path_provider_linux"],"dev_dependency":false},{"name":"url_launcher_linux","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_linux-3.2.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"wakelock_plus","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/wakelock_plus-1.5.2/","native_build":false,"dependencies":["package_info_plus"],"dev_dependency":false}],"windows":[{"name":"device_info_plus","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/device_info_plus-11.5.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"file_selector_windows","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/file_selector_windows-0.9.3+5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_inappwebview_windows","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flutter_inappwebview_windows-0.6.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"image_picker_windows","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/image_picker_windows-0.2.2/","native_build":false,"dependencies":["file_selector_windows"],"dev_dependency":false},{"name":"jni","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/jni-1.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/package_info_plus-9.0.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"path_provider_windows","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/path_provider_windows-2.3.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"permission_handler_windows","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/permission_handler_windows-0.2.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"screen_brightness_windows","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/screen_brightness_windows-2.1.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_windows","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_windows-2.4.1/","native_build":false,"dependencies":["path_provider_windows"],"dev_dependency":false},{"name":"url_launcher_windows","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_windows-3.1.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"wakelock_plus","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/wakelock_plus-1.5.2/","native_build":false,"dependencies":["package_info_plus"],"dev_dependency":false}],"web":[{"name":"device_info_plus","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/device_info_plus-11.5.0/","dependencies":[],"dev_dependency":false},{"name":"flutter_image_compress_web","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flutter_image_compress_web-0.1.5/","dependencies":[],"dev_dependency":false},{"name":"flutter_inappwebview_web","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/flutter_inappwebview_web-1.1.2/","dependencies":[],"dev_dependency":false},{"name":"image_picker_for_web","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/image_picker_for_web-3.1.1/","dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/package_info_plus-9.0.1/","dependencies":[],"dev_dependency":false},{"name":"permission_handler_html","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/permission_handler_html-0.1.3+5/","dependencies":[],"dev_dependency":false},{"name":"shared_preferences_web","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_web-2.4.3/","dependencies":[],"dev_dependency":false},{"name":"url_launcher_web","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_web-2.4.2/","dependencies":[],"dev_dependency":false},{"name":"video_player_web","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/video_player_web-2.4.0/","dependencies":[],"dev_dependency":false},{"name":"wakelock_plus","path":"/Users/wxl/.pub-cache/hosted/pub.flutter-io.cn/wakelock_plus-1.5.2/","dependencies":["package_info_plus"],"dev_dependency":false}]},"dependencyGraph":[{"name":"device_info_plus","dependencies":[]},{"name":"file_selector_linux","dependencies":[]},{"name":"file_selector_macos","dependencies":[]},{"name":"file_selector_windows","dependencies":[]},{"name":"flutter_image_compress","dependencies":["flutter_image_compress_common","flutter_image_compress_web","flutter_image_compress_macos","flutter_image_compress_ohos"]},{"name":"flutter_image_compress_common","dependencies":[]},{"name":"flutter_image_compress_macos","dependencies":[]},{"name":"flutter_image_compress_ohos","dependencies":[]},{"name":"flutter_image_compress_web","dependencies":[]},{"name":"flutter_inappwebview","dependencies":["flutter_inappwebview_android","flutter_inappwebview_ios","flutter_inappwebview_macos","flutter_inappwebview_web","flutter_inappwebview_windows"]},{"name":"flutter_inappwebview_android","dependencies":[]},{"name":"flutter_inappwebview_ios","dependencies":[]},{"name":"flutter_inappwebview_macos","dependencies":[]},{"name":"flutter_inappwebview_web","dependencies":[]},{"name":"flutter_inappwebview_windows","dependencies":[]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"image_gallery_saver_plus","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios","image_picker_linux","image_picker_macos","image_picker_windows"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"image_picker_linux","dependencies":["file_selector_linux"]},{"name":"image_picker_macos","dependencies":["file_selector_macos"]},{"name":"image_picker_windows","dependencies":["file_selector_windows"]},{"name":"jni","dependencies":[]},{"name":"jni_flutter","dependencies":["jni"]},{"name":"package_info_plus","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":["jni","jni_flutter"]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_html","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_html","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"photo_manager","dependencies":[]},{"name":"screen_brightness","dependencies":["screen_brightness_android","screen_brightness_ios","screen_brightness_macos","screen_brightness_windows","screen_brightness_ohos"]},{"name":"screen_brightness_android","dependencies":[]},{"name":"screen_brightness_ios","dependencies":[]},{"name":"screen_brightness_macos","dependencies":[]},{"name":"screen_brightness_ohos","dependencies":[]},{"name":"screen_brightness_windows","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]},{"name":"sqflite","dependencies":["sqflite_android","sqflite_darwin"]},{"name":"sqflite_android","dependencies":[]},{"name":"sqflite_darwin","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"wakelock_plus","dependencies":["package_info_plus"]}],"date_created":"2026-04-16 17:13:54.129186","version":"3.38.5","swift_package_manager_enabled":{"ios":false,"macos":false}} \ No newline at end of file diff --git a/.idea/flutter_common.iml b/.idea/flutter_common.iml index 462b161..b03b9f6 100644 --- a/.idea/flutter_common.iml +++ b/.idea/flutter_common.iml @@ -63,6 +63,12 @@ + + + + + + diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index 933a000..90344e3 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -271,7 +271,7 @@ - @@ -425,14 +425,14 @@ - - @@ -1020,7 +1020,7 @@ - @@ -1513,10 +1513,10 @@ - - - - + + + + diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index 004eeb3..a0a404d 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -1,62 +1,62 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/upload_image/ossUtil.dart b/lib/upload_image/ossUtil.dart index b3f1a73..26fa4e3 100755 --- a/lib/upload_image/ossUtil.dart +++ b/lib/upload_image/ossUtil.dart @@ -37,8 +37,15 @@ class UploadOss { required String ossHost, bool? isShowLoading, }) async { + final String normalizedFileType = + fileType.toLowerCase() == 'jpeg' ? 'jpg' : fileType.toLowerCase(); + final bool isVideo = normalizedFileType == 'mp4'; + final String? imageContentType = isVideo + ? null + : (normalizedFileType == 'jpg' ? 'jpeg' : normalizedFileType); // 生成oss的路径和文件名我这里目前设置的是moment/20201229/test.mp4 - String pathName = "$rootDir/${getDate()}/app-${getRandom(12)}.$fileType"; + String pathName = + "$rootDir/${getDate()}/app-${getRandom(12)}.$normalizedFileType"; // 请求参数的form对象 FormData formdata = FormData.fromMap({ @@ -51,8 +58,8 @@ class UploadOss { 'success_action_status': '200', 'file': MultipartFile.fromFileSync( path, - contentType: fileType == 'mp4' ? null : DioMediaType("image", "jpg"), - filename: "${getRandom(12)}.$fileType", + contentType: isVideo ? null : DioMediaType("image", imageContentType!), + filename: "${getRandom(12)}.$normalizedFileType", ), }); if (isShowLoading == true) { @@ -71,13 +78,19 @@ class UploadOss { ossHost, data: formdata, options: Options( - contentType: "multipart/form-data;image/jpg", - headers: {'Content-Type': 'multipart/form-data;image/jpg'}, + contentType: isVideo + ? "multipart/form-data" + : "multipart/form-data;image/$imageContentType", + headers: { + 'Content-Type': isVideo + ? "multipart/form-data" + : "multipart/form-data;image/$imageContentType", + }, ), ); print("response ===== $response"); EasyLoading.dismiss(); - if(fileType == 'jpg'){ + if (!isVideo && path.contains('compressed_images_')) { /// 删除临时文件 File(path).deleteSync(); } diff --git a/lib/upload_image/upload_images_tool.dart b/lib/upload_image/upload_images_tool.dart index 8f7ad0f..83cd066 100644 --- a/lib/upload_image/upload_images_tool.dart +++ b/lib/upload_image/upload_images_tool.dart @@ -1,5 +1,4 @@ import 'dart:io'; -import 'dart:math'; import 'package:flutter/cupertino.dart'; import 'package:flutter_common/upload_image/ossUtil.dart'; @@ -12,6 +11,28 @@ import 'package:image_picker/image_picker.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:wechat_assets_picker/wechat_assets_picker.dart'; +class _CompressedImageFile { + const _CompressedImageFile({ + required this.path, + required this.fileType, + }); + + final String path; + final String fileType; +} + +class _ImageCompressionTarget { + const _ImageCompressionTarget({ + required this.format, + required this.extension, + required this.fileType, + }); + + final CompressFormat format; + final String extension; + final String fileType; +} + class UploadImagesTool { static uploadImagesTool({ String? oSSAccessKeyId, @@ -139,7 +160,9 @@ class UploadImagesTool { ) : CupertinoActionSheet( title: const Text('上传图片'), - message: (max == null || max == 0) ? null : Text('请选择上传方式\n相册最多${max}张'), + message: (max == null || max == 0) + ? null + : Text('请选择上传方式\n相册最多$max张'), actions: isAddOtherWidget != null ? [ isAddOtherWidget, @@ -153,7 +176,8 @@ class UploadImagesTool { policy: policy ?? '', callback: callback ?? '', signature: signature ?? '', - chooseImages: (list) => chooseImages?.call(list), + chooseImages: (list) => + chooseImages?.call(list), ); Get.back(); }, @@ -169,7 +193,8 @@ class UploadImagesTool { policy: policy ?? '', callback: callback ?? '', signature: signature ?? '', - chooseImages: (list) => chooseImages?.call(list), + chooseImages: (list) => + chooseImages?.call(list), ); Get.back(); }, @@ -186,7 +211,8 @@ class UploadImagesTool { policy: policy ?? '', callback: callback ?? '', signature: signature ?? '', - chooseImages: (list) => chooseImages?.call(list), + chooseImages: (list) => + chooseImages?.call(list), ); Get.back(); }, @@ -203,7 +229,8 @@ class UploadImagesTool { callback: callback ?? '', signature: signature ?? '', isShowLoading: isShowLoading, - chooseImages: (list) => chooseImages?.call(list), + chooseImages: (list) => + chooseImages?.call(list), ); Get.back(); }, @@ -231,11 +258,10 @@ class UploadImagesTool { String? ossHost, }) async { XFile? file = await ImagePicker().pickImage( - source: ImageSource.camera, - maxHeight: 1080, - maxWidth: 1920, - imageQuality: 80 - ); + source: ImageSource.camera, + maxHeight: 1080, + maxWidth: 1920, + imageQuality: 80); if (file == null) { Get.back(); } else { @@ -267,7 +293,8 @@ class UploadImagesTool { if (isVideo == true) { final List? result = await AssetPicker.pickAssets( Get.context!, - pickerConfig: AssetPickerConfig(maxAssets: 1, requestType: RequestType.video), + pickerConfig: + AssetPickerConfig(maxAssets: 1, requestType: RequestType.video), ); final File? video = await result?.first.file; String path = await saveNetworkImgGallery( @@ -283,34 +310,34 @@ class UploadImagesTool { chooseImages?.call([path]); } else { /// 创建临时目录 - final Directory tempDir = Directory.systemTemp.createTempSync('compressed_images_'); + final Directory tempDir = + Directory.systemTemp.createTempSync('compressed_images_'); final List? result = await AssetPicker.pickAssets( Get.context!, pickerConfig: AssetPickerConfig(maxAssets: max ?? 50), ); + /// 临时存储选中的图片 - final List selectedFiles = []; + final List<_CompressedImageFile> selectedFiles = []; if (result != null && result.isNotEmpty) { for (int i = 0; i < result.length; i++) { final File? file = await result[i].file; if (file != null) { - /// 获取文件扩展名 - final String extension = file.absolute.path.split('.').last; - /// 压缩并保存到临时文件 - final XFile? compressedFile = await FlutterImageCompress.compressAndGetFile( - file.absolute.path, '${tempDir.path}/${DateTime.now().millisecondsSinceEpoch}_compressed.$extension', - quality: 80, minWidth: 1920, minHeight: 1080); + final _CompressedImageFile? compressedFile = + await _compressGalleryImage(file, tempDir); if (compressedFile != null) { selectedFiles.add(compressedFile); } } } } + /// 上传选中的图片 List list = []; for (var element in selectedFiles) { String path = await saveNetworkImgGallery( element.path, + fileType: element.fileType, oSSAccessKeyId: oSSAccessKeyId ?? '', ossHost: ossHost ?? '', ossDirectory: ossDirectory ?? '', @@ -325,6 +352,99 @@ class UploadImagesTool { } } + static Future<_CompressedImageFile?> _compressGalleryImage( + File file, + Directory tempDir, + ) async { + final _ImageCompressionTarget target = + _compressionTargetForPath(file.absolute.path); + final XFile? compressedFile = await _compressImageWithTarget( + file, + tempDir, + target, + ); + if (compressedFile != null) { + return _CompressedImageFile( + path: compressedFile.path, + fileType: target.fileType, + ); + } + + if (target.format == CompressFormat.jpeg) { + return null; + } + const _ImageCompressionTarget fallbackTarget = _ImageCompressionTarget( + format: CompressFormat.jpeg, + extension: 'jpg', + fileType: 'jpg', + ); + final XFile? fallbackFile = await _compressImageWithTarget( + file, + tempDir, + fallbackTarget, + ); + if (fallbackFile == null) { + return null; + } + return _CompressedImageFile( + path: fallbackFile.path, + fileType: fallbackTarget.fileType, + ); + } + + static Future _compressImageWithTarget( + File file, + Directory tempDir, + _ImageCompressionTarget target, + ) async { + try { + return await FlutterImageCompress.compressAndGetFile( + file.absolute.path, + '${tempDir.path}/${DateTime.now().microsecondsSinceEpoch}_compressed.${target.extension}', + quality: 80, + minWidth: 1920, + minHeight: 1080, + format: target.format, + ); + } catch (_) { + return null; + } + } + + static _ImageCompressionTarget _compressionTargetForPath(String path) { + final String extension = + path.split('?').first.split('.').last.toLowerCase(); + switch (extension) { + case 'png': + return const _ImageCompressionTarget( + format: CompressFormat.png, + extension: 'png', + fileType: 'png', + ); + case 'webp': + return const _ImageCompressionTarget( + format: CompressFormat.webp, + extension: 'webp', + fileType: 'webp', + ); + case 'heic': + case 'heif': + return const _ImageCompressionTarget( + format: CompressFormat.heic, + extension: 'heic', + fileType: 'heic', + ); + case 'jpeg': + case 'jpg': + default: + return const _ImageCompressionTarget( + format: CompressFormat.jpeg, + extension: 'jpg', + fileType: 'jpg', + ); + } + } + // 保存网络图片 static Future saveNetworkImg( XFile file, { From aa89e03beec78adbb496d8ff231c775c597ff9c7 Mon Sep 17 00:00:00 2001 From: wuxinglong Date: Fri, 29 May 2026 16:17:26 +0800 Subject: [PATCH 2/4] feat: add video batch upload queue --- lib/flutter_common.dart | 1 + lib/upload_video/video_batch_upload.dart | 4 + .../video_batch_upload_config.dart | 6 + .../video_batch_upload_panel.dart | 345 ++++++++++++++++++ .../video_batch_upload_queue.dart | 335 +++++++++++++++++ .../video_batch_upload_service.dart | 62 ++++ lib/upload_video/video_batch_upload_task.dart | 123 +++++++ .../video_batch_upload_widgets.dart | 75 ++++ lib/upload_video/video_batch_uploader.dart | 95 +++++ 9 files changed, 1046 insertions(+) create mode 100644 lib/upload_video/video_batch_upload.dart create mode 100644 lib/upload_video/video_batch_upload_config.dart create mode 100644 lib/upload_video/video_batch_upload_panel.dart create mode 100644 lib/upload_video/video_batch_upload_queue.dart create mode 100644 lib/upload_video/video_batch_upload_service.dart create mode 100644 lib/upload_video/video_batch_upload_task.dart create mode 100644 lib/upload_video/video_batch_upload_widgets.dart create mode 100644 lib/upload_video/video_batch_uploader.dart diff --git a/lib/flutter_common.dart b/lib/flutter_common.dart index 7bfa5d6..787fe95 100644 --- a/lib/flutter_common.dart +++ b/lib/flutter_common.dart @@ -3,4 +3,5 @@ export 'calendarcalendar/custom_calendar_range_picker_widget.dart'; export 'calendarcalendar/custom_date_picker.dart'; export 'upload_image/look_images_widget.dart'; export 'upload_image/upload_images_tool.dart'; +export 'upload_video/video_batch_upload.dart'; export 'utils/date_utils.dart'; diff --git a/lib/upload_video/video_batch_upload.dart b/lib/upload_video/video_batch_upload.dart new file mode 100644 index 0000000..076aaf2 --- /dev/null +++ b/lib/upload_video/video_batch_upload.dart @@ -0,0 +1,4 @@ +export 'video_batch_upload_config.dart'; +export 'video_batch_upload_task.dart'; +export 'video_batch_uploader.dart'; +export 'video_batch_upload_widgets.dart'; diff --git a/lib/upload_video/video_batch_upload_config.dart b/lib/upload_video/video_batch_upload_config.dart new file mode 100644 index 0000000..6c72547 --- /dev/null +++ b/lib/upload_video/video_batch_upload_config.dart @@ -0,0 +1,6 @@ +class VideoBatchUploadConfig { + const VideoBatchUploadConfig._(); + + static const int maxAssets = 9; + static const int maxConcurrent = 2; +} diff --git a/lib/upload_video/video_batch_upload_panel.dart b/lib/upload_video/video_batch_upload_panel.dart new file mode 100644 index 0000000..3304458 --- /dev/null +++ b/lib/upload_video/video_batch_upload_panel.dart @@ -0,0 +1,345 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; + +import 'video_batch_upload_queue.dart'; +import 'video_batch_upload_task.dart'; + +class VideoBatchUploadPanel extends StatelessWidget { + const VideoBatchUploadPanel({ + super.key, + required this.queue, + }); + + final VideoBatchUploadQueue queue; + + @override + Widget build(BuildContext context) { + if (!queue.hasTasks) { + return const SizedBox.shrink(); + } + return Positioned( + left: 0, + right: 0, + bottom: 0, + child: AnimatedSwitcher( + duration: const Duration(milliseconds: 180), + child: queue.isExpanded + ? _ExpandedUploadPanel(queue: queue) + : _CollapsedUploadBar(queue: queue), + ), + ); + } +} + +class _CollapsedUploadBar extends StatelessWidget { + const _CollapsedUploadBar({required this.queue}); + + final VideoBatchUploadQueue queue; + + @override + Widget build(BuildContext context) { + return SafeArea( + top: false, + child: GestureDetector( + onTap: queue.toggleExpanded, + child: Container( + height: 70.h, + margin: EdgeInsets.fromLTRB(24.w, 0, 24.w, 18.h), + padding: EdgeInsets.symmetric(horizontal: 22.w), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(18.r), + boxShadow: [ + BoxShadow( + color: Colors.black.withValues(alpha: 0.12), + blurRadius: 18.r, + offset: Offset(0, 6.h), + ), + ], + ), + child: Row( + children: [ + Icon( + Icons.cloud_upload_outlined, + color: const Color(0xFF46A5FF), + size: 34.sp, + ), + SizedBox(width: 12.w), + Expanded( + child: Text( + '正在上传 ${queue.finishedCount}/${queue.totalCount}', + style: TextStyle( + fontSize: 24.sp, + color: const Color(0xFF1F2937), + fontWeight: FontWeight.w500, + ), + ), + ), + Icon( + Icons.keyboard_arrow_up_rounded, + color: const Color(0xFF667085), + size: 34.sp, + ), + ], + ), + ), + ), + ); + } +} + +class _ExpandedUploadPanel extends StatelessWidget { + const _ExpandedUploadPanel({required this.queue}); + + final VideoBatchUploadQueue queue; + + @override + Widget build(BuildContext context) { + final double bottomPadding = MediaQuery.of(context).padding.bottom; + return Container( + constraints: BoxConstraints(maxHeight: 560.h), + padding: EdgeInsets.fromLTRB(24.w, 20.h, 24.w, 18.h + bottomPadding), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.vertical(top: Radius.circular(24.r)), + boxShadow: [ + BoxShadow( + color: Colors.black.withValues(alpha: 0.12), + blurRadius: 18.r, + offset: Offset(0, -6.h), + ), + ], + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + children: [ + Expanded( + child: Text( + '上传视频', + style: TextStyle( + fontSize: 30.sp, + color: const Color(0xFF111827), + fontWeight: FontWeight.w600, + ), + ), + ), + Text( + '${queue.finishedCount}/${queue.totalCount}', + style: TextStyle( + fontSize: 24.sp, + color: const Color(0xFF667085), + ), + ), + SizedBox(width: 10.w), + GestureDetector( + onTap: queue.toggleExpanded, + behavior: HitTestBehavior.opaque, + child: Icon( + Icons.keyboard_arrow_down_rounded, + color: const Color(0xFF667085), + size: 38.sp, + ), + ), + ], + ), + SizedBox(height: 16.h), + Flexible( + child: ListView.separated( + padding: EdgeInsets.zero, + shrinkWrap: true, + itemCount: queue.tasks.length, + separatorBuilder: (_, __) => SizedBox(height: 12.h), + itemBuilder: (_, int index) { + final VideoBatchUploadTask task = queue.tasks[index]; + return _UploadTaskCell( + task: task, + onRetry: () => queue.retryTask(task), + onRemove: () => queue.removeTask(task), + ); + }, + ), + ), + ], + ), + ); + } +} + +class _UploadTaskCell extends StatelessWidget { + const _UploadTaskCell({ + required this.task, + required this.onRetry, + required this.onRemove, + }); + + final VideoBatchUploadTask task; + final VoidCallback onRetry; + final VoidCallback onRemove; + + @override + Widget build(BuildContext context) { + final Color statusColor = task.status == VideoBatchUploadStatus.failed + ? const Color(0xFFE5484D) + : const Color(0xFF667085); + return Container( + padding: EdgeInsets.all(12.w), + decoration: BoxDecoration( + color: const Color(0xFFF7F8FA), + borderRadius: BorderRadius.circular(16.r), + ), + child: Row( + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(12.r), + child: SizedBox( + width: 86.w, + height: 86.w, + child: task.thumbnail == null + ? Container( + color: const Color(0xFFEDEFF3), + alignment: Alignment.center, + child: Icon( + Icons.videocam_outlined, + size: 46.sp, + color: const Color(0xFF98A2B3), + ), + ) + : Image.memory( + task.thumbnail!, + fit: BoxFit.cover, + ), + ), + ), + SizedBox(width: 14.w), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + task.fileName, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 24.sp, + color: const Color(0xFF1F2937), + fontWeight: FontWeight.w500, + ), + ), + SizedBox(height: 8.h), + Text( + _subtitle, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 20.sp, + color: const Color(0xFF8D90A0), + ), + ), + SizedBox(height: 10.h), + ClipRRect( + borderRadius: BorderRadius.circular(999), + child: LinearProgressIndicator( + value: task.progress.clamp(0, 1), + minHeight: 6.h, + backgroundColor: const Color(0xFFE5E7EB), + valueColor: AlwaysStoppedAnimation( + task.status == VideoBatchUploadStatus.failed + ? const Color(0xFFE5484D) + : const Color(0xFF46A5FF), + ), + ), + ), + ], + ), + ), + SizedBox(width: 12.w), + SizedBox( + width: 96.w, + child: Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text( + task.status == VideoBatchUploadStatus.failed && + task.errorMessage.isNotEmpty + ? task.errorMessage + : task.status.label, + maxLines: 1, + overflow: TextOverflow.ellipsis, + textAlign: TextAlign.right, + style: TextStyle( + fontSize: 20.sp, + color: statusColor, + ), + ), + SizedBox(height: 12.h), + _TaskActionButton( + task: task, + onRetry: onRetry, + onRemove: onRemove, + ), + ], + ), + ), + ], + ), + ); + } + + String get _subtitle { + final List parts = [ + if (task.durationText.isNotEmpty) task.durationText, + if (task.fileSizeText.isNotEmpty) task.fileSizeText, + ]; + return parts.isEmpty ? '本地视频' : parts.join(' · '); + } +} + +class _TaskActionButton extends StatelessWidget { + const _TaskActionButton({ + required this.task, + required this.onRetry, + required this.onRemove, + }); + + final VideoBatchUploadTask task; + final VoidCallback onRetry; + final VoidCallback onRemove; + + @override + Widget build(BuildContext context) { + if (task.canRetry) { + return GestureDetector( + onTap: onRetry, + behavior: HitTestBehavior.opaque, + child: Text( + '重试', + style: TextStyle( + fontSize: 22.sp, + color: const Color(0xFF46A5FF), + fontWeight: FontWeight.w500, + ), + ), + ); + } + if (task.status == VideoBatchUploadStatus.completed) { + return Icon( + Icons.check_circle_rounded, + size: 30.sp, + color: const Color(0xFF12B76A), + ); + } + return GestureDetector( + onTap: onRemove, + behavior: HitTestBehavior.opaque, + child: Icon( + task.status == VideoBatchUploadStatus.uploading + ? Icons.close_rounded + : Icons.delete_outline_rounded, + size: 30.sp, + color: const Color(0xFF98A2B3), + ), + ); + } +} diff --git a/lib/upload_video/video_batch_upload_queue.dart b/lib/upload_video/video_batch_upload_queue.dart new file mode 100644 index 0000000..1cb2983 --- /dev/null +++ b/lib/upload_video/video_batch_upload_queue.dart @@ -0,0 +1,335 @@ +import 'dart:async'; + +import 'package:dio/dio.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_common/utils/toast_utils.dart'; + +import 'video_batch_upload_config.dart'; +import 'video_batch_upload_service.dart'; +import 'video_batch_upload_task.dart'; + +class VideoBatchUploadQueue { + VideoBatchUploadQueue({ + required this.contextProvider, + required this.uploadTask, + required this.saveTask, + required this.onChanged, + this.onCompleted, + this.maxAssets = VideoBatchUploadConfig.maxAssets, + this.maxConcurrent = VideoBatchUploadConfig.maxConcurrent, + }); + + final BuildContext? Function() contextProvider; + final VideoBatchUploadUploadTask uploadTask; + final VideoBatchUploadSaveTask saveTask; + final VoidCallback onChanged; + final FutureOr Function()? onCompleted; + final int maxAssets; + final int maxConcurrent; + + final List tasks = []; + int _batchTotalCount = 0; + int _completedRemovedCount = 0; + bool isExpanded = false; + bool _isRunning = false; + bool _completionNotified = false; + bool _isDisposed = false; + + bool get hasTasks => tasks.isNotEmpty; + + bool get hasActiveUploads => tasks.any((VideoBatchUploadTask task) { + return task.isActive; + }); + + int get totalCount => _batchTotalCount > 0 ? _batchTotalCount : tasks.length; + + int get completedCount => tasks + .where((VideoBatchUploadTask task) => + task.status == VideoBatchUploadStatus.completed) + .length; + + int get failedCount => tasks + .where((VideoBatchUploadTask task) => + task.status == VideoBatchUploadStatus.failed) + .length; + + int get finishedCount => + _completedRemovedCount + completedCount + failedCount; + + Future pickAndStart() async { + if (hasActiveUploads) { + isExpanded = true; + _notifyChanged(); + ToastUtils.showToast(msg: '视频正在上传中'); + return; + } + + final BuildContext? context = contextProvider(); + if (context == null || !context.mounted) { + return; + } + + final List pickedTasks = + await VideoBatchUploadPicker.pickVideos( + context, + maxAssets: maxAssets, + ); + if (pickedTasks.isEmpty) { + return; + } + + tasks + ..clear() + ..addAll(pickedTasks); + _batchTotalCount = pickedTasks.length; + _completedRemovedCount = 0; + isExpanded = true; + _completionNotified = false; + _notifyChanged(); + unawaited(_runQueue()); + } + + void toggleExpanded() { + if (!hasTasks) { + return; + } + isExpanded = !isExpanded; + _notifyChanged(); + } + + void retryTask(VideoBatchUploadTask task) { + if (!tasks.contains(task) || !task.canRetry) { + return; + } + task + ..status = VideoBatchUploadStatus.waiting + ..progress = 0 + ..uploadUrl = '' + ..errorMessage = ''; + _completionNotified = false; + isExpanded = true; + _notifyChanged(); + unawaited(_runQueue()); + } + + void removeTask(VideoBatchUploadTask task) { + if (!tasks.contains(task)) { + return; + } + task.cancelToken?.cancel('removed'); + tasks.remove(task); + if (tasks.isEmpty) { + isExpanded = false; + _resetBatchProgress(); + } + _notifyChanged(); + } + + void clear() { + for (final VideoBatchUploadTask task in tasks) { + task.cancelToken?.cancel('cleared'); + } + tasks.clear(); + isExpanded = false; + _isRunning = false; + _resetBatchProgress(); + _notifyChanged(); + } + + void cancelAll() { + for (final VideoBatchUploadTask task in tasks) { + task.cancelToken?.cancel('cancelled'); + } + for (final VideoBatchUploadTask task in tasks) { + if (task.isActive) { + task + ..status = VideoBatchUploadStatus.failed + ..errorMessage = '已取消'; + } + } + _isRunning = false; + _notifyChanged(); + } + + void requestExit({required VoidCallback onExit}) { + if (!hasActiveUploads) { + onExit(); + return; + } + ToastUtils.showAlterDialog( + titleText: '视频还在上传', + contentText: '离开会中断本次上传,确定要离开吗?', + confirmText: '离开', + confirmCallback: () { + cancelAll(); + onExit(); + }, + ); + } + + void dispose() { + _isDisposed = true; + for (final VideoBatchUploadTask task in tasks) { + task.cancelToken?.cancel('disposed'); + } + } + + void _resetBatchProgress() { + _batchTotalCount = 0; + _completedRemovedCount = 0; + _completionNotified = false; + } + + Future _runQueue() async { + if (_isRunning || _isDisposed) { + return; + } + _isRunning = true; + final int workerCount = maxConcurrent < 1 ? 1 : maxConcurrent; + final List> workers = List>.generate( + workerCount, + (_) => _uploadWorker(), + ); + await Future.wait(workers); + _isRunning = false; + await _notifyCompletedIfNeeded(); + } + + Future _uploadWorker() async { + while (true) { + if (_isDisposed) { + return; + } + final VideoBatchUploadTask? task = _nextWaitingTask(); + if (task == null) { + return; + } + await _processTask(task); + } + } + + VideoBatchUploadTask? _nextWaitingTask() { + for (final VideoBatchUploadTask task in tasks) { + if (task.status == VideoBatchUploadStatus.waiting) { + return task; + } + } + return null; + } + + Future _processTask(VideoBatchUploadTask task) async { + task + ..status = VideoBatchUploadStatus.uploading + ..progress = 0 + ..errorMessage = '' + ..cancelToken = CancelToken(); + _notifyChanged(); + + try { + final String uploadUrl = await uploadTask( + task, + (double progress) { + if (!tasks.contains(task)) { + return; + } + task.progress = progress.clamp(0, 1); + _notifyChanged(); + }, + ); + if (!tasks.contains(task)) { + return; + } + if (uploadUrl.trim().isEmpty) { + throw Exception('empty upload url'); + } + task + ..uploadUrl = uploadUrl + ..progress = 1 + ..status = VideoBatchUploadStatus.uploaded; + _notifyChanged(); + + task.status = VideoBatchUploadStatus.saving; + _notifyChanged(); + final bool saved = await saveTask(task); + if (!tasks.contains(task)) { + return; + } + if (saved) { + task.status = VideoBatchUploadStatus.completed; + _completedRemovedCount += 1; + tasks.remove(task); + if (tasks.isEmpty) { + isExpanded = false; + } + } else { + task + ..status = VideoBatchUploadStatus.failed + ..errorMessage = '入库失败'; + } + } on DioException catch (error) { + if (!tasks.contains(task)) { + return; + } + task + ..status = VideoBatchUploadStatus.failed + ..errorMessage = + CancelToken.isCancel(error) ? '已取消' : _networkErrorText(error); + } catch (_) { + if (!tasks.contains(task)) { + return; + } + task + ..status = VideoBatchUploadStatus.failed + ..errorMessage = '上传失败'; + } finally { + task.cancelToken = null; + _notifyChanged(); + } + } + + String _networkErrorText(DioException error) { + switch (error.type) { + case DioExceptionType.connectionTimeout: + case DioExceptionType.sendTimeout: + case DioExceptionType.receiveTimeout: + case DioExceptionType.connectionError: + return '网络异常'; + case DioExceptionType.cancel: + return '已取消'; + case DioExceptionType.badResponse: + return '上传失败'; + case DioExceptionType.badCertificate: + case DioExceptionType.unknown: + return '上传失败'; + } + } + + Future _notifyCompletedIfNeeded() async { + if (_isDisposed || + _completionNotified || + totalCount == 0 || + hasActiveUploads) { + return; + } + _completionNotified = true; + await onCompleted?.call(); + if (failedCount > 0) { + ToastUtils.showToast( + msg: '已上传 $_completedRemovedCount 个,失败 $failedCount 个'); + return; + } + final int completed = _completedRemovedCount; + ToastUtils.showToast(msg: '已上传 $completed 个视频'); + tasks.clear(); + isExpanded = false; + _resetBatchProgress(); + _notifyChanged(); + } + + void _notifyChanged() { + if (_isDisposed) { + return; + } + onChanged(); + } +} diff --git a/lib/upload_video/video_batch_upload_service.dart b/lib/upload_video/video_batch_upload_service.dart new file mode 100644 index 0000000..6c2aa4c --- /dev/null +++ b/lib/upload_video/video_batch_upload_service.dart @@ -0,0 +1,62 @@ +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:flutter/widgets.dart'; +import 'package:wechat_assets_picker/wechat_assets_picker.dart'; + +import 'video_batch_upload_config.dart'; +import 'video_batch_upload_task.dart'; + +class VideoBatchUploadPicker { + const VideoBatchUploadPicker._(); + + static Future> pickVideos( + BuildContext context, { + int maxAssets = VideoBatchUploadConfig.maxAssets, + }) async { + final List? assets = await AssetPicker.pickAssets( + context, + pickerConfig: AssetPickerConfig( + maxAssets: maxAssets, + requestType: RequestType.video, + ), + ); + if (assets == null || assets.isEmpty) { + return []; + } + + final List tasks = []; + for (final AssetEntity asset in assets) { + final File? file = await asset.file; + if (file == null) { + continue; + } + final Uint8List? thumbnail = await asset.thumbnailDataWithSize( + const ThumbnailSize.square(220), + quality: 72, + ); + final int fileSize = await file.length(); + tasks.add( + VideoBatchUploadTask( + id: '${asset.id}_${DateTime.now().microsecondsSinceEpoch}', + file: file, + fileName: _normalizeFileName(asset.title, file.path), + fileSize: fileSize, + duration: asset.duration, + thumbnail: thumbnail, + ), + ); + } + return tasks; + } + + static String _normalizeFileName(String? assetTitle, String path) { + final String title = (assetTitle ?? '').trim(); + if (title.isNotEmpty) { + return title; + } + final List segments = path.split(Platform.pathSeparator); + final String fileName = segments.isEmpty ? '' : segments.last.trim(); + return fileName.isEmpty ? 'video.mp4' : fileName; + } +} diff --git a/lib/upload_video/video_batch_upload_task.dart b/lib/upload_video/video_batch_upload_task.dart new file mode 100644 index 0000000..9e6357b --- /dev/null +++ b/lib/upload_video/video_batch_upload_task.dart @@ -0,0 +1,123 @@ +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:dio/dio.dart'; + +typedef VideoBatchUploadProgressCallback = void Function(double progress); + +typedef VideoBatchUploadUploadTask = Future Function( + VideoBatchUploadTask task, + VideoBatchUploadProgressCallback onProgress, +); + +typedef VideoBatchUploadSaveTask = Future Function( + VideoBatchUploadTask task, +); + +enum VideoBatchUploadStatus { + waiting, + uploading, + uploaded, + saving, + completed, + failed, +} + +extension VideoBatchUploadStatusText on VideoBatchUploadStatus { + String get label { + switch (this) { + case VideoBatchUploadStatus.waiting: + return '等待中'; + case VideoBatchUploadStatus.uploading: + return '上传中'; + case VideoBatchUploadStatus.uploaded: + return '上传成功'; + case VideoBatchUploadStatus.saving: + return '入库中'; + case VideoBatchUploadStatus.completed: + return '已完成'; + case VideoBatchUploadStatus.failed: + return '失败'; + } + } +} + +class VideoBatchUploadTask { + VideoBatchUploadTask({ + required this.id, + required this.file, + required this.fileName, + required this.fileSize, + required this.duration, + this.thumbnail, + }); + + final String id; + final File file; + final String fileName; + final int fileSize; + final int duration; + final Uint8List? thumbnail; + + VideoBatchUploadStatus status = VideoBatchUploadStatus.waiting; + double progress = 0; + String uploadUrl = ''; + String errorMessage = ''; + CancelToken? cancelToken; + + String get ossUrl => uploadUrl; + + set ossUrl(String value) { + uploadUrl = value; + } + + bool get isActive => + status == VideoBatchUploadStatus.waiting || + status == VideoBatchUploadStatus.uploading || + status == VideoBatchUploadStatus.uploaded || + status == VideoBatchUploadStatus.saving; + + bool get canRetry => status == VideoBatchUploadStatus.failed; + + bool get canRemove => + status == VideoBatchUploadStatus.waiting || + status == VideoBatchUploadStatus.completed || + status == VideoBatchUploadStatus.failed; + + String get fileSizeText { + if (fileSize <= 0) { + return ''; + } + final double mb = fileSize / 1024 / 1024; + if (mb >= 1) { + return '${mb.toStringAsFixed(1)}MB'; + } + final double kb = fileSize / 1024; + return '${kb.toStringAsFixed(0)}KB'; + } + + String get durationText { + if (duration <= 0) { + return ''; + } + final int minutes = duration ~/ 60; + final int seconds = duration % 60; + return '${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}'; + } + + Map toVideoPayload({ + String urlKey = 'fileURL', + String fileNameKey = 'fileName', + String durationKey = 'duration', + }) { + return { + urlKey: uploadUrl, + fileNameKey: fileName, + if (duration > 0) durationKey: duration, + }; + } + + Map toLibraryVideoPayload() { + return toVideoPayload(); + } +} diff --git a/lib/upload_video/video_batch_upload_widgets.dart b/lib/upload_video/video_batch_upload_widgets.dart new file mode 100644 index 0000000..0d40476 --- /dev/null +++ b/lib/upload_video/video_batch_upload_widgets.dart @@ -0,0 +1,75 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; + +class VideoBatchUploadBackButton extends StatelessWidget { + const VideoBatchUploadBackButton({ + super.key, + required this.onTap, + this.iconSize = 19, + }); + + final VoidCallback onTap; + final double iconSize; + + @override + Widget build(BuildContext context) { + return IconButton( + onPressed: onTap, + icon: Icon( + Icons.arrow_back_ios_new, + color: Colors.black, + size: iconSize, + ), + ); + } +} + +class VideoBatchUploadIconButton extends StatelessWidget { + const VideoBatchUploadIconButton({ + super.key, + required this.onTap, + this.iconSize, + this.rightPadding, + }); + + final VoidCallback onTap; + final double? iconSize; + final double? rightPadding; + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: onTap, + child: Padding( + padding: EdgeInsets.only(right: rightPadding ?? 30.w), + child: Icon( + Icons.video_call_outlined, + size: iconSize ?? 50.sp, + color: const Color(0xFF1D1D21), + ), + ), + ); + } +} + +class VideoBatchUploadEmptyPlaceholder extends StatelessWidget { + const VideoBatchUploadEmptyPlaceholder({ + super.key, + this.title = '这个视频库里还没有视频', + }); + + final String title; + + @override + Widget build(BuildContext context) { + return Center( + child: Text( + title, + style: TextStyle( + fontSize: 28.sp, + color: const Color(0xFF8D90A0), + ), + ), + ); + } +} diff --git a/lib/upload_video/video_batch_uploader.dart b/lib/upload_video/video_batch_uploader.dart new file mode 100644 index 0000000..cdc16f9 --- /dev/null +++ b/lib/upload_video/video_batch_uploader.dart @@ -0,0 +1,95 @@ +import 'dart:async'; + +import 'package:flutter/widgets.dart'; + +import 'video_batch_upload_config.dart'; +import 'video_batch_upload_panel.dart'; +import 'video_batch_upload_queue.dart'; +import 'video_batch_upload_task.dart'; + +typedef VideoBatchUploadCallback = FutureOr Function(); + +class VideoBatchUploader { + VideoBatchUploader({ + required BuildContext? Function() contextProvider, + required VideoBatchUploadUploadTask uploadTask, + required VideoBatchUploadSaveTask saveTask, + VoidCallback? onChanged, + VideoBatchUploadCallback? onCompleted, + int? maxAssets, + int? maxConcurrent, + }) : _contextProvider = contextProvider, + _onChanged = onChanged { + queue = VideoBatchUploadQueue( + contextProvider: contextProvider, + uploadTask: uploadTask, + saveTask: saveTask, + onChanged: _handleChanged, + onCompleted: onCompleted, + maxAssets: maxAssets ?? VideoBatchUploadConfig.maxAssets, + maxConcurrent: maxConcurrent ?? VideoBatchUploadConfig.maxConcurrent, + ); + } + + final BuildContext? Function() _contextProvider; + final VoidCallback? _onChanged; + late final VideoBatchUploadQueue queue; + OverlayEntry? _overlayEntry; + + bool get hasActiveUploads => queue.hasActiveUploads; + + Future start() async { + await queue.pickAndStart(); + } + + void requestExit({required VoidCallback onExit}) { + queue.requestExit(onExit: onExit); + } + + void clear() { + queue.clear(); + _syncOverlay(); + } + + void dispose() { + queue.dispose(); + _removeOverlay(); + } + + void _handleChanged() { + _syncOverlay(); + _overlayEntry?.markNeedsBuild(); + _onChanged?.call(); + } + + void _syncOverlay() { + if (queue.hasTasks) { + _insertOverlayIfNeeded(); + return; + } + _removeOverlay(); + } + + void _insertOverlayIfNeeded() { + if (_overlayEntry != null) { + return; + } + final BuildContext? context = _contextProvider(); + if (context == null || !context.mounted) { + return; + } + final OverlayState? overlay = Overlay.maybeOf(context); + if (overlay == null) { + return; + } + _overlayEntry = OverlayEntry( + builder: (_) => VideoBatchUploadPanel(queue: queue), + ); + overlay.insert(_overlayEntry!); + } + + void _removeOverlay() { + _overlayEntry?.remove(); + _overlayEntry = null; + } +} From 037f14b52f966185cecb019f9fc1aeedbaa39727 Mon Sep 17 00:00:00 2001 From: wuxinglong Date: Fri, 29 May 2026 17:58:44 +0800 Subject: [PATCH 3/4] =?UTF-8?q?fix(upload=5Fimage):=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E5=AA=92=E4=BD=93=E4=B8=8A=E4=BC=A0=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../video_batch_upload_panel.dart | 10 ++-- .../video_batch_upload_queue.dart | 15 ++++-- .../video_batch_upload_service.dart | 48 ++++++++++++++++-- lib/upload_video/video_batch_upload_task.dart | 49 +++++++++++++++++++ .../video_batch_upload_widgets.dart | 8 ++- lib/upload_video/video_batch_uploader.dart | 2 + 6 files changed, 117 insertions(+), 15 deletions(-) diff --git a/lib/upload_video/video_batch_upload_panel.dart b/lib/upload_video/video_batch_upload_panel.dart index 3304458..ca7293d 100644 --- a/lib/upload_video/video_batch_upload_panel.dart +++ b/lib/upload_video/video_batch_upload_panel.dart @@ -67,7 +67,7 @@ class _CollapsedUploadBar extends StatelessWidget { SizedBox(width: 12.w), Expanded( child: Text( - '正在上传 ${queue.finishedCount}/${queue.totalCount}', + '正在上传${queue.assetType.label} ${queue.finishedCount}/${queue.totalCount}', style: TextStyle( fontSize: 24.sp, color: const Color(0xFF1F2937), @@ -117,7 +117,7 @@ class _ExpandedUploadPanel extends StatelessWidget { children: [ Expanded( child: Text( - '上传视频', + '上传${queue.assetType.label}', style: TextStyle( fontSize: 30.sp, color: const Color(0xFF111827), @@ -201,7 +201,9 @@ class _UploadTaskCell extends StatelessWidget { color: const Color(0xFFEDEFF3), alignment: Alignment.center, child: Icon( - Icons.videocam_outlined, + task.assetType == VideoBatchUploadAssetType.video + ? Icons.videocam_outlined + : Icons.image_outlined, size: 46.sp, color: const Color(0xFF98A2B3), ), @@ -292,7 +294,7 @@ class _UploadTaskCell extends StatelessWidget { if (task.durationText.isNotEmpty) task.durationText, if (task.fileSizeText.isNotEmpty) task.fileSizeText, ]; - return parts.isEmpty ? '本地视频' : parts.join(' · '); + return parts.isEmpty ? task.assetType.localLabel : parts.join(' · '); } } diff --git a/lib/upload_video/video_batch_upload_queue.dart b/lib/upload_video/video_batch_upload_queue.dart index 1cb2983..fa4d237 100644 --- a/lib/upload_video/video_batch_upload_queue.dart +++ b/lib/upload_video/video_batch_upload_queue.dart @@ -14,6 +14,7 @@ class VideoBatchUploadQueue { required this.uploadTask, required this.saveTask, required this.onChanged, + this.assetType = VideoBatchUploadAssetType.video, this.onCompleted, this.maxAssets = VideoBatchUploadConfig.maxAssets, this.maxConcurrent = VideoBatchUploadConfig.maxConcurrent, @@ -23,6 +24,7 @@ class VideoBatchUploadQueue { final VideoBatchUploadUploadTask uploadTask; final VideoBatchUploadSaveTask saveTask; final VoidCallback onChanged; + final VideoBatchUploadAssetType assetType; final FutureOr Function()? onCompleted; final int maxAssets; final int maxConcurrent; @@ -60,7 +62,7 @@ class VideoBatchUploadQueue { if (hasActiveUploads) { isExpanded = true; _notifyChanged(); - ToastUtils.showToast(msg: '视频正在上传中'); + ToastUtils.showToast(msg: '${assetType.label}正在上传中'); return; } @@ -70,9 +72,10 @@ class VideoBatchUploadQueue { } final List pickedTasks = - await VideoBatchUploadPicker.pickVideos( + await VideoBatchUploadPicker.pickMedia( context, maxAssets: maxAssets, + assetType: assetType, ); if (pickedTasks.isEmpty) { return; @@ -157,7 +160,7 @@ class VideoBatchUploadQueue { return; } ToastUtils.showAlterDialog( - titleText: '视频还在上传', + titleText: '${assetType.label}还在上传', contentText: '离开会中断本次上传,确定要离开吗?', confirmText: '离开', confirmCallback: () { @@ -315,11 +318,13 @@ class VideoBatchUploadQueue { await onCompleted?.call(); if (failedCount > 0) { ToastUtils.showToast( - msg: '已上传 $_completedRemovedCount 个,失败 $failedCount 个'); + msg: + '已上传 $_completedRemovedCount ${assetType.unit},失败 $failedCount ${assetType.unit}'); return; } final int completed = _completedRemovedCount; - ToastUtils.showToast(msg: '已上传 $completed 个视频'); + ToastUtils.showToast( + msg: '已上传 $completed ${assetType.unit}${assetType.label}'); tasks.clear(); isExpanded = false; _resetBatchProgress(); diff --git a/lib/upload_video/video_batch_upload_service.dart b/lib/upload_video/video_batch_upload_service.dart index 6c2aa4c..2d0cf39 100644 --- a/lib/upload_video/video_batch_upload_service.dart +++ b/lib/upload_video/video_batch_upload_service.dart @@ -13,12 +13,35 @@ class VideoBatchUploadPicker { static Future> pickVideos( BuildContext context, { int maxAssets = VideoBatchUploadConfig.maxAssets, + }) async { + return pickMedia( + context, + maxAssets: maxAssets, + assetType: VideoBatchUploadAssetType.video, + ); + } + + static Future> pickImages( + BuildContext context, { + int maxAssets = VideoBatchUploadConfig.maxAssets, + }) async { + return pickMedia( + context, + maxAssets: maxAssets, + assetType: VideoBatchUploadAssetType.image, + ); + } + + static Future> pickMedia( + BuildContext context, { + int maxAssets = VideoBatchUploadConfig.maxAssets, + VideoBatchUploadAssetType assetType = VideoBatchUploadAssetType.video, }) async { final List? assets = await AssetPicker.pickAssets( context, pickerConfig: AssetPickerConfig( maxAssets: maxAssets, - requestType: RequestType.video, + requestType: _requestType(assetType), ), ); if (assets == null || assets.isEmpty) { @@ -39,10 +62,12 @@ class VideoBatchUploadPicker { tasks.add( VideoBatchUploadTask( id: '${asset.id}_${DateTime.now().microsecondsSinceEpoch}', + assetType: assetType, file: file, - fileName: _normalizeFileName(asset.title, file.path), + fileName: _normalizeFileName(asset.title, file.path, assetType), fileSize: fileSize, - duration: asset.duration, + duration: + assetType == VideoBatchUploadAssetType.video ? asset.duration : 0, thumbnail: thumbnail, ), ); @@ -50,13 +75,26 @@ class VideoBatchUploadPicker { return tasks; } - static String _normalizeFileName(String? assetTitle, String path) { + static RequestType _requestType(VideoBatchUploadAssetType assetType) { + switch (assetType) { + case VideoBatchUploadAssetType.image: + return RequestType.image; + case VideoBatchUploadAssetType.video: + return RequestType.video; + } + } + + static String _normalizeFileName( + String? assetTitle, + String path, + VideoBatchUploadAssetType assetType, + ) { final String title = (assetTitle ?? '').trim(); if (title.isNotEmpty) { return title; } final List segments = path.split(Platform.pathSeparator); final String fileName = segments.isEmpty ? '' : segments.last.trim(); - return fileName.isEmpty ? 'video.mp4' : fileName; + return fileName.isEmpty ? assetType.defaultFileName : fileName; } } diff --git a/lib/upload_video/video_batch_upload_task.dart b/lib/upload_video/video_batch_upload_task.dart index 9e6357b..ddaa60d 100644 --- a/lib/upload_video/video_batch_upload_task.dart +++ b/lib/upload_video/video_batch_upload_task.dart @@ -14,6 +14,49 @@ typedef VideoBatchUploadSaveTask = Future Function( VideoBatchUploadTask task, ); +enum VideoBatchUploadAssetType { + image, + video, +} + +extension VideoBatchUploadAssetTypeText on VideoBatchUploadAssetType { + String get label { + switch (this) { + case VideoBatchUploadAssetType.image: + return '图片'; + case VideoBatchUploadAssetType.video: + return '视频'; + } + } + + String get unit { + switch (this) { + case VideoBatchUploadAssetType.image: + return '张'; + case VideoBatchUploadAssetType.video: + return '个'; + } + } + + String get localLabel { + switch (this) { + case VideoBatchUploadAssetType.image: + return '本地图片'; + case VideoBatchUploadAssetType.video: + return '本地视频'; + } + } + + String get defaultFileName { + switch (this) { + case VideoBatchUploadAssetType.image: + return 'image.jpg'; + case VideoBatchUploadAssetType.video: + return 'video.mp4'; + } + } +} + enum VideoBatchUploadStatus { waiting, uploading, @@ -45,6 +88,7 @@ extension VideoBatchUploadStatusText on VideoBatchUploadStatus { class VideoBatchUploadTask { VideoBatchUploadTask({ required this.id, + this.assetType = VideoBatchUploadAssetType.video, required this.file, required this.fileName, required this.fileSize, @@ -53,6 +97,7 @@ class VideoBatchUploadTask { }); final String id; + final VideoBatchUploadAssetType assetType; final File file; final String fileName; final int fileSize; @@ -120,4 +165,8 @@ class VideoBatchUploadTask { Map toLibraryVideoPayload() { return toVideoPayload(); } + + String toLibraryImageURL() { + return uploadUrl; + } } diff --git a/lib/upload_video/video_batch_upload_widgets.dart b/lib/upload_video/video_batch_upload_widgets.dart index 0d40476..e678db3 100644 --- a/lib/upload_video/video_batch_upload_widgets.dart +++ b/lib/upload_video/video_batch_upload_widgets.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'video_batch_upload_task.dart'; + class VideoBatchUploadBackButton extends StatelessWidget { const VideoBatchUploadBackButton({ super.key, @@ -28,11 +30,13 @@ class VideoBatchUploadIconButton extends StatelessWidget { const VideoBatchUploadIconButton({ super.key, required this.onTap, + this.assetType = VideoBatchUploadAssetType.video, this.iconSize, this.rightPadding, }); final VoidCallback onTap; + final VideoBatchUploadAssetType assetType; final double? iconSize; final double? rightPadding; @@ -43,7 +47,9 @@ class VideoBatchUploadIconButton extends StatelessWidget { child: Padding( padding: EdgeInsets.only(right: rightPadding ?? 30.w), child: Icon( - Icons.video_call_outlined, + assetType == VideoBatchUploadAssetType.video + ? Icons.video_call_outlined + : Icons.add_photo_alternate_outlined, size: iconSize ?? 50.sp, color: const Color(0xFF1D1D21), ), diff --git a/lib/upload_video/video_batch_uploader.dart b/lib/upload_video/video_batch_uploader.dart index cdc16f9..10964f9 100644 --- a/lib/upload_video/video_batch_uploader.dart +++ b/lib/upload_video/video_batch_uploader.dart @@ -14,6 +14,7 @@ class VideoBatchUploader { required BuildContext? Function() contextProvider, required VideoBatchUploadUploadTask uploadTask, required VideoBatchUploadSaveTask saveTask, + VideoBatchUploadAssetType assetType = VideoBatchUploadAssetType.video, VoidCallback? onChanged, VideoBatchUploadCallback? onCompleted, int? maxAssets, @@ -25,6 +26,7 @@ class VideoBatchUploader { uploadTask: uploadTask, saveTask: saveTask, onChanged: _handleChanged, + assetType: assetType, onCompleted: onCompleted, maxAssets: maxAssets ?? VideoBatchUploadConfig.maxAssets, maxConcurrent: maxConcurrent ?? VideoBatchUploadConfig.maxConcurrent, From a1b98e987e718f7dd3cf9b6c0e20ac3066961dbe Mon Sep 17 00:00:00 2001 From: wuxinglong Date: Fri, 29 May 2026 18:26:16 +0800 Subject: [PATCH 4/4] =?UTF-8?q?fix(upload=5Fimage):=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E5=AA=92=E4=BD=93=E4=B8=8A=E4=BC=A0=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../video_batch_upload_queue.dart | 71 ++++++++++++++++++- lib/upload_video/video_batch_upload_task.dart | 4 ++ lib/upload_video/video_batch_uploader.dart | 7 +- 3 files changed, 77 insertions(+), 5 deletions(-) diff --git a/lib/upload_video/video_batch_upload_queue.dart b/lib/upload_video/video_batch_upload_queue.dart index fa4d237..74b1d2b 100644 --- a/lib/upload_video/video_batch_upload_queue.dart +++ b/lib/upload_video/video_batch_upload_queue.dart @@ -12,7 +12,8 @@ class VideoBatchUploadQueue { VideoBatchUploadQueue({ required this.contextProvider, required this.uploadTask, - required this.saveTask, + this.saveTask, + this.batchSaveTask, required this.onChanged, this.assetType = VideoBatchUploadAssetType.video, this.onCompleted, @@ -22,7 +23,8 @@ class VideoBatchUploadQueue { final BuildContext? Function() contextProvider; final VideoBatchUploadUploadTask uploadTask; - final VideoBatchUploadSaveTask saveTask; + final VideoBatchUploadSaveTask? saveTask; + final VideoBatchUploadBatchSaveTask? batchSaveTask; final VoidCallback onChanged; final VideoBatchUploadAssetType assetType; final FutureOr Function()? onCompleted; @@ -58,6 +60,8 @@ class VideoBatchUploadQueue { int get finishedCount => _completedRemovedCount + completedCount + failedCount; + bool get _usesBatchSave => batchSaveTask != null; + Future pickAndStart() async { if (hasActiveUploads) { isExpanded = true; @@ -195,6 +199,7 @@ class VideoBatchUploadQueue { ); await Future.wait(workers); _isRunning = false; + await _saveUploadedBatchIfNeeded(); await _notifyCompletedIfNeeded(); } @@ -251,9 +256,13 @@ class VideoBatchUploadQueue { ..status = VideoBatchUploadStatus.uploaded; _notifyChanged(); + if (_usesBatchSave) { + return; + } + task.status = VideoBatchUploadStatus.saving; _notifyChanged(); - final bool saved = await saveTask(task); + final bool saved = await saveTask!(task); if (!tasks.contains(task)) { return; } @@ -290,6 +299,62 @@ class VideoBatchUploadQueue { } } + Future _saveUploadedBatchIfNeeded() async { + if (!_usesBatchSave || _isDisposed) { + return; + } + final List successfulUploadTasks = tasks + .where((VideoBatchUploadTask task) => + task.status == VideoBatchUploadStatus.uploaded) + .toList(); + if (successfulUploadTasks.isEmpty) { + return; + } + + for (final VideoBatchUploadTask task in successfulUploadTasks) { + task.status = VideoBatchUploadStatus.saving; + } + _notifyChanged(); + + try { + final bool saved = await batchSaveTask!(List.of( + successfulUploadTasks, + growable: false, + )); + if (_isDisposed) { + return; + } + if (saved) { + _completedRemovedCount += successfulUploadTasks.length; + tasks.removeWhere(successfulUploadTasks.contains); + if (tasks.isEmpty) { + isExpanded = false; + } + return; + } + for (final VideoBatchUploadTask task in successfulUploadTasks) { + if (tasks.contains(task)) { + task + ..status = VideoBatchUploadStatus.failed + ..errorMessage = '入库失败'; + } + } + } catch (_) { + if (_isDisposed) { + return; + } + for (final VideoBatchUploadTask task in successfulUploadTasks) { + if (tasks.contains(task)) { + task + ..status = VideoBatchUploadStatus.failed + ..errorMessage = '入库失败'; + } + } + } finally { + _notifyChanged(); + } + } + String _networkErrorText(DioException error) { switch (error.type) { case DioExceptionType.connectionTimeout: diff --git a/lib/upload_video/video_batch_upload_task.dart b/lib/upload_video/video_batch_upload_task.dart index ddaa60d..35267ef 100644 --- a/lib/upload_video/video_batch_upload_task.dart +++ b/lib/upload_video/video_batch_upload_task.dart @@ -14,6 +14,10 @@ typedef VideoBatchUploadSaveTask = Future Function( VideoBatchUploadTask task, ); +typedef VideoBatchUploadBatchSaveTask = Future Function( + List tasks, +); + enum VideoBatchUploadAssetType { image, video, diff --git a/lib/upload_video/video_batch_uploader.dart b/lib/upload_video/video_batch_uploader.dart index 10964f9..d7c5c5c 100644 --- a/lib/upload_video/video_batch_uploader.dart +++ b/lib/upload_video/video_batch_uploader.dart @@ -13,18 +13,21 @@ class VideoBatchUploader { VideoBatchUploader({ required BuildContext? Function() contextProvider, required VideoBatchUploadUploadTask uploadTask, - required VideoBatchUploadSaveTask saveTask, + VideoBatchUploadSaveTask? saveTask, + VideoBatchUploadBatchSaveTask? batchSaveTask, VideoBatchUploadAssetType assetType = VideoBatchUploadAssetType.video, VoidCallback? onChanged, VideoBatchUploadCallback? onCompleted, int? maxAssets, int? maxConcurrent, - }) : _contextProvider = contextProvider, + }) : assert(saveTask != null || batchSaveTask != null), + _contextProvider = contextProvider, _onChanged = onChanged { queue = VideoBatchUploadQueue( contextProvider: contextProvider, uploadTask: uploadTask, saveTask: saveTask, + batchSaveTask: batchSaveTask, onChanged: _handleChanged, assetType: assetType, onCompleted: onCompleted,