Skip to content

Commit

Permalink
feat: added support for android 13+ themed icons
Browse files Browse the repository at this point in the history
  • Loading branch information
OutdatedGuy committed Jun 20, 2023
1 parent f825018 commit 1902eba
Show file tree
Hide file tree
Showing 14 changed files with 130 additions and 58 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
1 change: 1 addition & 0 deletions bin/generate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions example/default_example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
115 changes: 73 additions & 42 deletions lib/android.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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 +=
' <background android:drawable="@drawable/ic_launcher_background"/>\n';
} else {
xmlContent +=
' <background android:drawable="@color/ic_launcher_background"/>\n';
}

xmlContent +=
' <foreground android:drawable="@drawable/ic_launcher_foreground"/>\n';
}

if (config.hasAndroidAdaptiveMonochromeConfig) {
xmlContent +=
' <monochrome android:drawable="@drawable/ic_launcher_monochrome"/>\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
Expand All @@ -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,
Expand All @@ -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
Expand Down
12 changes: 11 additions & 1 deletion lib/config/config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class Config {
this.imagePathIOS,
this.adaptiveIconForeground,
this.adaptiveIconBackground,
this.adaptiveIconMonochrome,
this.minSdkAndroid = constants.androidDefaultAndroidMinSDK,
this.removeAlphaIOS = false,
this.backgroundColorIOS = '#ffffff',
Expand Down Expand Up @@ -116,14 +117,18 @@ 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;

/// android adaptive_icon_background image
@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;
Expand Down Expand Up @@ -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 ||
Expand Down
4 changes: 4 additions & 0 deletions lib/config/config.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions lib/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
12 changes: 12 additions & 0 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,18 @@ Future<void> 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);
}
Expand Down
14 changes: 2 additions & 12 deletions lib/xml_templates.dart
Original file line number Diff line number Diff line change
@@ -1,19 +1,9 @@
// ignore_for_file: public_member_api_docs

const String icLauncherXml = '''
const String mipmapXmlFile = '''
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>
''';

const String icLauncherDrawableBackgroundXml = '''
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>
{{CONTENT}}</adaptive-icon>
''';

const String colorsXml = '''
Expand Down
7 changes: 6 additions & 1 deletion test/abs/icon_generator_test.mocks.dart
Original file line number Diff line number Diff line change
@@ -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.

Expand Down Expand Up @@ -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,
Expand Down
8 changes: 7 additions & 1 deletion test/macos/macos_icon_generator_test.mocks.dart
Original file line number Diff line number Diff line change
@@ -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.

Expand Down Expand Up @@ -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,
Expand Down
4 changes: 4 additions & 0 deletions test/templates.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand Down
7 changes: 6 additions & 1 deletion test/windows/windows_icon_generator_test.mocks.dart
Original file line number Diff line number Diff line change
@@ -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.

Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit 1902eba

Please sign in to comment.