From 006cb1ed53f969bf11816cde5b16dd520e1ee40e Mon Sep 17 00:00:00 2001 From: OutdatedGuy Date: Fri, 29 Dec 2023 23:09:01 +0530 Subject: [PATCH] feat: added support for android 13+ themed icons (#497) * feat: added support for android 13+ themed icons * fix: linting and analyzer issues --- README.md | 2 + analysis_options.yaml | 7 +- bin/generate.dart | 1 + .../assets/images/icon-monochrome-432x432.png | Bin 0 -> 8426 bytes example/default_example/pubspec.yaml | 1 + lib/android.dart | 115 +++++++++++------- lib/config/config.dart | 12 +- lib/config/config.g.dart | 4 + lib/constants.dart | 1 + lib/ios.dart | 6 +- lib/main.dart | 12 ++ lib/xml_templates.dart | 14 +-- test/abs/icon_generator_test.mocks.dart | 7 +- test/android_test.dart | 6 +- .../macos_icon_generator_test.mocks.dart | 8 +- test/main_test.dart | 18 +-- test/templates.dart | 4 + test/web/web_icon_generator_test.dart | 2 +- test/web/web_template_test.dart | 4 +- .../windows_icon_generator_test.mocks.dart | 7 +- 20 files changed, 149 insertions(+), 82 deletions(-) create mode 100644 example/default_example/assets/images/icon-monochrome-432x432.png diff --git a/README.md b/README.md index b094fab868..0650989eab 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,8 @@ Shown below is the full list of attributes which you can specify within your Flu be used to fill out the background of the adaptive icon. - `adaptive_icon_foreground`: The image asset which will be used for the icon foreground of the adaptive icon *Note: Adaptive Icons will only be generated when both adaptive_icon_background and adaptive_icon_foreground are specified. (the image_path is not automatically taken as foreground)* +- `adaptive_icon_monochrome`: The image asset which will be used for the icon +foreground of the Android 13+ themed icon. For more information see [Android Adaptive Icons](https://developer.android.com/develop/ui/views/launch/icon_design_adaptive#user-theming) ### IOS diff --git a/analysis_options.yaml b/analysis_options.yaml index 1421ef5bcb..37f1c95755 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -8,10 +8,6 @@ analyzer: missing_return: warning # allow having TODOs in the code todo: ignore - # Ignore analyzer hints for updating pubspecs when using Future or - # Stream and not importing dart:async - # Please see https://github.com/flutter/flutter/pull/24528 for details. - sdk_version_async_exported_from_core: ignore exclude: - "bin/cache/**" # the following two are relative to the stocks example and the flutter package respectively @@ -55,10 +51,9 @@ linter: - flutter_style_todos - hash_and_equals - implementation_imports - - iterable_contains_unrelated_type + - collection_methods_unrelated_type - library_names - library_prefixes - - list_remove_unrelated_type - no_adjacent_strings_in_list - no_duplicate_case_values - non_constant_identifier_names diff --git a/bin/generate.dart b/bin/generate.dart index 7f52e5cec5..b7772d7827 100644 --- a/bin/generate.dart +++ b/bin/generate.dart @@ -91,6 +91,7 @@ flutter_launcher_icons: min_sdk_android: 21 # android min sdk min:16, default 21 # adaptive_icon_background: "assets/icon/background.png" # adaptive_icon_foreground: "assets/icon/foreground.png" + # adaptive_icon_monochrome: "assets/icon/monochrome.png" ios: true # image_path_ios: "assets/icon/icon.png" diff --git a/example/default_example/assets/images/icon-monochrome-432x432.png b/example/default_example/assets/images/icon-monochrome-432x432.png new file mode 100644 index 0000000000000000000000000000000000000000..7a070224144390583746e8c50b53bf1f71dc2626 GIT binary patch literal 8426 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 literal 0 HcmV?d00001 diff --git a/example/default_example/pubspec.yaml b/example/default_example/pubspec.yaml index c7d4046e7d..b3aab90ccd 100644 --- a/example/default_example/pubspec.yaml +++ b/example/default_example/pubspec.yaml @@ -21,6 +21,7 @@ flutter_launcher_icons: ios: true # can specify file name here e.g. "My-Launcher-Icon" adaptive_icon_background: "assets/images/christmas-background.png" # only available for Android 8.0 devices and above adaptive_icon_foreground: "assets/images/icon-foreground-432x432.png" # only available for Android 8.0 devices and above + adaptive_icon_monochrome: "assets/images/icon-monochrome-432x432.png" # only available for Android 13 devices and above min_sdk_android: 21 # android min sdk min:16, default 21 remove_alpha_ios: true background_color_ios: "#ffffff" diff --git a/lib/android.dart b/lib/android.dart index a94d7ae773..a9e8327b9a 100644 --- a/lib/android.dart +++ b/lib/android.dart @@ -123,11 +123,83 @@ void createAdaptiveIcons( flavor, ); } else { - createAdaptiveIconMipmapXmlFile(config, flavor); updateColorsXmlFile(backgroundConfig, flavor); } } +void createAdaptiveMonochromeIcons( + Config config, + String? flavor, +) { + utils.printStatus('Creating adaptive monochrome icons Android'); + + // Retrieve the necessary Flutter Launcher Icons configuration from the pubspec.yaml file + final String? monochromeImagePath = config.adaptiveIconMonochrome; + if (monochromeImagePath == null) { + throw const InvalidConfigException(errorMissingImagePath); + } + final Image? monochromeImage = utils.decodeImageFile(monochromeImagePath); + if (monochromeImage == null) { + return; + } + + // Create adaptive icon monochrome images + for (AndroidIconTemplate androidIcon in adaptiveForegroundIcons) { + overwriteExistingIcons( + androidIcon, + monochromeImage, + constants.androidAdaptiveMonochromeFileName, + flavor, + ); + } +} + +void createMipmapXmlFile( + Config config, + String? flavor, +) { + utils.printStatus('Creating mipmap xml file Android'); + + String xmlContent = ''; + + if (config.hasAndroidAdaptiveConfig) { + if (isAdaptiveIconConfigPngFile(config.adaptiveIconBackground!)) { + xmlContent += + ' \n'; + } else { + xmlContent += + ' \n'; + } + + xmlContent += + ' \n'; + } + + if (config.hasAndroidAdaptiveMonochromeConfig) { + xmlContent += + ' \n'; + } + + late File mipmapXmlFile; + if (config.isCustomAndroidFile) { + mipmapXmlFile = File( + constants.androidAdaptiveXmlFolder(flavor) + config.android + '.xml', + ); + } else { + mipmapXmlFile = File( + constants.androidAdaptiveXmlFolder(flavor) + + constants.androidDefaultIconName + + '.xml', + ); + } + + mipmapXmlFile.create(recursive: true).then((File adaptiveIconFile) { + adaptiveIconFile.writeAsString( + xml_template.mipmapXmlFile.replaceAll('{{CONTENT}}', xmlContent), + ); + }); +} + /// Retrieves the colors.xml file for the project. /// /// If the colors.xml file is found, it is updated with a new color item for the @@ -151,29 +223,6 @@ void updateColorsXmlFile(String backgroundConfig, String? flavor) { } } -/// Creates the xml file required for the adaptive launcher icon -/// FILE LOCATED HERE: res/mipmap-anydpi/{icon-name-from-yaml-config}.xml -void createAdaptiveIconMipmapXmlFile( - Config config, - String? flavor, -) { - if (config.isCustomAndroidFile) { - File( - constants.androidAdaptiveXmlFolder(flavor) + config.android + '.xml', - ).create(recursive: true).then((File adaptiveIcon) { - adaptiveIcon.writeAsString(xml_template.icLauncherXml); - }); - } else { - File( - constants.androidAdaptiveXmlFolder(flavor) + - constants.androidDefaultIconName + - '.xml', - ).create(recursive: true).then((File adaptiveIcon) { - adaptiveIcon.writeAsString(xml_template.icLauncherXml); - }); - } -} - /// creates adaptive background using png image void _createAdaptiveBackgrounds( Config config, @@ -196,24 +245,6 @@ void _createAdaptiveBackgrounds( flavor, ); } - - // Creates the xml file required for the adaptive launcher icon - // FILE LOCATED HERE: res/mipmap-anydpi/{icon-name-from-yaml-config}.xml - if (config.isCustomAndroidFile) { - File( - constants.androidAdaptiveXmlFolder(flavor) + config.android + '.xml', - ).create(recursive: true).then((File adaptiveIcon) { - adaptiveIcon.writeAsString(xml_template.icLauncherDrawableBackgroundXml); - }); - } else { - File( - constants.androidAdaptiveXmlFolder(flavor) + - constants.androidDefaultIconName + - '.xml', - ).create(recursive: true).then((File adaptiveIcon) { - adaptiveIcon.writeAsString(xml_template.icLauncherDrawableBackgroundXml); - }); - } } /// Creates a colors.xml file if it was missing from android/app/src/main/res/values/colors.xml diff --git a/lib/config/config.dart b/lib/config/config.dart index db28cc559d..ba03809b68 100644 --- a/lib/config/config.dart +++ b/lib/config/config.dart @@ -27,6 +27,7 @@ class Config { this.imagePathIOS, this.adaptiveIconForeground, this.adaptiveIconBackground, + this.adaptiveIconMonochrome, this.minSdkAndroid = constants.androidDefaultAndroidMinSDK, this.removeAlphaIOS = false, this.backgroundColorIOS = '#ffffff', @@ -116,7 +117,7 @@ class Config { @JsonKey(name: 'image_path_ios') final String? imagePathIOS; - /// android adaptive icon foreground image + /// android adaptive_icon_foreground image @JsonKey(name: 'adaptive_icon_foreground') final String? adaptiveIconForeground; @@ -124,6 +125,10 @@ class Config { @JsonKey(name: 'adaptive_icon_background') final String? adaptiveIconBackground; + /// android adaptive_icon_background image + @JsonKey(name: 'adaptive_icon_monochrome') + final String? adaptiveIconMonochrome; + /// Android min_sdk_android @JsonKey(name: 'min_sdk_android') final int minSdkAndroid; @@ -157,6 +162,11 @@ class Config { adaptiveIconForeground != null && adaptiveIconBackground != null; + /// whether or not there is configuration for monochrome icons for android + bool get hasAndroidAdaptiveMonochromeConfig { + return isNeedingNewAndroidIcon && adaptiveIconMonochrome != null; + } + /// Checks if contains any platform config bool get hasPlatformConfig { return ios != false || diff --git a/lib/config/config.g.dart b/lib/config/config.g.dart index 82f2f481e9..2be66ae374 100644 --- a/lib/config/config.g.dart +++ b/lib/config/config.g.dart @@ -21,6 +21,8 @@ Config _$ConfigFromJson(Map json) => $checkedCreate( $checkedConvert('adaptive_icon_foreground', (v) => v as String?), adaptiveIconBackground: $checkedConvert('adaptive_icon_background', (v) => v as String?), + adaptiveIconMonochrome: + $checkedConvert('adaptive_icon_monochrome', (v) => v as String?), minSdkAndroid: $checkedConvert('min_sdk_android', (v) => v as int? ?? constants.androidDefaultAndroidMinSDK), removeAlphaIOS: @@ -42,6 +44,7 @@ Config _$ConfigFromJson(Map json) => $checkedCreate( 'imagePathIOS': 'image_path_ios', 'adaptiveIconForeground': 'adaptive_icon_foreground', 'adaptiveIconBackground': 'adaptive_icon_background', + 'adaptiveIconMonochrome': 'adaptive_icon_monochrome', 'minSdkAndroid': 'min_sdk_android', 'removeAlphaIOS': 'remove_alpha_ios', 'backgroundColorIOS': 'background_color_ios', @@ -59,6 +62,7 @@ Map _$ConfigToJson(Config instance) => { 'image_path_ios': instance.imagePathIOS, 'adaptive_icon_foreground': instance.adaptiveIconForeground, 'adaptive_icon_background': instance.adaptiveIconBackground, + 'adaptive_icon_monochrome': instance.adaptiveIconMonochrome, 'min_sdk_android': instance.minSdkAndroid, 'remove_alpha_ios': instance.removeAlphaIOS, 'background_color_ios': instance.backgroundColorIOS, diff --git a/lib/constants.dart b/lib/constants.dart index 9f51dab39b..6ef7d01c6b 100644 --- a/lib/constants.dart +++ b/lib/constants.dart @@ -24,6 +24,7 @@ const int androidDefaultAndroidMinSDK = 21; const String androidFileName = 'ic_launcher.png'; const String androidAdaptiveForegroundFileName = 'ic_launcher_foreground.png'; const String androidAdaptiveBackgroundFileName = 'ic_launcher_background.png'; +const String androidAdaptiveMonochromeFileName = 'ic_launcher_monochrome.png'; String androidAdaptiveXmlFolder(String? flavor) => androidResFolder(flavor) + 'mipmap-anydpi-v26/'; const String androidDefaultIconName = 'ic_launcher'; diff --git a/lib/ios.dart b/lib/ios.dart index 1339de35e3..5fad0e7da2 100644 --- a/lib/ios.dart +++ b/lib/ios.dart @@ -197,7 +197,7 @@ void modifyContentsFile(String newIconName) { String generateContentsFileAsString(String newIconName) { final Map contentJson = { 'images': createImageList(newIconName), - 'info': ContentsInfoObject(version: 1, author: 'xcode').toJson() + 'info': ContentsInfoObject(version: 1, author: 'xcode').toJson(), }; return json.encode(contentJson); } @@ -220,7 +220,7 @@ class ContentsImageObject { 'size': size, 'idiom': idiom, 'filename': filename, - 'scale': scale + 'scale': scale, }; } } @@ -390,7 +390,7 @@ List> createImageList(String fileNamePrefix) { idiom: 'ios-marketing', filename: '$fileNamePrefix-1024x1024@1x.png', scale: '1x', - ).toJson() + ).toJson(), ]; return imageList; } diff --git a/lib/main.dart b/lib/main.dart index ef957ad565..4b235fa33a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -141,6 +141,18 @@ Future createIconsFromConfig( if (flutterConfigs.hasAndroidAdaptiveConfig) { android_launcher_icons.createAdaptiveIcons(flutterConfigs, flavor); } + if (flutterConfigs.hasAndroidAdaptiveMonochromeConfig) { + android_launcher_icons.createAdaptiveMonochromeIcons( + flutterConfigs, + flavor, + ); + } + if (flutterConfigs.isNeedingNewAndroidIcon) { + android_launcher_icons.createMipmapXmlFile( + flutterConfigs, + flavor, + ); + } if (flutterConfigs.isNeedingNewIOSIcon) { ios_launcher_icons.createIcons(flutterConfigs, flavor); } diff --git a/lib/xml_templates.dart b/lib/xml_templates.dart index 9f6282e148..a21198d14c 100644 --- a/lib/xml_templates.dart +++ b/lib/xml_templates.dart @@ -1,19 +1,9 @@ // ignore_for_file: public_member_api_docs -const String icLauncherXml = ''' +const String mipmapXmlFile = ''' - - - -'''; - -const String icLauncherDrawableBackgroundXml = ''' - - - - - +{{CONTENT}} '''; const String colorsXml = ''' diff --git a/test/abs/icon_generator_test.mocks.dart b/test/abs/icon_generator_test.mocks.dart index adcbe83cf5..0b320f4f56 100644 --- a/test/abs/icon_generator_test.mocks.dart +++ b/test/abs/icon_generator_test.mocks.dart @@ -1,4 +1,4 @@ -// Mocks generated by Mockito 5.3.2 from annotations +// Mocks generated by Mockito 5.4.2 from annotations // in flutter_launcher_icons/test/abs/icon_generator_test.dart. // Do not manually edit this file. @@ -58,6 +58,11 @@ class MockConfig extends _i1.Mock implements _i3.Config { returnValue: false, ) as bool); @override + bool get hasAndroidAdaptiveMonochromeConfig => (super.noSuchMethod( + Invocation.getter(#hasAndroidAdaptiveMonochromeConfig), + returnValue: false, + ) as bool); + @override bool get hasPlatformConfig => (super.noSuchMethod( Invocation.getter(#hasPlatformConfig), returnValue: false, diff --git a/test/android_test.dart b/test/android_test.dart index c621998d0a..f65fb8b8de 100644 --- a/test/android_test.dart +++ b/test/android_test.dart @@ -32,7 +32,7 @@ void main() { final Map flutterIconsConfig = { 'image_path': 'assets/images/icon-710x599.png', 'android': true, - 'ios': true + 'ios': true, }; expect( Config.fromJson(flutterIconsConfig).isCustomAndroidFile, @@ -42,7 +42,7 @@ void main() { final Map flutterIconsNewIconConfig = { 'image_path': 'assets/images/icon-710x599.png', 'android': 'New Icon', - 'ios': true + 'ios': true, }; expect( Config.fromJson(flutterIconsNewIconConfig).isCustomAndroidFile, @@ -55,7 +55,7 @@ void main() { 'image_path': 'assets/images/icon-710x599.png', 'image_path_android': 'assets/images/icon-android.png', 'android': 'New Icon', - 'ios': true + 'ios': true, }; expect( Config.fromJson(flutterIconsNewIconConfig).getImagePathAndroid(), diff --git a/test/macos/macos_icon_generator_test.mocks.dart b/test/macos/macos_icon_generator_test.mocks.dart index 49de9a8f4a..6d6509666e 100644 --- a/test/macos/macos_icon_generator_test.mocks.dart +++ b/test/macos/macos_icon_generator_test.mocks.dart @@ -1,4 +1,4 @@ -// Mocks generated by Mockito 5.3.2 from annotations +// Mocks generated by Mockito 5.4.2 from annotations // in flutter_launcher_icons/test/macos/macos_icon_generator_test.dart. // Do not manually edit this file. @@ -69,6 +69,12 @@ class MockConfig extends _i1.Mock implements _i3.Config { returnValueForMissingStub: false, ) as bool); @override + bool get hasAndroidAdaptiveMonochromeConfig => (super.noSuchMethod( + Invocation.getter(#hasAndroidAdaptiveMonochromeConfig), + returnValue: false, + returnValueForMissingStub: false, + ) as bool); + @override bool get hasPlatformConfig => (super.noSuchMethod( Invocation.getter(#hasPlatformConfig), returnValue: false, diff --git a/test/main_test.dart b/test/main_test.dart index 581cf8a565..17bb7a041b 100644 --- a/test/main_test.dart +++ b/test/main_test.dart @@ -111,7 +111,7 @@ flutter_launcher_icons: final Map flutterIconsConfig = { 'image_path': 'assets/images/icon-710x599.png', 'android': true, - 'ios': true + 'ios': true, }; final config = Config.fromJson(flutterIconsConfig); expect( @@ -122,7 +122,7 @@ flutter_launcher_icons: final Map flutterIconsConfigAndroid = { 'image_path_android': 'assets/images/icon-710x599.png', 'android': true, - 'ios': true + 'ios': true, }; final configAndroid = Config.fromJson(flutterIconsConfigAndroid); expect( @@ -134,7 +134,7 @@ flutter_launcher_icons: 'image_path_android': 'assets/images/icon-android.png', 'image_path_ios': 'assets/images/icon-ios.png', 'android': true, - 'ios': true + 'ios': true, }; final configBoth = Config.fromJson(flutterIconsConfigBoth); expect( @@ -148,7 +148,7 @@ flutter_launcher_icons: final Map flutterIconsConfig = { 'image_path': 'assets/images/icon-710x599.png', 'android': true, - 'ios': true + 'ios': true, }; final config = Config.fromJson(flutterIconsConfig); expect(config.hasPlatformConfig, isTrue); @@ -156,7 +156,7 @@ flutter_launcher_icons: test('No platform specified in config', () { final Map flutterIconsConfig = { - 'image_path': 'assets/images/icon-710x599.png' + 'image_path': 'assets/images/icon-710x599.png', }; final config = Config.fromJson(flutterIconsConfig); expect(config.hasPlatformConfig, isFalse); @@ -166,7 +166,7 @@ flutter_launcher_icons: final Map flutterIconsConfig = { 'image_path': 'assets/images/icon-710x599.png', 'android': false, - 'ios': true + 'ios': true, }; final config = Config.fromJson(flutterIconsConfig); expect(config.isNeedingNewAndroidIcon, isFalse); @@ -175,7 +175,7 @@ flutter_launcher_icons: test('No new Android icon needed - no Android config', () { final Map flutterIconsConfig = { 'image_path': 'assets/images/icon-710x599.png', - 'ios': true + 'ios': true, }; final config = Config.fromJson(flutterIconsConfig); expect(config.isNeedingNewAndroidIcon, isFalse); @@ -185,7 +185,7 @@ flutter_launcher_icons: final Map flutterIconsConfig = { 'image_path': 'assets/images/icon-710x599.png', 'android': true, - 'ios': false + 'ios': false, }; final config = Config.fromJson(flutterIconsConfig); expect(config.isNeedingNewIOSIcon, isFalse); @@ -194,7 +194,7 @@ flutter_launcher_icons: test('No new iOS icon needed - no iOS config', () { final Map flutterIconsConfig = { 'image_path': 'assets/images/icon-710x599.png', - 'android': true + 'android': true, }; final config = Config.fromJson(flutterIconsConfig); expect(config.isNeedingNewIOSIcon, isFalse); diff --git a/test/templates.dart b/test/templates.dart index aa1537a168..69caf54f3e 100644 --- a/test/templates.dart +++ b/test/templates.dart @@ -7,6 +7,7 @@ flutter_launcher_icons: image_path_ios: "assets/images/icon-1024x1024.png" adaptive_icon_background: "assets/images/christmas-background.png" adaptive_icon_foreground: "assets/images/icon-foreground-432x432.png" + adaptive_icon_monochrome: "assets/images/icon-monochrome-432x432.png" min_sdk_android: 21 remove_alpha_ios: false web: @@ -56,6 +57,7 @@ image_path_android: "assets/images/icon-710x599-android.png" image_path_ios: "assets/images/icon-1024x1024.png" adaptive_icon_background: "assets/images/christmas-background.png" adaptive_icon_foreground: "assets/images/icon-foreground-432x432.png" +adaptive_icon_monochrome: "assets/images/icon-monochrome-432x432.png" web: generate: true image_path: "app_icon.png" # filepath @@ -111,6 +113,7 @@ flutter_launcher_icons: image_path_ios: "assets/images/icon-1024x1024.png" adaptive_icon_background: "assets/images/christmas-background.png" adaptive_icon_foreground: "assets/images/icon-foreground-432x432.png" + adaptive_icon_monochrome: "assets/images/icon-monochrome-432x432.png" min_sdk_android: 21 remove_alpha_ios: false web: @@ -176,6 +179,7 @@ flutter_launcher_icons: image_path_ios: "assets/images/icon-1024x1024.png" adaptive_icon_background: "assets/images/christmas-background.png" adaptive_icon_foreground: "assets/images/icon-foreground-432x432.png" + adaptive_icon_monochrome: "assets/images/icon-monochrome-432x432.png" web: generate: true image_path: "app_icon.png" # filepath diff --git a/test/web/web_icon_generator_test.dart b/test/web/web_icon_generator_test.dart index 6872ffa6a0..453492e48d 100644 --- a/test/web/web_icon_generator_test.dart +++ b/test/web/web_icon_generator_test.dart @@ -65,7 +65,7 @@ void main() { d.file('manifest.json', anything), ]), d.file('flutter_launcher_icons.yaml', anything), - d.file('pubspec.yaml', templates.pubspecTemplate) + d.file('pubspec.yaml', templates.pubspecTemplate), ]).validate(), completes, ); diff --git a/test/web/web_template_test.dart b/test/web/web_template_test.dart index 452c033923..58317b92ca 100644 --- a/test/web/web_template_test.dart +++ b/test/web/web_template_test.dart @@ -22,7 +22,7 @@ void main() { equals({ 'src': 'icons/Icon-512.png', 'sizes': '512x512', - 'type': 'image/png' + 'type': 'image/png', }), ); expect( @@ -31,7 +31,7 @@ void main() { 'src': 'icons/Icon-maskable-512.png', 'sizes': '512x512', 'type': 'image/png', - 'purpose': 'maskable' + 'purpose': 'maskable', }), ); }); diff --git a/test/windows/windows_icon_generator_test.mocks.dart b/test/windows/windows_icon_generator_test.mocks.dart index 8c7a5d02b2..1a6463b7c8 100644 --- a/test/windows/windows_icon_generator_test.mocks.dart +++ b/test/windows/windows_icon_generator_test.mocks.dart @@ -1,4 +1,4 @@ -// Mocks generated by Mockito 5.3.2 from annotations +// Mocks generated by Mockito 5.4.2 from annotations // in flutter_launcher_icons/test/windows/windows_icon_generator_test.dart. // Do not manually edit this file. @@ -69,6 +69,11 @@ class MockConfig extends _i1.Mock implements _i3.Config { returnValue: false, ) as bool); @override + bool get hasAndroidAdaptiveMonochromeConfig => (super.noSuchMethod( + Invocation.getter(#hasAndroidAdaptiveMonochromeConfig), + returnValue: false, + ) as bool); + @override bool get hasPlatformConfig => (super.noSuchMethod( Invocation.getter(#hasPlatformConfig), returnValue: false,