diff --git a/README.md b/README.md index 7238c7a..0f5b010 100644 --- a/README.md +++ b/README.md @@ -205,6 +205,7 @@ flavorizr: | customConfig | Array | | false | An array which contains a set of custom configs, *overrides defaultConfig* | | generateDummyAssets | bool | true | false | True if you want to generate dummy assets (icon set, strings, etc) | | icon | String | | false | The icon path for this android flavor | +| adaptiveIcon | Array | | false | An array which contains foreground and background of adaptive icon | #### ios (under *flavorname*) @@ -354,6 +355,24 @@ apple { } ``` +#### adaptiveIcon (for Android only) + +You can define adaptiveIcon for android: +```yml +flavors: + apple: + app: + name: "Apple App" + + android: + applicationId: "com.example.apple" + icon: "assets/icon/appleApp/ic_launcher.png" + adaptiveIcon: + foreground: "assets/adaptive_icon/appleApp/ic_launcher_foreground.png" + background: "assets/adaptive_icon/appleApp/ic_launcher_background.png" +``` +After removing adaptiveIcon key, the adaptive icons generated before will still exist. Please delete adaptiveIcon manually. + ## Usage diff --git a/example/pubspec.lock b/example/pubspec.lock index 6f98c73..7b9099c 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -13,10 +13,10 @@ packages: dependency: transitive description: name: args - sha256: c372bb384f273f0c2a8aaaa226dad84dc27c8519a691b888725dec59518ad53a + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.2" async: dependency: transitive description: diff --git a/lib/src/parser/models/flavors/android.dart b/lib/src/parser/models/flavors/android.dart index 8661562..f8fd0ec 100644 --- a/lib/src/parser/models/flavors/android.dart +++ b/lib/src/parser/models/flavors/android.dart @@ -23,6 +23,7 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +import 'package:flutter_flavorizr/src/parser/models/flavors/android/adaptive_icon.dart'; import 'package:flutter_flavorizr/src/parser/models/flavors/android/build_config_field.dart'; import 'package:flutter_flavorizr/src/parser/models/flavors/android/res_value.dart'; import 'package:flutter_flavorizr/src/parser/models/flavors/commons/os.dart'; @@ -49,6 +50,9 @@ class Android extends OS { @JsonKey(disallowNullValue: true) final AGConnect? agconnect; + @JsonKey(disallowNullValue: true) + final AdaptiveIcon? adaptiveIcon; + Android({ required this.applicationId, this.customConfig = const {}, @@ -58,6 +62,7 @@ class Android extends OS { bool generateDummyAssets = true, Firebase? firebase, String? icon, + this.adaptiveIcon, }) : super( generateDummyAssets: generateDummyAssets, firebase: firebase, diff --git a/lib/src/parser/models/flavors/android.g.dart b/lib/src/parser/models/flavors/android.g.dart index f4a32af..e86713c 100644 --- a/lib/src/parser/models/flavors/android.g.dart +++ b/lib/src/parser/models/flavors/android.g.dart @@ -45,5 +45,9 @@ Android _$AndroidFromJson(Map json) { ? null : Firebase.fromJson(Map.from(json['firebase'] as Map)), icon: json['icon'] as String?, + adaptiveIcon: json['adaptiveIcon'] == null + ? null + : AdaptiveIcon.fromJson( + Map.from(json['adaptiveIcon'] as Map)), ); } diff --git a/lib/src/parser/models/flavors/android/adaptive_icon.dart b/lib/src/parser/models/flavors/android/adaptive_icon.dart new file mode 100644 index 0000000..967c868 --- /dev/null +++ b/lib/src/parser/models/flavors/android/adaptive_icon.dart @@ -0,0 +1,14 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'adaptive_icon.g.dart'; + +@JsonSerializable(anyMap: true, createToJson: false) +class AdaptiveIcon { + final String foreground; + final String background; + + AdaptiveIcon({required this.foreground, required this.background}); + + factory AdaptiveIcon.fromJson(Map json) => + _$AdaptiveIconFromJson(json); +} diff --git a/lib/src/parser/models/flavors/android/adaptive_icon.g.dart b/lib/src/parser/models/flavors/android/adaptive_icon.g.dart new file mode 100644 index 0000000..45e4686 --- /dev/null +++ b/lib/src/parser/models/flavors/android/adaptive_icon.g.dart @@ -0,0 +1,19 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'adaptive_icon.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +AdaptiveIcon _$AdaptiveIconFromJson(Map json) { + $checkKeys( + json, + requiredKeys: const ['foreground', 'background'], + disallowNullValues: const ['foreground', 'background'], + ); + return AdaptiveIcon( + foreground: json['foreground'] as String, + background: json['background'] as String, + ); +} diff --git a/lib/src/processors/android/icons/android_adaptive_icon_processor.dart b/lib/src/processors/android/icons/android_adaptive_icon_processor.dart new file mode 100644 index 0000000..88627f2 --- /dev/null +++ b/lib/src/processors/android/icons/android_adaptive_icon_processor.dart @@ -0,0 +1,38 @@ +import 'package:flutter_flavorizr/src/parser/models/flavorizr.dart'; +import 'package:flutter_flavorizr/src/processors/commons/image_resizer_processor.dart'; +import 'package:flutter_flavorizr/src/processors/commons/queue_processor.dart'; +import 'package:flutter_flavorizr/src/utils/constants.dart'; +import 'package:sprintf/sprintf.dart'; + +class AndroidAdaptiveIconProcessor extends QueueProcessor { + String foregroundSource; + String backgroundSource; + String flavorName; + String folder; + Size size; + + AndroidAdaptiveIconProcessor( + this.foregroundSource, + this.backgroundSource, + this.flavorName, + this.folder, + this.size, { + required Flavorizr config, + }) : super([ + ImageResizerProcessor( + foregroundSource, + sprintf(K.androidAdaptiveIconForegroundPath, [flavorName, folder]), + size, + config: config, + ), + ImageResizerProcessor( + backgroundSource, + sprintf(K.androidAdaptiveIconBackgroundPath, [flavorName, folder]), + size, + config: config, + ), + ], config: config); + + @override + String toString() => 'AndroidAdaptiveIconProcessor'; +} diff --git a/lib/src/processors/android/icons/android_adaptive_icon_xml_processor.dart b/lib/src/processors/android/icons/android_adaptive_icon_xml_processor.dart new file mode 100644 index 0000000..c9f166d --- /dev/null +++ b/lib/src/processors/android/icons/android_adaptive_icon_xml_processor.dart @@ -0,0 +1,25 @@ +import 'package:flutter_flavorizr/src/parser/models/flavorizr.dart'; +import 'package:flutter_flavorizr/src/processors/android/icons/android_generate_iclauncher_xml_processor.dart'; +import 'package:flutter_flavorizr/src/processors/commons/new_file_string_processor.dart'; +import 'package:flutter_flavorizr/src/processors/commons/queue_processor.dart'; +import 'package:flutter_flavorizr/src/utils/constants.dart'; +import 'package:sprintf/sprintf.dart'; + +class AndroidAdaptiveIconXmlProcessor extends QueueProcessor { + AndroidAdaptiveIconXmlProcessor( + String? flavorName, { + required Flavorizr config, + }) : super( + [ + NewFileStringProcessor( + sprintf(K.androidAdaptiveIconXmlPath, [flavorName]), + AndroidGenerateIclauncherXmlProcessor(config: config), + config: config, + ), + ], + config: config, + ); + + @override + String toString() => 'AndroidAdaptiveIconXmlProcessor'; +} diff --git a/lib/src/processors/android/icons/android_adaptive_icons_processor.dart b/lib/src/processors/android/icons/android_adaptive_icons_processor.dart new file mode 100644 index 0000000..d05e033 --- /dev/null +++ b/lib/src/processors/android/icons/android_adaptive_icons_processor.dart @@ -0,0 +1,45 @@ +import 'package:flutter_flavorizr/src/parser/models/flavorizr.dart'; +import 'package:flutter_flavorizr/src/processors/android/icons/android_adaptive_icon_processor.dart'; +import 'package:flutter_flavorizr/src/processors/commons/image_resizer_processor.dart'; +import 'package:flutter_flavorizr/src/processors/commons/queue_processor.dart'; + +class AndroidAdaptiveIconsProcessor extends QueueProcessor { + static const _entries = { + 'drawable-mdpi': Size(width: 108, height: 108), + 'drawable-hdpi': Size(width: 162, height: 162), + 'drawable-xhdpi': Size(width: 216, height: 216), + 'drawable-xxhdpi': Size(width: 324, height: 324), + 'drawable-xxxhdpi': Size(width: 432, height: 432), + }; + + String foregroundSource; + String backgroundSource; + String flavorName; + + AndroidAdaptiveIconsProcessor( + this.foregroundSource, + this.backgroundSource, + this.flavorName, { + required Flavorizr config, + }) : super( + _entries.map( + (folder, size) { + return MapEntry( + folder, + AndroidAdaptiveIconProcessor( + foregroundSource, + backgroundSource, + flavorName, + folder, + size, + config: config, + ), + ); + }, + ).values, + config: config, + ); + + @override + String toString() => 'AndroidAdaptiveIconsProcessor'; +} diff --git a/lib/src/processors/android/icons/android_generate_iclauncher_xml_processor.dart b/lib/src/processors/android/icons/android_generate_iclauncher_xml_processor.dart new file mode 100644 index 0000000..0b95852 --- /dev/null +++ b/lib/src/processors/android/icons/android_generate_iclauncher_xml_processor.dart @@ -0,0 +1,22 @@ +import 'package:flutter_flavorizr/src/parser/models/flavorizr.dart'; +import 'package:flutter_flavorizr/src/processors/commons/string_processor.dart'; + +class AndroidGenerateIclauncherXmlProcessor extends StringProcessor { + AndroidGenerateIclauncherXmlProcessor({ + required Flavorizr config, + }) : super( + config: config, + ); + + @override + String execute() { + return '' + '' + '' + '' + ''; + } + + @override + String toString() => 'AndroidGenerateIclauncherXmlProcessor'; +} diff --git a/lib/src/processors/android/icons/android_icons_processor.dart b/lib/src/processors/android/icons/android_icons_processor.dart index ed64471..9471510 100644 --- a/lib/src/processors/android/icons/android_icons_processor.dart +++ b/lib/src/processors/android/icons/android_icons_processor.dart @@ -25,6 +25,8 @@ import 'package:flutter_flavorizr/src/extensions/extensions_map.dart'; import 'package:flutter_flavorizr/src/parser/models/flavorizr.dart'; +import 'package:flutter_flavorizr/src/processors/android/icons/android_adaptive_icons_processor.dart'; +import 'package:flutter_flavorizr/src/processors/android/icons/android_adaptive_icon_xml_processor.dart'; import 'package:flutter_flavorizr/src/processors/android/icons/android_icon_processor.dart'; import 'package:flutter_flavorizr/src/processors/commons/queue_processor.dart'; @@ -32,20 +34,48 @@ class AndroidIconsProcessor extends QueueProcessor { AndroidIconsProcessor({ required Flavorizr config, }) : super( - config.androidFlavors - .where((_, flavor) => - flavor.app.icon != null || flavor.android?.icon != null) - .map( - (flavorName, flavor) => MapEntry( - flavorName, - AndroidIconProcessor( - flavor.android!.icon ?? flavor.app.icon ?? '', + [ + ...config.androidFlavors + .where((_, flavor) => + flavor.app.icon != null || flavor.android?.icon != null) + .map( + (flavorName, flavor) => MapEntry( flavorName, - config: config, + AndroidIconProcessor( + flavor.android!.icon ?? flavor.app.icon ?? '', + flavorName, + config: config, + ), ), - ), - ) - .values, + ) + .values, + ...config.androidFlavors + .where((_, flavor) => flavor.android!.adaptiveIcon != null) + .map( + (flavorName, flavor) => MapEntry( + flavorName, + AndroidAdaptiveIconXmlProcessor( + flavorName, + config: config, + ), + ), + ) + .values, + ...config.androidFlavors + .where((_, flavor) => flavor.android!.adaptiveIcon != null) + .map( + (flavorName, flavor) => MapEntry( + flavorName, + AndroidAdaptiveIconsProcessor( + flavor.android!.adaptiveIcon!.foreground, + flavor.android!.adaptiveIcon!.background, + flavorName, + config: config, + ), + ), + ) + .values, + ], config: config, ); diff --git a/lib/src/processors/commons/new_file_string_processor.dart b/lib/src/processors/commons/new_file_string_processor.dart index 78d0923..180613a 100644 --- a/lib/src/processors/commons/new_file_string_processor.dart +++ b/lib/src/processors/commons/new_file_string_processor.dart @@ -37,4 +37,10 @@ class NewFileStringProcessor extends AbstractFileStringProcessor { processor, config: config, ); + + @override + void execute() { + file.createSync(recursive: true); + super.execute(); + } } diff --git a/lib/src/processors/processor.dart b/lib/src/processors/processor.dart index 09f191d..c13a259 100644 --- a/lib/src/processors/processor.dart +++ b/lib/src/processors/processor.dart @@ -73,6 +73,7 @@ class Processor extends AbstractProcessor { 'android:buildGradle', 'android:dummyAssets', 'android:icons', + 'android:adaptiveIcons', // Flutter 'flutter:flavors', diff --git a/lib/src/utils/constants.dart b/lib/src/utils/constants.dart index dba13ef..cd07870 100644 --- a/lib/src/utils/constants.dart +++ b/lib/src/utils/constants.dart @@ -31,6 +31,15 @@ class K { static String androidIconPath = '$androidAppPath/src/%s/res/%s/ic_launcher.png'; + static String androidAdaptiveIconBackgroundPath = + '$androidAppPath/src/%s/res/%s/ic_launcher_background.png'; + + static String androidAdaptiveIconForegroundPath = + '$androidAppPath/src/%s/res/%s/ic_launcher_foreground.png'; + + static String androidAdaptiveIconXmlPath = + '$androidAppPath/src/%s/res/mipmap-anydpi-v26/ic_launcher.xml'; + static String androidManifestPath = '$androidSrcPath/main/AndroidManifest.xml';