updateContentOfStoryboard function
Update the default storyboard content with the provided details Image, Color and contentMode
Implementation
Future<void> updateContentOfStoryboard({
String? imagePath,
String? color,
String? iosContentMode,
String? backgroundImage,
String? iosBackgroundContentMode,
String? darkColor,
String? darkBackgroundImage,
}) async {
final file = File(CmdStrings.storyboardPath);
final xmlDocument = XmlDocument.parse(file.readAsStringSync());
final documentData = xmlDocument.getElement(
IOSStrings.documentElement,
);
/// Find the default view in the storyboard
final view = documentData?.descendants
.whereType<XmlElement>()
.firstWhereOrNull((element) {
return element.name.qualified == IOSStrings.viewElement &&
element.getAttribute(IOSStrings.viewIdAttr) == IOSStrings.defaultViewId;
});
if (view == null) {
throw SplashMasterException(
message:
'Default Flutter view with ${IOSStrings.defaultViewId} ID not found.',
);
}
final resolvedColor = color ?? IOSStrings.defaultColor;
// Dark mode requires an Asset Catalog color set (.colorset);
// an inline storyboard color cannot express appearance variants.
// resolvedColor serves as the light variant.
if (darkColor != null) {
await createLaunchBackgroundColorSet(
lightColor: resolvedColor,
darkColor: darkColor,
);
_setNamedBackgroundColor(view);
} else if (color != null) {
await _removeLaunchBackgroundColorSet();
/// Update or add a `color` element for the background color
final colorElement = view.getElement(IOSStrings.colorElement);
if (colorElement != null) {
/// Update existing color with provided color code
_updateColorAttributes(colorElement, color);
} else {
/// Add a new color element with provided color code
view.children.add(XmlElement(
XmlName(IOSStrings.colorElement),
_buildColorAttributes(color),
));
}
} else {
await _removeLaunchBackgroundColorSet();
final colorElement = view.getElement(IOSStrings.colorElement);
if (colorElement != null) {
/// Update existing color to white background
_updateColorAttributes(colorElement, IOSStrings.defaultColor);
} else {
/// Add a new color element with white background color as child in view element
view.children.add(XmlElement(
XmlName(IOSStrings.colorElement),
_buildColorAttributes(IOSStrings.defaultColor),
));
}
}
var shouldAddBackgroundImage = false;
if (backgroundImage != null) {
final backgroundImageFile = File(backgroundImage);
final backgroundImageFileExists = await backgroundImageFile.exists();
if (backgroundImageFileExists) {
// Per Apple's Asset Catalog spec, a Dark appearance variant requires a base
// "Any" appearance asset. Both are resolved here together before writing the image set.
File? darkBackgroundImageFile;
if (darkBackgroundImage != null) {
final file = File(darkBackgroundImage);
if (await file.exists()) {
darkBackgroundImageFile = file;
} else {
throw SplashMasterException(
message: 'Asset not found. $darkBackgroundImage',
);
}
}
await createBackgroundImage(
const Image(
scale: '3x',
filename: '${IOSStrings.backgroundImageSnakeCase}.png',
idiom: 'universal',
),
backgroundImageFile,
darkImageFile: darkBackgroundImageFile,
);
shouldAddBackgroundImage = true;
} else {
throw SplashMasterException(message: 'Asset not found. $backgroundImage');
}
} else {
await _removeBackgroundImageSet();
}
final shouldRenderImageViews = imagePath != null || shouldAddBackgroundImage;
if (shouldRenderImageViews) {
/// Find (or create) subViews element in the storyboard only when needed.
final subViews = _getOrCreateSubViews(view);
/// Keep the storyboard idempotent by recreating the managed image nodes.
_removeManagedImageViews(subViews);
if (shouldAddBackgroundImage) {
subViews.children.add(getImageXMLElement(
elementId: IOSStrings.backgroundImageViewIdValue,
imageName: IOSStrings.backgroundImage,
contentMode: iosBackgroundContentMode ?? IOSStrings.contentModeValue,
));
}
if (imagePath != null) {
subViews.children.add(getImageXMLElement(
elementId: IOSStrings.defaultImageViewIdValue,
imageName: IOSStrings.imageValue,
contentMode: iosContentMode ?? IOSStrings.contentModeValue,
));
}
/// Remove all existing constraints elements to avoid duplicates
view.children.removeWhere(
(node) =>
node is XmlElement &&
node.name.qualified == IOSStrings.constraintsElement,
);
/// Add constraints in view element based on requested content modes.
final constraintsElement = _buildConstraintsElement(
includeSplashImage: imagePath != null,
splashContentMode: iosContentMode ?? IOSStrings.contentModeValue,
includeBackgroundImage: shouldAddBackgroundImage,
backgroundContentMode:
iosBackgroundContentMode ?? IOSStrings.contentModeValue,
);
if (constraintsElement != null) {
view.children.add(constraintsElement);
}
} else {
/// Remove all existing constraints elements
view.children.removeWhere(
(node) =>
node is XmlElement &&
node.name.qualified == IOSStrings.constraintsElement,
);
final subviewsTag = view.getElement(IOSStrings.subViewsElement);
/// subview element
subviewsTag?.remove();
}
_syncStoryboardImageResources(
documentData,
includeLaunchImage: imagePath != null,
includeBackgroundImage: shouldAddBackgroundImage,
);
/// Write the updated storyboard content to the file.
file.writeAsStringSync(
'${xmlDocument.toXmlString(pretty: true, indent: ' ')}\n',
);
}