From 6dc7b90fce3dd7d63299088775038d5427f2ac4e Mon Sep 17 00:00:00 2001 From: Pavel Date: Fri, 13 Dec 2024 09:41:23 -0600 Subject: [PATCH] Fix for the [issue 622](https://github.com/ionic-team/capacitor-assets/issues/622) dark mode support for android --- src/definitions.ts | 1 + src/platforms/android/assets.ts | 55 ++++++++++++++++++++++++++++ src/platforms/android/index.ts | 37 +++++++++---------- test/platforms/android.asset.test.ts | 6 +-- 4 files changed, 75 insertions(+), 24 deletions(-) diff --git a/src/definitions.ts b/src/definitions.ts index 42160dd..935586e 100644 --- a/src/definitions.ts +++ b/src/definitions.ts @@ -30,6 +30,7 @@ export const enum AssetKind { Logo = 'logo', LogoDark = 'logo-dark', AdaptiveIcon = 'adaptive-icon', + AdaptiveIconDark = 'adaptive-icon-dark', Icon = 'icon', IconForeground = 'icon-foreground', IconBackground = 'icon-background', diff --git a/src/platforms/android/assets.ts b/src/platforms/android/assets.ts index 37592d6..4d05b8b 100644 --- a/src/platforms/android/assets.ts +++ b/src/platforms/android/assets.ts @@ -116,6 +116,61 @@ export const ANDROID_XXXHDPI_ADAPTIVE_ICON: AndroidOutputAssetTemplateAdaptiveIc density: AndroidDensity.Xxxhdpi, }; +// Dark/night mode adaptive icons +export const ANDROID_LDPI_ADAPTIVE_ICON_DARK: AndroidOutputAssetTemplateAdaptiveIcon = { + platform: Platform.Android, + kind: AssetKind.AdaptiveIconDark, + format: Format.Png, + width: 81, + height: 81, + density: AndroidDensity.LdpiNight, +}; + +export const ANDROID_MDPI_ADAPTIVE_ICON_DARK: AndroidOutputAssetTemplateAdaptiveIcon = { + platform: Platform.Android, + kind: AssetKind.AdaptiveIconDark, + format: Format.Png, + width: 108, + height: 108, + density: AndroidDensity.MdpiNight, +}; + +export const ANDROID_HDPI_ADAPTIVE_ICON_DARK: AndroidOutputAssetTemplateAdaptiveIcon = { + platform: Platform.Android, + kind: AssetKind.AdaptiveIconDark, + format: Format.Png, + width: 162, + height: 162, + density: AndroidDensity.HdpiNight, +}; + +export const ANDROID_XHDPI_ADAPTIVE_ICON_DARK: AndroidOutputAssetTemplateAdaptiveIcon = { + platform: Platform.Android, + kind: AssetKind.AdaptiveIconDark, + format: Format.Png, + width: 216, + height: 216, + density: AndroidDensity.XhdpiNight, +}; + +export const ANDROID_XXHDPI_ADAPTIVE_ICON_DARK: AndroidOutputAssetTemplateAdaptiveIcon = { + platform: Platform.Android, + kind: AssetKind.AdaptiveIconDark, + format: Format.Png, + width: 324, + height: 324, + density: AndroidDensity.XxhdpiNight, +}; + +export const ANDROID_XXXHDPI_ADAPTIVE_ICON_DARK: AndroidOutputAssetTemplateAdaptiveIcon = { + platform: Platform.Android, + kind: AssetKind.AdaptiveIconDark, + format: Format.Png, + width: 432, + height: 432, + density: AndroidDensity.XxxhdpiNight, +}; + // // Splash screens // diff --git a/src/platforms/android/index.ts b/src/platforms/android/index.ts index 8d1b7c3..69d5051 100644 --- a/src/platforms/android/index.ts +++ b/src/platforms/android/index.ts @@ -1,22 +1,22 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ -import { mkdirp, pathExists, writeFile } from '@ionic/utils-fs'; -import { dirname, join, relative } from 'path'; -import type { OutputInfo, Sharp } from 'sharp'; +import {mkdirp, pathExists, writeFile} from '@ionic/utils-fs'; +import {dirname, join, relative} from 'path'; +import type {OutputInfo, Sharp} from 'sharp'; import sharp from 'sharp'; -import type { AssetGeneratorOptions } from '../../asset-generator'; -import { AssetGenerator } from '../../asset-generator'; +import type {AssetGeneratorOptions} from '../../asset-generator'; +import {AssetGenerator} from '../../asset-generator'; import type { AndroidOutputAssetTemplate, AndroidOutputAssetTemplateAdaptiveIcon, AndroidOutputAssetTemplateSplash, } from '../../definitions'; -import { AssetKind, Platform } from '../../definitions'; -import { BadPipelineError, BadProjectError } from '../../error'; -import type { InputAsset } from '../../input-asset'; -import { OutputAsset } from '../../output-asset'; -import type { Project } from '../../project'; -import { warn } from '../../util/log'; +import {AssetKind, Platform} from '../../definitions'; +import {BadPipelineError, BadProjectError} from '../../error'; +import type {InputAsset} from '../../input-asset'; +import {OutputAsset} from '../../output-asset'; +import type {Project} from '../../project'; +import {warn} from '../../util/log'; import * as AndroidAssetTemplates from './assets'; @@ -118,11 +118,7 @@ export class AndroidAssetGenerator extends AssetGenerator { asset: InputAsset, pipe: Sharp, ): Promise { - // Current versions of Android don't appear to support night mode icons (13+ might?) - // so, for now, we only generate light mode ones - if (asset.kind === AssetKind.LogoDark) { - return []; - } + const isNightMode = asset.kind !== AssetKind.Logo; // Create the background pipeline for the generated icons const backgroundPipe = sharp({ @@ -131,14 +127,15 @@ export class AndroidAssetGenerator extends AssetGenerator { height: asset.height!, channels: 4, background: - asset.kind === AssetKind.Logo - ? this.options.iconBackgroundColor ?? '#ffffff' - : this.options.iconBackgroundColorDark ?? '#111111', + isNightMode + ? this.options.iconBackgroundColorDark ?? '#111111' + : this.options.iconBackgroundColor ?? '#ffffff', }, }); + const adaptiveIconKind = isNightMode ? AssetKind.AdaptiveIconDark : AssetKind.AdaptiveIcon; const icons = Object.values(AndroidAssetTemplates).filter( - (a) => a.kind === AssetKind.AdaptiveIcon, + (a) => a.kind === adaptiveIconKind, ) as AndroidOutputAssetTemplateAdaptiveIcon[]; const backgroundImages = await Promise.all( diff --git a/test/platforms/android.asset.test.ts b/test/platforms/android.asset.test.ts index c21b205..065dc72 100644 --- a/test/platforms/android.asset.test.ts +++ b/test/platforms/android.asset.test.ts @@ -1,4 +1,4 @@ -import { copy, pathExists, readdirp, readFile, rmSync as rm, statSync } from '@ionic/utils-fs'; +import { copy, pathExists, rmSync as rm } from '@ionic/utils-fs'; import tempy from 'tempy'; import sharp from 'sharp'; import { join } from 'path'; @@ -7,12 +7,10 @@ import { Context, loadContext } from '../../src/ctx'; import { AndroidOutputAssetTemplate, AndroidOutputAssetTemplateAdaptiveIcon, - AssetKind, Assets, } from '../../src/definitions'; import { OutputAsset } from '../../src/output-asset'; import { AndroidAssetGenerator } from '../../src/platforms/android'; -import * as AndroidAssets from '../../src/platforms/android/assets'; describe('Android asset test', () => { let ctx: Context; @@ -187,7 +185,7 @@ describe('Android Asset Test - Logo Only', () => { let generatedAssets = ((await assets.logoDark?.generate(strategy, ctx.project)) ?? []) as OutputAsset[]; - expect(generatedAssets.length).toBe(13); + expect(generatedAssets.length).toBe(25); await verifySizes(generatedAssets); });