From 9a63cbe8483c96bee2de613f64482f2178a5b961 Mon Sep 17 00:00:00 2001 From: Knot Date: Tue, 16 Apr 2024 17:51:06 +0700 Subject: [PATCH] add lints, add lunch.json for VSCode to easy run example project --- .vscode/launch.json | 12 + .vscode/settings.json | 8 + analysis_options.yaml | 25 ++ example/ios/Flutter/AppFrameworkInfo.plist | 2 +- example/ios/Podfile | 2 +- example/ios/Runner.xcodeproj/project.pbxproj | 26 ++- .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- example/lib/dialog.dart | 216 ++++++++++-------- example/lib/main.dart | 170 ++++++++------ example/lib/utils.dart | 23 +- example/pubspec.yaml | 65 +----- example/test/widget_test.dart | 2 +- lib/image_gallery_saver.dart | 50 ++-- pubspec.yaml | 1 + test/image_gallery_saver_test.dart | 26 +-- 15 files changed, 348 insertions(+), 282 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 analysis_options.yaml diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3fa60e5 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,12 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Debug", + "request": "launch", + "type": "dart", + "program": "example/lib/main.dart", + "flutterMode": "debug", + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..c23472f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "[dart]": { + "editor.formatOnSave": true + }, + "editor.codeActionsOnSave": { + "source.organizeImports": "explicit" + } +} diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..ceb6ab0 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,25 @@ +include: package:flutter_lints/flutter.yaml + +linter: + rules: + always_use_package_imports: true + always_declare_return_types: true + avoid_print: true + prefer_is_empty: true + prefer_is_not_empty: true + prefer_is_not_operator: true + require_trailing_commas: true + unnecessary_overrides: false + avoid_function_literals_in_foreach_calls: false + depend_on_referenced_packages: false + +analyzer: + errors: + always_use_package_imports: error + always_declare_return_types: error + avoid_print: error + prefer_is_empty: error + prefer_is_not_empty: error + prefer_is_not_operator: error + require_trailing_commas: error + invalid_use_of_protected_member: ignore \ No newline at end of file diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist index 9625e10..7c56964 100644 --- a/example/ios/Flutter/AppFrameworkInfo.plist +++ b/example/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 11.0 + 12.0 diff --git a/example/ios/Podfile b/example/ios/Podfile index 50bb0cf..6656b4d 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '11.0' +# platform :ios, '12.0' # source '源地址' source 'https://github.com/CocoaPods/Specs.git' diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 9e53bc2..beb4dc3 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -139,6 +139,7 @@ 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 74E1176F028703D33774BD4F /* [CP] Embed Pods Frameworks */, + 58D7E035431BBB5EEAC7DC10 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -155,7 +156,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { @@ -235,6 +236,23 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; + 58D7E035431BBB5EEAC7DC10 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; 74E1176F028703D33774BD4F /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -342,7 +360,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -420,7 +438,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -469,7 +487,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index c87d15a..5e31d3d 100644 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ show( - {required BuildContext context, - String title = '温馨提示', - String? content, - bool barrierDismissible = true, - Color? barrierColor = Colors.black54, - bool? useSafeArea, - bool? useRootNavigator, - Widget? contentWidget, - List options = const [DialogAction(text: '知道了')]}) { + static Future show({ + required BuildContext context, + String title = '温馨提示', + String? content, + bool barrierDismissible = true, + Color? barrierColor = Colors.black54, + bool? useSafeArea, + bool? useRootNavigator, + Widget? contentWidget, + List options = const [DialogAction(text: '知道了')], + }) { return showDialog( - context: context, - barrierDismissible: barrierDismissible, - barrierColor: barrierColor, - useSafeArea: useSafeArea ?? true, - useRootNavigator: useRootNavigator ?? true, - builder: (BuildContext context) => HDialogWidget( - title: title, - content: content, - contentWidget: contentWidget, - options: options, - isSheetStyle: false, - )); + context: context, + barrierDismissible: barrierDismissible, + barrierColor: barrierColor, + useSafeArea: useSafeArea ?? true, + useRootNavigator: useRootNavigator ?? true, + builder: (BuildContext context) => HDialogWidget( + title: title, + content: content, + contentWidget: contentWidget, + options: options, + isSheetStyle: false, + ), + ); } } @@ -40,12 +41,13 @@ class DialogAction { final T? actionValue; final VoidCallback? onPressed; - const DialogAction( - {this.text, - this.type = ActionType.positive, - this.child, - this.actionValue, - this.onPressed}); + const DialogAction({ + this.text, + this.type = ActionType.positive, + this.child, + this.actionValue, + this.onPressed, + }); } enum ActionType { delete, positive, negative } @@ -71,54 +73,60 @@ class HDialogWidget extends StatelessWidget { final DialogAction? bottomSheetCancel; final bool isSheetStyle; - const HDialogWidget( - {Key? key, - this.title, - this.content, - this.contentWidget, - this.options = const [], - this.bottomSheetCancel, - this.isSheetStyle = false}) - : super(key: key); + const HDialogWidget({ + super.key, + this.title, + this.content, + this.contentWidget, + this.options = const [], + this.bottomSheetCancel, + this.isSheetStyle = false, + }); @override Widget build(BuildContext context) { if (Platform.isIOS) { return createIOSDialog( - content: content, - contentWidget: contentWidget, - title: title, - context: context, - options: options); + content: content, + contentWidget: contentWidget, + title: title, + context: context, + options: options, + ); } else { return createAndroidDialog( - content: content, - contentWidget: contentWidget, - title: title, - context: context, - options: options); + content: content, + contentWidget: contentWidget, + title: title, + context: context, + options: options, + ); } } - AlertDialog createAndroidDialog( - {required BuildContext context, - String? title, - String? content, - required List> options, - Widget? contentWidget}) { + AlertDialog createAndroidDialog({ + required BuildContext context, + String? title, + String? content, + required List> options, + Widget? contentWidget, + }) { final actions = options.map((option) { return CupertinoButton( - onPressed: () { - Navigator.pop(context, option.actionValue); - if (option.onPressed != null) option.onPressed!(); - }, - child: option.child ?? - Text(option.text ?? '', - style: TextStyle(color: _getActionColor(option.type)))); + onPressed: () { + Navigator.pop(context, option.actionValue); + if (option.onPressed != null) option.onPressed!(); + }, + child: option.child ?? + Text( + option.text ?? '', + style: TextStyle(color: _getActionColor(option.type)), + ), + ); }).toList(); final dialog = AlertDialog( - title: title==null ? null : Text(title), - content: contentWidget != null && content==null + title: title == null ? null : Text(title), + content: contentWidget != null && content == null ? contentWidget : Text(content ?? ''), actions: actions, @@ -126,12 +134,13 @@ class HDialogWidget extends StatelessWidget { return dialog; } - Widget createIOSDialog( - {required BuildContext context, - String? title, - String? content, - Widget? contentWidget, - required List> options}) { + Widget createIOSDialog({ + required BuildContext context, + String? title, + String? content, + Widget? contentWidget, + required List> options, + }) { final actions = options.map((option) { return CupertinoButton( onPressed: () { @@ -139,12 +148,14 @@ class HDialogWidget extends StatelessWidget { if (option.onPressed != null) option.onPressed!(); }, child: option.child ?? - Text(option.text ?? '', - style: TextStyle(color: _getActionColor(option.type))), + Text( + option.text ?? '', + style: TextStyle(color: _getActionColor(option.type)), + ), ); }).toList(); return CupertinoAlertDialog( - title: title==null ? null : Text(title), + title: title == null ? null : Text(title), content: contentWidget != null && content == null ? contentWidget : Text(content ?? ''), @@ -152,43 +163,52 @@ class HDialogWidget extends StatelessWidget { ); } - Widget createIOSSheetDialog( - {required BuildContext context, - String? title, - String? content, - Widget? contentWidget, - required List> options, - DialogAction? bottomSheetCancel}) { + Widget createIOSSheetDialog({ + required BuildContext context, + String? title, + String? content, + Widget? contentWidget, + required List> options, + DialogAction? bottomSheetCancel, + }) { final actions = options.map((option) { return CupertinoActionSheetAction( - onPressed: () { - Navigator.pop(context, option.actionValue); - if (option.onPressed != null) option.onPressed!(); - }, - child: option.child ?? - Text(option.text ?? '', - style: TextStyle(color: _getActionColor(option.type)))); + onPressed: () { + Navigator.pop(context, option.actionValue); + if (option.onPressed != null) option.onPressed!(); + }, + child: option.child ?? + Text( + option.text ?? '', + style: TextStyle(color: _getActionColor(option.type)), + ), + ); }).toList(); final cancelButton = bottomSheetCancel == null ? null : CupertinoActionSheetAction( onPressed: () { Navigator.pop(context, bottomSheetCancel.actionValue); - if (bottomSheetCancel.onPressed != null) + if (bottomSheetCancel.onPressed != null) { bottomSheetCancel.onPressed!(); + } }, isDefaultAction: true, child: bottomSheetCancel.child ?? - Text(bottomSheetCancel.text ?? '', - style: TextStyle( - color: _getActionColor(bottomSheetCancel.type))), + Text( + bottomSheetCancel.text ?? '', + style: TextStyle( + color: _getActionColor(bottomSheetCancel.type), + ), + ), ); return CupertinoActionSheet( - title: title==null ? null : Text(title), - message: contentWidget != null && content==null - ? contentWidget - : Text(content ?? ''), - actions: actions, - cancelButton: cancelButton); + title: title == null ? null : Text(title), + message: contentWidget != null && content == null + ? contentWidget + : Text(content ?? ''), + actions: actions, + cancelButton: cancelButton, + ); } -} \ No newline at end of file +} diff --git a/example/lib/main.dart b/example/lib/main.dart index 6c5c87d..01a8258 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,17 +1,18 @@ -import 'dart:typed_data'; import 'dart:ui' as ui; import 'package:dio/dio.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:image_gallery_saver/image_gallery_saver.dart'; +import 'package:image_gallery_saver_example/utils.dart'; import 'package:path_provider/path_provider.dart'; -import 'utils.dart'; - -void main() => runApp(MyApp()); +void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { + const MyApp({super.key}); + @override Widget build(BuildContext context) { return MaterialApp( @@ -19,18 +20,20 @@ class MyApp extends StatelessWidget { theme: ThemeData( primarySwatch: Colors.blue, ), - home: MyHomePage(), + home: const MyHomePage(), ); } } class MyHomePage extends StatefulWidget { + const MyHomePage({super.key}); + @override - _MyHomePageState createState() => _MyHomePageState(); + State createState() => _MyHomePageState(); } class _MyHomePageState extends State { - GlobalKey _globalKey = GlobalKey(); + final GlobalKey _globalKey = GlobalKey(); @override void initState() { @@ -41,64 +44,65 @@ class _MyHomePageState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar( - title: Text("Save image to gallery"), - ), - body: Center( - child: Column( - children: [ - SizedBox(height: 15), - RepaintBoundary( - key: _globalKey, - child: Container( - alignment: Alignment.center, - width: 300, - height: 300, - color: Colors.blue, - ), - ), - Container( - padding: EdgeInsets.only(top: 15), - child: ElevatedButton( - onPressed: _saveLocalImage, - child: Text("Save Local Image"), - ), + appBar: AppBar( + title: const Text("Save image to gallery"), + ), + body: Center( + child: Column( + children: [ + const SizedBox(height: 15), + RepaintBoundary( + key: _globalKey, + child: Container( + alignment: Alignment.center, width: 300, - height: 44, + height: 300, + color: Colors.blue, ), - Container( - padding: EdgeInsets.only(top: 15), - child: ElevatedButton( - onPressed: _saveNetworkImage, - child: Text("Save Network Image"), - ), - width: 300, - height: 44, + ), + Container( + padding: const EdgeInsets.only(top: 15), + width: 300, + height: 44, + child: ElevatedButton( + onPressed: _saveLocalImage, + child: const Text("Save Local Image"), ), - Container( - padding: EdgeInsets.only(top: 15), - child: ElevatedButton( - onPressed: _saveNetworkGifFile, - child: Text("Save Network Gif Image"), - ), - width: 300, - height: 44, + ), + Container( + padding: const EdgeInsets.only(top: 15), + width: 300, + height: 44, + child: ElevatedButton( + onPressed: _saveNetworkImage, + child: const Text("Save Network Image"), ), - Container( - padding: EdgeInsets.only(top: 15), - child: ElevatedButton( - onPressed: _saveNetworkVideoFile, - child: Text("Save Network Video"), - ), - width: 300, - height: 44, + ), + Container( + padding: const EdgeInsets.only(top: 15), + width: 300, + height: 44, + child: ElevatedButton( + onPressed: _saveNetworkGifFile, + child: const Text("Save Network Gif Image"), ), - ], - ), - )); + ), + Container( + padding: const EdgeInsets.only(top: 15), + width: 300, + height: 44, + child: ElevatedButton( + onPressed: _saveNetworkVideoFile, + child: const Text("Save Network Video"), + ), + ), + ], + ), + ), + ); } - _saveLocalImage() async { + void _saveLocalImage() async { RenderRepaintBoundary boundary = _globalKey.currentContext!.findRenderObject() as RenderRepaintBoundary; ui.Image image = await boundary.toImage(); @@ -107,45 +111,61 @@ class _MyHomePageState extends State { if (byteData != null) { final result = await ImageGallerySaver.saveImage(byteData.buffer.asUint8List()); - print(result); + if (kDebugMode) { + print(result); + } Utils.toast(result.toString()); } } - _saveNetworkImage() async { + void _saveNetworkImage() async { var response = await Dio().get( - "https://ss0.baidu.com/94o3dSag_xI4khGko9WTAnF6hhy/image/h%3D300/sign=a62e824376d98d1069d40a31113eb807/838ba61ea8d3fd1fc9c7b6853a4e251f94ca5f46.jpg", - options: Options(responseType: ResponseType.bytes)); + "https://ss0.baidu.com/94o3dSag_xI4khGko9WTAnF6hhy/image/h%3D300/sign=a62e824376d98d1069d40a31113eb807/838ba61ea8d3fd1fc9c7b6853a4e251f94ca5f46.jpg", + options: Options(responseType: ResponseType.bytes), + ); final result = await ImageGallerySaver.saveImage( - Uint8List.fromList(response.data), - quality: 60, - name: "hello"); - print(result); + Uint8List.fromList(response.data), + quality: 60, + name: "hello", + ); + if (kDebugMode) { + print(result); + } Utils.toast("$result"); } - _saveNetworkGifFile() async { + void _saveNetworkGifFile() async { var appDocDir = await getTemporaryDirectory(); - String savePath = appDocDir.path + "/temp.gif"; + String savePath = "${appDocDir.path}/temp.gif"; String fileUrl = "https://hyjdoc.oss-cn-beijing.aliyuncs.com/hyj-doc-flutter-demo-run.gif"; await Dio().download(fileUrl, savePath); final result = await ImageGallerySaver.saveFile(savePath, isReturnPathOfIOS: true); - print(result); + if (kDebugMode) { + print(result); + } Utils.toast("$result"); } - _saveNetworkVideoFile() async { + void _saveNetworkVideoFile() async { var appDocDir = await getTemporaryDirectory(); - String savePath = appDocDir.path + "/temp.mp4"; + String savePath = "${appDocDir.path}/temp.mp4"; String fileUrl = "https://s3.cn-north-1.amazonaws.com.cn/mtab.kezaihui.com/video/ForBiggerBlazes.mp4"; - await Dio().download(fileUrl, savePath, onReceiveProgress: (count, total) { - print((count / total * 100).toStringAsFixed(0) + "%"); - }); + await Dio().download( + fileUrl, + savePath, + onReceiveProgress: (count, total) { + if (kDebugMode) { + print("${(count / total * 100).toStringAsFixed(0)}%"); + } + }, + ); final result = await ImageGallerySaver.saveFile(savePath); - print(result); + if (kDebugMode) { + print(result); + } Utils.toast("$result"); } } diff --git a/example/lib/utils.dart b/example/lib/utils.dart index e22e5a6..07cefb9 100644 --- a/example/lib/utils.dart +++ b/example/lib/utils.dart @@ -2,10 +2,9 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; +import 'package:image_gallery_saver_example/dialog.dart'; import 'package:permission_handler/permission_handler.dart'; -import 'dialog.dart'; - class Utils { static void toast(String msg) { Fluttertoast.showToast( @@ -24,13 +23,13 @@ class PermissionUtil { /// 安卓权限 static List androidPermissions = [ // 在这里添加需要的权限 - Permission.storage + Permission.storage, ]; /// ios权限 static List iosPermissions = [ // 在这里添加需要的权限 - Permission.storage + Permission.storage, ]; static Future> requestAll() async { @@ -41,7 +40,8 @@ class PermissionUtil { } static Future> request( - Permission permission) async { + Permission permission, + ) async { final List permissions = [permission]; return await permissions.request(); } @@ -59,12 +59,13 @@ class PermissionUtil { static void showDeniedDialog(BuildContext context) { HDialog.show( - context: context, - title: '权限申请异常', - content: '请在【应用信息】-【权限管理】中,开启全部所需权限,以正常使用惠爆单功能', - options: [ - DialogAction(text: '去设置', onPressed: () => openAppSettings()) - ]); + context: context, + title: '权限申请异常', + content: '请在【应用信息】-【权限管理】中,开启全部所需权限,以正常使用惠爆单功能', + options: [ + DialogAction(text: '去设置', onPressed: () => openAppSettings()), + ], + ); } /// 检查权限 diff --git a/example/pubspec.yaml b/example/pubspec.yaml index beb6049..069992b 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,73 +1,26 @@ name: image_gallery_saver_example -description: Demonstrates how to use the image_gallery_saver plugin. - -# The following defines the version and build number for your application. -# A version number is three numbers separated by dots, like 1.2.43 -# followed by an optional build number separated by a +. -# Both the version and the builder number may be overridden in flutter -# build by specifying --build-name and --build-number, respectively. -# Read more about versioning at semver.org. version: 2.0.3+3 - +publish_to: none +description: Demonstrates how to use the image_gallery_saver plugin. environment: sdk: '>=2.19.6 <4.0.0' dependencies: flutter: sdk: flutter - - permission_handler: ^10.3.0 - fluttertoast: ^8.2.2 - path_provider: ^2.0.15 - dio: ^5.2.1+1 - + cupertino_icons: ^1.0.6 + dio: ^5.4.3 + fluttertoast: ^8.2.5 + path_provider: ^2.1.3 + permission_handler: ^11.3.1 image_gallery_saver: path: ../ - cupertino_icons: ^1.0.5 + dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^2.0.1 + flutter_lints: ^3.0.2 -# For information on the generic Dart part of this file, see the -# following page: https://www.dartlang.org/tools/pub/pubspec - -# The following section is specific to Flutter. flutter: - - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. uses-material-design: true - - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.io/assets-and-images/#resolution-aware. - - # For details regarding adding assets from package dependencies, see - # https://flutter.io/assets-and-images/#from-packages - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.io/custom-fonts/#from-packages diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart index 95fbd2f..f04597d 100644 --- a/example/test/widget_test.dart +++ b/example/test/widget_test.dart @@ -5,7 +5,7 @@ import 'package:image_gallery_saver_example/main.dart'; void main() { testWidgets('Verify Widgets', (WidgetTester tester) async { // Build our app and trigger a frame. - await tester.pumpWidget(new MyApp()); + await tester.pumpWidget(const MyApp()); final Finder flatButtonPass = find.widgetWithText(ElevatedButton, '保存屏幕截图'); expect(flatButtonPass, findsOneWidget); }); diff --git a/lib/image_gallery_saver.dart b/lib/image_gallery_saver.dart index 96deea1..2501bcf 100644 --- a/lib/image_gallery_saver.dart +++ b/lib/image_gallery_saver.dart @@ -3,36 +3,44 @@ import 'dart:async'; import 'package:flutter/services.dart'; class ImageGallerySaver { - static const MethodChannel _channel = - const MethodChannel('image_gallery_saver'); + static const MethodChannel _channel = MethodChannel('image_gallery_saver'); /// save image to Gallery /// imageBytes can't null /// return Map type - /// for example:{"isSuccess":true, "filePath":String?} - static FutureOr saveImage(Uint8List imageBytes, - {int quality = 100, - String? name, - bool isReturnImagePathOfIOS = false}) async { - final result = - await _channel.invokeMethod('saveImageToGallery', { - 'imageBytes': imageBytes, - 'quality': quality, - 'name': name, - 'isReturnImagePathOfIOS': isReturnImagePathOfIOS - }); + /// for example: `{"isSuccess":true, "filePath":String?}` + static FutureOr saveImage( + Uint8List imageBytes, { + int quality = 100, + String? name, + bool isReturnImagePathOfIOS = false, + }) async { + final result = await _channel.invokeMethod( + 'saveImageToGallery', + { + 'imageBytes': imageBytes, + 'quality': quality, + 'name': name, + 'isReturnImagePathOfIOS': isReturnImagePathOfIOS, + }, + ); return result; } /// Save the PNG,JPG,JPEG image or video located at [file] to the local device media gallery. - static Future saveFile(String file, - {String? name, bool isReturnPathOfIOS = false}) async { + static Future saveFile( + String file, { + String? name, + bool isReturnPathOfIOS = false, + }) async { final result = await _channel.invokeMethod( - 'saveFileToGallery', { - 'file': file, - 'name': name, - 'isReturnPathOfIOS': isReturnPathOfIOS - }); + 'saveFileToGallery', + { + 'file': file, + 'name': name, + 'isReturnPathOfIOS': isReturnPathOfIOS, + }, + ); return result; } } diff --git a/pubspec.yaml b/pubspec.yaml index 9ca1581..6847391 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -28,4 +28,5 @@ flutter: dev_dependencies: flutter_test: sdk: flutter + flutter_lints: ">=3.0.0 <4.0.0" diff --git a/test/image_gallery_saver_test.dart b/test/image_gallery_saver_test.dart index 5faca52..aad7b13 100644 --- a/test/image_gallery_saver_test.dart +++ b/test/image_gallery_saver_test.dart @@ -1,5 +1,3 @@ -import 'dart:async'; -import 'dart:typed_data'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:image_gallery_saver/image_gallery_saver.dart'; @@ -11,8 +9,9 @@ void main() { final List log = []; bool? response; - channel.setMockMethodCallHandler((MethodCall methodCall) async { - log.add(methodCall); + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(channel, (message) async { + log.add(message); return response; }); @@ -20,23 +19,24 @@ void main() { log.clear(); }); - test('saveImageToGallery test', () async { response = true; Uint8List imageBytes = Uint8List(16); - final bool? result = await (ImageGallerySaver.saveImage(imageBytes) as FutureOr); + final bool? result = await ImageGallerySaver.saveImage(imageBytes); expect( log, [ - isMethodCall('saveImageToGallery', arguments: { - 'imageBytes': imageBytes, - 'quality': 80, - 'name': null, - "isReturnImagePathOfIOS": false - }) + isMethodCall( + 'saveImageToGallery', + arguments: { + 'imageBytes': imageBytes, + 'quality': 100, + 'name': null, + "isReturnImagePathOfIOS": false, + }, + ), ], ); expect(result, response); }); - }