diff --git a/README.md b/README.md index 0650989eab..dc1343a909 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,7 @@ foreground of the Android 13+ themed icon. For more information see [Android Ada - `web`: Add web related configs - `generate`: Specifies whether to generate icons for this platform or not - `image_path`: Path to web icon.png + - `image_path_favicon`: The location of the icon image file used to generate the favicon (optional - if not defined then falls back to using the web image_path then the global image_path) - `background_color`: Updates *background_color* in `web/manifest.json` - `theme_color`: Updates *theme_color* in `web/manifest.json` diff --git a/bin/generate.dart b/bin/generate.dart index b7772d7827..edc1e5b3e7 100644 --- a/bin/generate.dart +++ b/bin/generate.dart @@ -100,6 +100,7 @@ flutter_launcher_icons: web: generate: true image_path: "path/to/image.png" + # image_path_favicon: "assets/icon/icon-favicon.png" background_color: "#hexcode" theme_color: "#hexcode" diff --git a/lib/config/web_config.dart b/lib/config/web_config.dart index c0130375c3..3b321ca016 100644 --- a/lib/config/web_config.dart +++ b/lib/config/web_config.dart @@ -15,6 +15,10 @@ class WebConfig { @JsonKey(name: 'image_path') final String? imagePath; + /// Override image path for favicon + @JsonKey(name: 'image_path_favicon') + final String? imagePathFavicon; + /// manifest.json's background_color @JsonKey(name: 'background_color') final String? backgroundColor; @@ -27,6 +31,7 @@ class WebConfig { const WebConfig({ this.generate = false, this.imagePath, + this.imagePathFavicon, this.backgroundColor, this.themeColor, }); diff --git a/lib/config/web_config.g.dart b/lib/config/web_config.g.dart index d1451c0b35..2c8096992d 100644 --- a/lib/config/web_config.g.dart +++ b/lib/config/web_config.g.dart @@ -13,6 +13,8 @@ WebConfig _$WebConfigFromJson(Map json) => $checkedCreate( final val = WebConfig( generate: $checkedConvert('generate', (v) => v as bool? ?? false), imagePath: $checkedConvert('image_path', (v) => v as String?), + imagePathFavicon: + $checkedConvert('image_path_favicon', (v) => v as String?), backgroundColor: $checkedConvert('background_color', (v) => v as String?), themeColor: $checkedConvert('theme_color', (v) => v as String?), @@ -21,6 +23,7 @@ WebConfig _$WebConfigFromJson(Map json) => $checkedCreate( }, fieldKeyMap: const { 'imagePath': 'image_path', + 'imagePathFavicon': 'image_path_favicon', 'backgroundColor': 'background_color', 'themeColor': 'theme_color' }, @@ -29,6 +32,7 @@ WebConfig _$WebConfigFromJson(Map json) => $checkedCreate( Map _$WebConfigToJson(WebConfig instance) => { 'generate': instance.generate, 'image_path': instance.imagePath, + 'image_path_favicon': instance.imagePathFavicon, 'background_color': instance.backgroundColor, 'theme_color': instance.themeColor, }; diff --git a/lib/web/web_icon_generator.dart b/lib/web/web_icon_generator.dart index ebc60694ed..810be50acf 100644 --- a/lib/web/web_icon_generator.dart +++ b/lib/web/web_icon_generator.dart @@ -53,6 +53,7 @@ class WebIconGenerator extends IconGenerator { context.webConfig!.imagePath ?? context.config.imagePath!, ); + // load and decode the image file context.logger .verbose('Decoding and loading image file at $imgFilePath...'); final imgFile = utils.decodeImageFile(imgFilePath); @@ -61,9 +62,31 @@ class WebIconGenerator extends IconGenerator { throw FileNotFoundException(imgFilePath); } + // resolve the favicon image path and file, which is either one explicitly + // provided or the same as the image file loaded above + late final String faviconImgFilePath; + late final Image faviconImgFile; + final faviconImgFileOverride = context.webConfig!.imagePathFavicon; + if (faviconImgFileOverride != null) { + // favicon override was specified, construct the full path and decode + faviconImgFilePath = + path.join(context.prefixPath, faviconImgFileOverride); + final imgFile = utils.decodeImageFile(faviconImgFilePath); + if (imgFile == null) { + context.logger + .error('Image File not found at give path $faviconImgFilePath...'); + throw FileNotFoundException(faviconImgFilePath); + } + faviconImgFile = imgFile; + } else { + // no favicon override, use the fallback image file + faviconImgFilePath = imgFilePath; + faviconImgFile = imgFile; + } + // generate favicon in web/favicon.png - context.logger.verbose('Generating favicon from $imgFilePath...'); - _generateFavicon(imgFile); + context.logger.verbose('Generating favicon from $faviconImgFilePath...'); + _generateFavicon(faviconImgFile); // generate icons in web/icons/ context.logger.verbose('Generating icons from $imgFilePath...'); diff --git a/test/config_test.dart b/test/config_test.dart index acd8b1f8b8..f8146648a6 100644 --- a/test/config_test.dart +++ b/test/config_test.dart @@ -47,6 +47,7 @@ void main() { equals({ 'generate': true, 'image_path': 'app_icon.png', + 'image_path_favicon': null, 'background_color': '#0175C2', 'theme_color': '#0175C2', }), @@ -155,6 +156,7 @@ void main() { equals({ 'generate': true, 'image_path': 'app_icon.png', + 'image_path_favicon': 'app_icon.png', 'background_color': '#0175C2', 'theme_color': '#0175C2', }), @@ -238,6 +240,7 @@ void main() { equals({ 'generate': true, 'image_path': 'app_icon.png', + 'image_path_favicon': null, 'background_color': '#0175C2', 'theme_color': '#0175C2', }), diff --git a/test/templates.dart b/test/templates.dart index 69caf54f3e..64aeb5524c 100644 --- a/test/templates.dart +++ b/test/templates.dart @@ -119,6 +119,7 @@ flutter_launcher_icons: web: generate: true image_path: "app_icon.png" # filepath + image_path_favicon: "app_icon.png" # filepath background_color: "#0175C2" # hex_color theme_color: "#0175C2" # hex_color apple_mobile_web_app_title: "demo" diff --git a/test/web/web_icon_generator_test.dart b/test/web/web_icon_generator_test.dart index 453492e48d..dc0554c154 100644 --- a/test/web/web_icon_generator_test.dart +++ b/test/web/web_icon_generator_test.dart @@ -30,6 +30,7 @@ void main() { d.file('flutter_launcher_icons.yaml', templates.fliWebConfig), d.file('pubspec.yaml', templates.pubspecTemplate), d.file('app_icon.png', imageFile.readAsBytesSync()), + d.file('app_icon_favicon.png', imageFile.readAsBytesSync()), ]).create(); prefixPath = path.join(d.sandbox, 'fli_test'); config = Config.loadConfigFromPath(