createIcons function

Future<void> createIcons(
  1. Config config,
  2. String? flavor
)

create the ios icons

Implementation

Future<void> createIcons(Config config, String? flavor) async {
  // TODO(p-mazhnik): support prefixPath
  final String? filePath = config.getImagePathIOS();
  final String? darkFilePath = config.imagePathIOSDarkTransparent;
  final String? tintedFilePath = config.imagePathIOSTintedGrayscale;

  if (filePath == null) {
    throw const InvalidConfigException(errorMissingImagePath);
  }

  // decodeImageFile shows error message if null
  // so can return here if image is null
  Image? image = decodeImage(await File(filePath).readAsBytes());
  if (image == null) {
    return;
  }

  // For dark and tinted images, return here if path was specified but image is null
  Image? darkImage;
  if (darkFilePath != null) {
    darkImage = decodeImage(await File(darkFilePath).readAsBytes());
    if (darkImage == null) {
      return;
    }
  }

  Image? tintedImage;
  if (tintedFilePath != null) {
    tintedImage = decodeImage(await File(tintedFilePath).readAsBytes());
    if (tintedImage == null) {
      return;
    }
    if (config.desaturateTintedToGrayscaleIOS) {
      printStatus('Desaturating iOS tinted image to grayscale');
      tintedImage = grayscale(tintedImage);
    } else {
      // Check if the image is already grayscale
      final pixel = tintedImage.getPixel(0, 0);
      do {
        if (pixel.r != pixel.g || pixel.g != pixel.b) {
          print(
            '\nWARNING: Tinted iOS image is not grayscale.\nSet "desaturate_tinted_to_grayscale_ios: true" to desaturate it.\n',
          );
          break;
        }
      } while (pixel.moveNext());
    }
  }

  if (config.removeAlphaIOS && image.hasAlpha) {
    final backgroundColor = _getBackgroundColor(config);
    final pixel = image.getPixel(0, 0);
    do {
      pixel.set(_alphaBlend(pixel, backgroundColor));
    } while (pixel.moveNext());

    image = image.convert(numChannels: 3);
  }
  if (image.hasAlpha) {
    print(
      '\nWARNING: Icons with alpha channel are not allowed in the Apple App Store.\nSet "remove_alpha_ios: true" to remove it.\n',
    );
  }
  String iconName;
  String? darkIconName;
  String? tintedIconName;
  final List<IosIconTemplate> generateIosIcons =
      (darkImage == null && tintedImage == null) ? legacyIosIcons : iosIcons;
  final dynamic iosConfig = config.ios;
  final concurrentIconUpdates = <Future<void>>[];
  if (flavor != null) {
    final String catalogName = 'AppIcon-$flavor';

    printStatus('Building iOS launcher icon for $flavor');
    for (IosIconTemplate template in generateIosIcons) {
      concurrentIconUpdates.add(
        saveNewIcons(
          template: template,
          image: image,
          catalogName: catalogName,
          // Since this is the base icon name we are using the same name for the icon as the catalog name
          iconName: catalogName,
        ),
      );
    }

    if (darkImage != null) {
      darkIconName = 'AppIcon-$flavor-Dark';
      printStatus('Building iOS dark launcher icon for $flavor');
      for (IosIconTemplate template in generateIosIcons) {
        concurrentIconUpdates.add(
          saveNewIcons(
            template: template,
            image: darkImage,
            catalogName: catalogName,
            iconName: darkIconName,
          ),
        );
      }
    }
    if (tintedImage != null) {
      tintedIconName = 'AppIcon-$flavor-Tinted';
      printStatus('Building iOS tinted launcher icon for $flavor');
      for (IosIconTemplate template in generateIosIcons) {
        concurrentIconUpdates.add(
          saveNewIcons(
            template: template,
            image: tintedImage,
            catalogName: catalogName,
            iconName: tintedIconName,
          ),
        );
      }
    }
    iconName = iosDefaultIconName;
    await changeIosLauncherIcon(catalogName, flavor);
    await modifyContentsFile(catalogName, darkIconName, tintedIconName);
  } else if (iosConfig is String) {
    // If the IOS configuration is a string then the user has specified a new icon to be created
    // and for the old icon file to be kept
    final String newIconName = iosConfig;
    printStatus('Adding new iOS launcher icon');
    for (IosIconTemplate template in generateIosIcons) {
      concurrentIconUpdates.add(
        saveNewIcons(
          template: template,
          image: image,
          catalogName: 'AppIcon',
          iconName: newIconName,
        ),
      );
    }
    if (darkImage != null) {
      darkIconName = newIconName + '-Dark';
      printStatus('Adding new iOS dark launcher icon');
      for (IosIconTemplate template in generateIosIcons) {
        concurrentIconUpdates.add(
          saveNewIcons(
            template: template,
            image: darkImage,
            catalogName: 'AppIcon',
            iconName: darkIconName,
          ),
        );
      }
    }
    if (tintedImage != null) {
      tintedIconName = newIconName + '-Tinted';
      printStatus('Adding new iOS tinted launcher icon');
      for (IosIconTemplate template in generateIosIcons) {
        concurrentIconUpdates.add(
          saveNewIcons(
            template: template,
            image: tintedImage,
            catalogName: 'AppIcon',
            iconName: tintedIconName,
          ),
        );
      }
    }
    iconName = newIconName;
    await changeIosLauncherIcon(iconName, flavor);
    await modifyContentsFile(iconName, darkIconName, tintedIconName);
  }
  // Otherwise the user wants the new icon to use the default icons name and
  // update config file to use it
  else {
    printStatus('Overwriting default iOS launcher icon with new icon');
    for (IosIconTemplate template in generateIosIcons) {
      concurrentIconUpdates.add(overwriteDefaultIcons(template, image));
    }
    if (darkImage != null) {
      printStatus('Overwriting default iOS dark launcher icon with new icon');
      for (IosIconTemplate template in generateIosIcons) {
        concurrentIconUpdates.add(overwriteDefaultIcons(template, darkImage, '-Dark'));
      }
      darkIconName = iosDefaultIconName + '-Dark';
    }
    if (tintedImage != null) {
      printStatus('Overwriting default iOS tinted launcher icon with new icon');
      for (IosIconTemplate template in generateIosIcons) {
        concurrentIconUpdates.add(overwriteDefaultIcons(template, tintedImage, '-Tinted'));
      }
      tintedIconName = iosDefaultIconName + '-Tinted';
    }
    iconName = iosDefaultIconName;
    await changeIosLauncherIcon('AppIcon', flavor);
    // Still need to modify the Contents.json file
    // since the user could have added dark and tinted icons
    await modifyDefaultContentsFile(iconName, darkIconName, tintedIconName);
  }
  await Future.wait(concurrentIconUpdates);
}