diff --git a/CHANGELOG.md b/CHANGELOG.md index daeabe5..0f51e9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## [1.0.0] - (2021-Feb-19) + +* Adds null safety. Closes [#127](https://github.com/jonbhanson/flutter_native_splash/issues/127). + ## [0.3.0] - (2021-Feb-10) * Added support for web. Closes [#30](https://github.com/jonbhanson/flutter_native_splash/issues/30). diff --git a/README.md b/README.md index c65fa35..7ad5f3c 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ First, add `flutter_native_splash` as a dev dependency in your pubspec.yaml file ```yaml dev_dependencies: - flutter_native_splash: ^0.3.0 + flutter_native_splash: ^1.0.0 ``` Don't forget to `flutter pub get`. @@ -105,6 +105,7 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return FutureBuilder( + // Replace the 3 second delay with your initialization code: future: Future.delayed(Duration(seconds: 3)), builder: (context, AsyncSnapshot snapshot) { // Show splash screen while waiting for app resources to load: @@ -153,7 +154,7 @@ Not at this time. However, you may want to consider a secondary splash screen t # Notes * If splash screen was not updated properly on iOS or if you experience a white screen before splash screen, run `flutter clean` and recompile your app. If that does not solve the problem, delete your app from the device, power down the device, power up device, install and launch app as per [this stackoverflow thread](https://stackoverflow.com/questions/33002829/ios-keeping-old-launch-screen-and-app-icon-after-update). -* This package modifies `launch_background.xml`, and `styles.xml` files on Android and `LaunchScreen.storyboard`, and `Info.plist` on iOS. If you modified this files manually this plugin may not work properly, please [open an issue](https://github.com//jonbhanson/flutter_native_splash/issues/new?template=bug_report.md) if you find any bugs. +* This package modifies `launch_background.xml` and `styles.xml` files on Android, `LaunchScreen.storyboard` and `Info.plist` on iOS, and `index.html` on Web. If you have modified these files manually, this plugin may not work properly. Please [open an issue](https://github.com//jonbhanson/flutter_native_splash/issues/new?template=bug_report.md) if you find any bugs. # How it works ## Android diff --git a/example/pubspec.yaml b/example/pubspec.yaml index bb01938..fa369a4 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -18,7 +18,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: ">=2.7.0 <3.0.0" + sdk: '>=2.12.0-0 <3.0.0' dependencies: flutter: diff --git a/lib/android.dart b/lib/android.dart index 381f5a7..e81dd9b 100644 --- a/lib/android.dart +++ b/lib/android.dart @@ -4,7 +4,8 @@ part of flutter_native_splash_supported_platform; class _AndroidDrawableTemplate { final String directoryName; final double divider; - _AndroidDrawableTemplate({this.directoryName, this.divider}); + _AndroidDrawableTemplate( + {required this.directoryName, required this.divider}); } final List<_AndroidDrawableTemplate> _splashImages = <_AndroidDrawableTemplate>[ @@ -27,13 +28,13 @@ final List<_AndroidDrawableTemplate> _splashImagesDark = ]; /// Create Android splash screen -void _createAndroidSplash( - {String imagePath, - String darkImagePath, - String color, - String darkColor, - String gravity, - bool fullscreen}) async { +Future _createAndroidSplash( + {required String imagePath, + required String darkImagePath, + required String color, + required String darkColor, + required String gravity, + required bool fullscreen}) async { if (imagePath.isNotEmpty) { await _applyImageAndroid(imagePath: imagePath); } @@ -87,7 +88,8 @@ void _createAndroidSplash( } /// Create splash screen as drawables for multiple screens (dpi) -void _applyImageAndroid({String imagePath, bool dark = false}) { +Future _applyImageAndroid( + {required String imagePath, bool dark = false}) async { print('[Android] Creating ' + (dark ? 'dark mode ' : '') + 'splash images'); final file = File(imagePath); @@ -97,6 +99,9 @@ void _applyImageAndroid({String imagePath, bool dark = false}) { } final image = decodeImage(File(imagePath).readAsBytesSync()); + if (image == null) { + throw _NoImageFileFoundException('The file $imagePath could not be read.'); + } for (var template in dark ? _splashImagesDark : _splashImages) { _saveImageAndroid(template: template, image: image); @@ -106,7 +111,8 @@ void _applyImageAndroid({String imagePath, bool dark = false}) { /// Saves splash screen image to the project /// Note: Do not change interpolation unless you end up with better results /// https://github.com/fluttercommunity/flutter_launcher_icons/issues/101#issuecomment-495528733 -void _saveImageAndroid({_AndroidDrawableTemplate template, Image image}) { +void _saveImageAndroid( + {required _AndroidDrawableTemplate template, required Image image}) { var newFile = copyResize( image, width: image.width ~/ template.divider, @@ -123,9 +129,9 @@ void _saveImageAndroid({_AndroidDrawableTemplate template, Image image}) { /// Create or update launch_background.xml adding splash image path Future _applyLaunchBackgroundXml({ - String gravity, - String launchBackgroundFilePath, - bool showImage, + required String gravity, + required String launchBackgroundFilePath, + required bool showImage, }) { final launchBackgroundFile = File(launchBackgroundFilePath); @@ -157,7 +163,9 @@ Future _applyLaunchBackgroundXml({ /// Updates launch_background.xml adding splash image path Future _updateLaunchBackgroundFileWithImagePath( - {String launchBackgroundFilePath, String gravity, bool showImage}) async { + {required String launchBackgroundFilePath, + required String gravity, + required bool showImage}) async { final launchBackgroundFile = File(launchBackgroundFilePath); var launchBackgroundDocument; if (launchBackgroundFile.existsSync()) { @@ -190,7 +198,7 @@ Future _updateLaunchBackgroundFileWithImagePath( if (showImage) { var splashItem = XmlDocument.parse(_androidLaunchBackgroundItemXml).rootElement.copy(); - splashItem.getElement('bitmap').setAttribute('android:gravity', gravity); + splashItem.getElement('bitmap')?.setAttribute('android:gravity', gravity); items.add(splashItem); } launchBackgroundFile.writeAsStringSync( @@ -199,22 +207,24 @@ Future _updateLaunchBackgroundFileWithImagePath( /// Creates launch_background.xml with splash image path Future _createLaunchBackgroundFileWithImagePath( - {String gravity, String launchBackgroundFilePath, bool showImage}) async { + {required String gravity, + required String launchBackgroundFilePath, + required bool showImage}) async { var file = await File(launchBackgroundFilePath).create(recursive: true); var fileContent = XmlDocument.parse(_androidLaunchBackgroundXml); if (showImage) { var splashItem = XmlDocument.parse(_androidLaunchBackgroundItemXml).rootElement.copy(); - splashItem.getElement('bitmap').setAttribute('android:gravity', gravity); - fileContent.getElement('layer-list').children.add(splashItem); + splashItem.getElement('bitmap')?.setAttribute('android:gravity', gravity); + fileContent.getElement('layer-list')?.children.add(splashItem); } return await file .writeAsString(fileContent.toXmlString(pretty: true, indent: ' ')); } /// Create or update colors.xml adding splash screen background color -Future _applyColor({color, String colorFile}) async { +Future _applyColor({color, required String colorFile}) async { var colorsXml = File(colorFile); color = '#' + color; @@ -233,7 +243,8 @@ Future _applyColor({color, String colorFile}) async { } /// Updates the colors.xml with the splash screen background color -void _updateColorsFileWithColor({File colorsFile, String color}) { +void _updateColorsFileWithColor( + {required File colorsFile, required String color}) { final lines = colorsFile.readAsLinesSync(); var foundExisting = false; @@ -264,7 +275,7 @@ void _updateColorsFileWithColor({File colorsFile, String color}) { } /// Creates a colors.xml file if it was missing from android/app/src/main/res/values/colors.xml -void _createColorsFile({String color, File colorsXml}) { +void _createColorsFile({required String color, required File colorsXml}) { colorsXml.create(recursive: true).then((File colorsFile) { colorsFile.writeAsString(_androidColorsXml).then((File file) { _updateColorsFileWithColor(colorsFile: colorsFile, color: color); @@ -277,7 +288,7 @@ void _createColorsFile({String color, File colorsXml}) { /// /// Note: default color = "splash_color" Future _overwriteLaunchBackgroundWithNewSplashColor( - {String color, String launchBackgroundFilePath}) async { + {required String color, required String launchBackgroundFilePath}) async { final launchBackgroundFile = File(launchBackgroundFilePath); final lines = await launchBackgroundFile.readAsLines(); @@ -302,7 +313,7 @@ Future _overwriteLaunchBackgroundWithNewSplashColor( } /// Create or update styles.xml full screen mode setting -Future _applyStylesXml({bool fullScreen}) async { +Future _applyStylesXml({required bool fullScreen}) async { final stylesFile = File(_androidStylesFile); if (!stylesFile.existsSync()) { @@ -316,7 +327,8 @@ Future _applyStylesXml({bool fullScreen}) async { } /// Updates styles.xml adding full screen property -Future _updateStylesFile({bool fullScreen, File stylesFile}) async { +Future _updateStylesFile( + {required bool fullScreen, required File stylesFile}) async { final stylesDocument = XmlDocument.parse(await stylesFile.readAsString()); final styles = stylesDocument.findAllElements('style'); if (styles.length == 1) { @@ -325,19 +337,24 @@ Future _updateStylesFile({bool fullScreen, File stylesFile}) async { 'embedding. Skipping update of styles.xml with fullscreen mode'); return; } + var found = true; final launchTheme = styles.firstWhere( (element) => (element.attributes.any((attribute) => attribute.name.toString() == 'name' && - attribute.value == 'LaunchTheme')), - orElse: () => null); - if (launchTheme != null) { + attribute.value == 'LaunchTheme')), orElse: () { + found = false; + return XmlElement(XmlName('dummy')); + }); + if (found) { final fullScreenElement = launchTheme.children.firstWhere( (element) => (element.attributes.any((attribute) { return attribute.name.toString() == 'name' && attribute.value == 'android:windowFullscreen'; - })), - orElse: () => null); - if (fullScreenElement == null) { + })), orElse: () { + found = false; + return XmlElement(XmlName('dummy')); + }); + if (found) { launchTheme.children.add(XmlElement( XmlName('item'), [XmlAttribute(XmlName('name'), 'android:windowFullscreen')], @@ -354,7 +371,7 @@ Future _updateStylesFile({bool fullScreen, File stylesFile}) async { } /// Creates styles.xml with full screen property -void _createStylesFileWithImagePath({File stylesFile}) { +void _createStylesFileWithImagePath({required File stylesFile}) { stylesFile.createSync(recursive: true); stylesFile.writeAsStringSync(_androidStylesXml); } diff --git a/lib/exceptions.dart b/lib/exceptions.dart index 76d1f3a..c623698 100644 --- a/lib/exceptions.dart +++ b/lib/exceptions.dart @@ -1,7 +1,7 @@ part of flutter_native_splash_supported_platform; class _NoConfigFoundException implements Exception { - const _NoConfigFoundException([this.message]); + const _NoConfigFoundException(this.message); final String message; @override @@ -13,7 +13,7 @@ class _NoConfigFoundException implements Exception { } class _InvalidConfigException implements Exception { - const _InvalidConfigException([this.message]); + const _InvalidConfigException(this.message); final String message; @override @@ -25,7 +25,7 @@ class _InvalidConfigException implements Exception { } class _NoImageFileFoundException implements Exception { - const _NoImageFileFoundException([this.message]); + const _NoImageFileFoundException(this.message); final String message; @override @@ -37,7 +37,7 @@ class _NoImageFileFoundException implements Exception { } class _InvalidNativeFile implements Exception { - const _InvalidNativeFile([this.message]); + const _InvalidNativeFile(this.message); final String message; @override @@ -49,7 +49,7 @@ class _InvalidNativeFile implements Exception { } class _LaunchScreenStoryboardModified implements Exception { - const _LaunchScreenStoryboardModified([this.message]); + const _LaunchScreenStoryboardModified(this.message); final String message; @override @@ -61,7 +61,7 @@ class _LaunchScreenStoryboardModified implements Exception { } class _CantFindInfoPlistFile implements Exception { - const _CantFindInfoPlistFile([this.message]); + const _CantFindInfoPlistFile(this.message); final String message; @override diff --git a/lib/ios.dart b/lib/ios.dart index 9c1bd48..39177f0 100644 --- a/lib/ios.dart +++ b/lib/ios.dart @@ -5,7 +5,7 @@ class _IosLaunchImageTemplate { final String fileName; final double divider; - _IosLaunchImageTemplate({this.fileName, this.divider}); + _IosLaunchImageTemplate({required this.fileName, required this.divider}); } final List<_IosLaunchImageTemplate> _iOSSplashImages = @@ -25,14 +25,14 @@ final List<_IosLaunchImageTemplate> _iOSSplashImagesDark = ]; /// Create iOS splash screen -void _createiOSSplash({ - String imagePath, - String darkImagePath, - String color, - String darkColor, - List plistFiles, - String iosContentMode, - bool fullscreen, +Future _createiOSSplash({ + required String imagePath, + required String darkImagePath, + required String color, + required String darkColor, + List? plistFiles, + required String iosContentMode, + required bool fullscreen, }) async { if (imagePath.isNotEmpty) { await _applyImageiOS(imagePath: imagePath); @@ -70,20 +70,25 @@ void _createiOSSplash({ } /// Create splash screen images for original size, @2x and @3x -void _applyImageiOS({String imagePath, bool dark = false}) { +Future _applyImageiOS( + {required String imagePath, bool dark = false}) async { print('[iOS] Creating ' + (dark ? 'dark mode ' : '') + 'splash images'); if (!File(imagePath).existsSync()) { throw _NoImageFileFoundException('The file $imagePath was not found.'); } final image = decodeImage(File(imagePath).readAsBytesSync()); + if (image == null) { + throw _NoImageFileFoundException(imagePath + ' could not be loaded.'); + } for (var template in dark ? _iOSSplashImagesDark : _iOSSplashImages) { _saveImageiOS(template: template, image: image); } } /// Saves splash screen image to the project -void _saveImageiOS({_IosLaunchImageTemplate template, Image image}) { +void _saveImageiOS( + {required _IosLaunchImageTemplate template, required Image image}) { var newFile = copyResize( image, width: image.width ~/ template.divider, @@ -99,7 +104,8 @@ void _saveImageiOS({_IosLaunchImageTemplate template, Image image}) { } /// Update LaunchScreen.storyboard adding width, height and color -Future _applyLaunchScreenStoryboard({String imagePath, String iosContentMode}) { +Future _applyLaunchScreenStoryboard( + {required String imagePath, required String iosContentMode}) { final file = File(_iOSLaunchScreenStoryboardFile); if (file.existsSync()) { @@ -117,7 +123,7 @@ Future _applyLaunchScreenStoryboard({String imagePath, String iosContentMode}) { /// Updates LaunchScreen.storyboard adding splash image path Future _updateLaunchScreenStoryboard( - {String imagePath, String iosContentMode}) async { + {required String imagePath, required String iosContentMode}) async { // Load the data final file = File(_iOSLaunchScreenStoryboardFile); final xmlDocument = XmlDocument.parse(file.readAsStringSync()); @@ -125,7 +131,7 @@ Future _updateLaunchScreenStoryboard( // Find the view that contains the splash image final view = - documentData.descendants.whereType().firstWhere((element) { + documentData?.descendants.whereType().firstWhere((element) { return (element.name.qualified == 'view' && element.getAttribute('id') == 'Ze5-6b-2t3'); }); @@ -136,47 +142,37 @@ Future _updateLaunchScreenStoryboard( // Find the splash imageView final subViews = view.getElement('subviews'); - final imageView = subViews.children.whereType().firstWhere( + final imageView = subViews?.children.whereType().firstWhere( (element) => (element.name.qualified == 'imageView' && element.getAttribute('image') == 'LaunchImage')); - final backgroundView = subViews.children.whereType().firstWhere( + subViews?.children.whereType().firstWhere( (element) => (element.name.qualified == 'imageView' && - element.getAttribute('image') == 'LaunchBackground'), - orElse: () => null); + element.getAttribute('image') == 'LaunchBackground'), orElse: () { + subViews.children.insert( + 0, XmlDocument.parse(_iOSLaunchBackgroundSubview).rootElement.copy()); + return XmlElement(XmlName('')); + }); // Update the fill property - imageView.setAttribute('contentMode', iosContentMode); + imageView?.setAttribute('contentMode', iosContentMode); // Find the resources - final resources = documentData.getElement('resources'); - var launchImageResource = resources.children - .whereType() - .firstWhere( - (element) => (element.name.qualified == 'image' && - element.getAttribute('name') == 'LaunchImage'), - orElse: () => null); - if (launchImageResource == null) { - throw _LaunchScreenStoryboardModified( - "Not able to find 'LaunchImage' image tag in LaunchScreen.storyboard. Image for splash screen not updated. Did you modify your default LaunchScreen.storyboard file?"); - } - final launchBackgroundResource = resources.children - .whereType() - .firstWhere( - (element) => (element.name.qualified == 'image' && - element.getAttribute('name') == 'LaunchBackground'), - orElse: () => null); - - // If the color has not been set via background image, set it here: - if (launchBackgroundResource == null) { + final resources = documentData?.getElement('resources'); + var launchImageResource = resources?.children.whereType().firstWhere( + (element) => (element.name.qualified == 'image' && + element.getAttribute('name') == 'LaunchImage'), + orElse: () => throw _LaunchScreenStoryboardModified( + "Not able to find 'LaunchImage' image tag in LaunchScreen.storyboard. Image for splash screen not updated. Did you modify your default LaunchScreen.storyboard file?")); + + resources?.children.whereType().firstWhere( + (element) => (element.name.qualified == 'image' && + element.getAttribute('name') == 'LaunchBackground'), orElse: () { + // If the color has not been set via background image, set it here: resources.children.add(XmlDocument.parse( '') .rootElement .copy()); - } - - if (backgroundView == null) { - subViews.children.insert( - 0, XmlDocument.parse(_iOSLaunchBackgroundSubview).rootElement.copy()); - } + return XmlElement(XmlName('')); + }); view.children.remove(view.getElement('constraints')); view.children.add( @@ -188,8 +184,11 @@ Future _updateLaunchScreenStoryboard( } final image = decodeImage(File(imagePath).readAsBytesSync()); - launchImageResource.setAttribute('width', image.width.toString()); - launchImageResource.setAttribute('height', image.height.toString()); + if (image == null) { + throw _NoImageFileFoundException(imagePath + ' could not be loaded.'); + } + launchImageResource?.setAttribute('width', image.width.toString()); + launchImageResource?.setAttribute('height', image.height.toString()); } file.writeAsStringSync(xmlDocument.toXmlString(pretty: true, indent: ' ')); @@ -197,7 +196,7 @@ Future _updateLaunchScreenStoryboard( /// Creates LaunchScreen.storyboard with splash image path Future _createLaunchScreenStoryboard( - {String imagePath, String iosContentMode}) async { + {required String imagePath, required String iosContentMode}) async { var file = await File(_iOSLaunchScreenStoryboardFile).create(recursive: true); await file.writeAsString(_iOSLaunchScreenStoryboardContent); return _updateLaunchScreenStoryboard( @@ -205,7 +204,7 @@ Future _createLaunchScreenStoryboard( } Future _createBackgroundColor( - {String colorString, String darkColorString}) async { + {required String colorString, required String darkColorString}) async { var background = Image(1, 1); var redChannel = int.parse(colorString.substring(0, 2), radix: 16); var greenChannel = int.parse(colorString.substring(2, 4), radix: 16); @@ -241,7 +240,8 @@ Future _createBackgroundColor( } /// Update Info.plist for status bar behaviour (hidden/visible) -Future _applyInfoPList({List plistFiles, bool fullscreen}) async { +Future _applyInfoPList( + {List? plistFiles, required bool fullscreen}) async { if (plistFiles == null) { plistFiles = []; plistFiles.add(_iOSInfoPlistFile); @@ -261,12 +261,17 @@ Future _applyInfoPList({List plistFiles, bool fullscreen}) async { } /// Update Infop.list with status bar hidden directive -Future _updateInfoPlistFile({String plistFile, bool fullscreen}) async { +Future _updateInfoPlistFile( + {required String plistFile, required bool fullscreen}) async { // Load the data final file = File(plistFile); final xmlDocument = XmlDocument.parse(file.readAsStringSync()); - final dict = xmlDocument.getElement('plist').getElement('dict'); + final dict = xmlDocument.getElement('plist')?.getElement('dict'); + if (dict == null) { + throw Exception(plistFile + ' plist dict element not found'); + } + var elementFound = true; final uIStatusBarHidden = dict.children.whereType().firstWhere((element) { return (element.text == 'UIStatusBarHidden'); @@ -277,16 +282,18 @@ Future _updateInfoPlistFile({String plistFile, bool fullscreen}) async { }); dict.children.add(builder.buildFragment()); dict.children.add(XmlElement(XmlName(fullscreen.toString()))); - return null; + elementFound = false; + return XmlElement(XmlName('')); }); - if (uIStatusBarHidden != null) { + if (elementFound) { var index = dict.children.indexOf(uIStatusBarHidden); var uIStatusBarHiddenValue = dict.children[index + 1].following .firstWhere((element) => element.nodeType == XmlNodeType.ELEMENT); uIStatusBarHiddenValue.replace(XmlElement(XmlName(fullscreen.toString()))); } + elementFound = true; if (fullscreen) { final uIViewControllerBasedStatusBarAppearance = dict.children.whereType().firstWhere((element) { @@ -298,10 +305,11 @@ Future _updateInfoPlistFile({String plistFile, bool fullscreen}) async { }); dict.children.add(builder.buildFragment()); dict.children.add(XmlElement(XmlName((!fullscreen).toString()))); - return null; + elementFound = false; + return XmlElement(XmlName('')); }); - if (uIViewControllerBasedStatusBarAppearance != null) { + if (elementFound) { var index = dict.children.indexOf(uIViewControllerBasedStatusBarAppearance); diff --git a/lib/supported_platform.dart b/lib/supported_platform.dart index 8c0d5e3..2153b58 100644 --- a/lib/supported_platform.dart +++ b/lib/supported_platform.dart @@ -38,7 +38,7 @@ Future tryCreateSplashByConfig(Map config) async { String image = config['image'] ?? ''; String darkImage = config['image_dark'] ?? ''; var color = _parseColor(config['color']); - var darkColor = _parseColor(config['color_dark']) ?? ''; + var darkColor = _parseColor(config['color_dark']); var plistFiles = config['info_plist_files']; var gravity = (config['fill'] ?? false) ? 'fill' : 'center'; if (config['android_gravity'] != null) gravity = config['android_gravity']; @@ -86,7 +86,7 @@ String _parseColor(var color) { color = color.replaceAll('#', '').replaceAll(' ', ''); if (color.length == 6) return color; } - if (color == null) return null; + if (color == null) return ''; throw Exception('Invalid color value'); } @@ -103,19 +103,23 @@ Map _getConfig() { final yamlString = file.readAsStringSync(); final Map yamlMap = loadYaml(yamlString); - if (yamlMap == null || !(yamlMap['flutter_native_splash'] is Map)) { + if (!(yamlMap['flutter_native_splash'] is Map)) { stderr.writeln(_NoConfigFoundException( 'Your `$filePath` file does not contain a `flutter_native_splash` section.')); exit(1); } - // yamlMap has the type YamlMap, which has several unwanted sideeffects + // yamlMap has the type YamlMap, which has several unwanted side effects final config = {}; for (MapEntry entry in yamlMap['flutter_native_splash'].entries) { if (entry.value is YamlList) { var list = []; - (entry.value as YamlList).forEach(list.add); + (entry.value as YamlList).forEach((dynamic value) { + if (value is String) { + list.add(value); + } + }); config[entry.key] = list; } else { config[entry.key] = entry.value; diff --git a/lib/unsupported_platform.dart b/lib/unsupported_platform.dart index 6e01532..b9d2020 100644 --- a/lib/unsupported_platform.dart +++ b/lib/unsupported_platform.dart @@ -15,7 +15,7 @@ void tryCreateSplashByConfig(Map config) async { } /// Function that will be called on unsupported platforms, triggering exception. -void tryCreateSplash() async { +Future tryCreateSplash() async { throw UnsupportedError( 'This package requires dart:io, which is unsupported by this platform.'); } diff --git a/lib/web.dart b/lib/web.dart index 6f0caae..3a846ca 100644 --- a/lib/web.dart +++ b/lib/web.dart @@ -4,16 +4,16 @@ part of flutter_native_splash_supported_platform; class _WebLaunchImageTemplate { final String fileName; final double divider; - _WebLaunchImageTemplate({this.fileName, this.divider}); + _WebLaunchImageTemplate({required this.fileName, required this.divider}); } /// Create Android splash screen Future _createWebSplash({ - String imagePath, - String darkImagePath, - String color, - String darkColor, - String imageMode, + required String imagePath, + required String darkImagePath, + required String color, + required String darkColor, + required String imageMode, }) async { if (!File(_webIndex).existsSync()) { print('[Web] ' + _webIndex + ' not found. Skipping Web.'); @@ -35,8 +35,9 @@ Future _createWebSplash({ await updateIndex(imageMode: imageMode, showImages: imagePath.isNotEmpty); } -void createWebImages( - {String imagePath, List<_WebLaunchImageTemplate> webSplashImages}) async { +Future createWebImages( + {required String imagePath, + required List<_WebLaunchImageTemplate> webSplashImages}) async { if (imagePath.isEmpty) { for (var template in webSplashImages) { final file = File(_webSplashImagesFolder + template.fileName); @@ -44,6 +45,9 @@ void createWebImages( } } else { final image = decodeImage(File(imagePath).readAsBytesSync()); + if (image == null) { + throw _NoImageFileFoundException(imagePath + ' could not be read'); + } print('[Web] Creating images'); for (var template in webSplashImages) { await _saveImageWeb(template: template, image: image); @@ -51,7 +55,8 @@ void createWebImages( } } -dynamic _saveImageWeb({_WebLaunchImageTemplate template, Image image}) async { +dynamic _saveImageWeb( + {required _WebLaunchImageTemplate template, required Image image}) async { var newFile = await copyResize( image, width: image.width ~/ template.divider, @@ -64,7 +69,8 @@ dynamic _saveImageWeb({_WebLaunchImageTemplate template, Image image}) async { await file.writeAsBytes(encodePng(newFile)); } -void createSplashCss({String color, String darkColor}) { +Future createSplashCss( + {required String color, required String darkColor}) async { print('[Web] Creating CSS'); if (darkColor.isEmpty) darkColor = color; var cssContent = _webCss @@ -73,7 +79,8 @@ void createSplashCss({String color, String darkColor}) { File(_webFolder + _webRelativeStyleFile).writeAsStringSync(cssContent); } -void updateIndex({String imageMode, bool showImages}) async { +Future updateIndex( + {required String imageMode, required bool showImages}) async { print('[Web] Updating index.html'); final webIndex = File(_webIndex); var lines = webIndex.readAsLinesSync(); diff --git a/pubspec.lock b/pubspec.lock index ff913ec..83412d6 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,14 +7,7 @@ packages: name: archive url: "https://pub.dartlang.org" source: hosted - version: "2.0.13" - args: - dependency: transitive - description: - name: args - url: "https://pub.dartlang.org" - source: hosted - version: "1.6.0" + version: "3.0.0" charcode: dependency: transitive description: @@ -29,27 +22,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.15.0" - convert: - dependency: transitive - description: - name: convert - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.1" crypto: dependency: transitive description: name: crypto url: "https://pub.dartlang.org" source: hosted - version: "2.1.5" + version: "3.0.0" image: dependency: "direct main" description: name: image url: "https://pub.dartlang.org" source: hosted - version: "2.1.19" + version: "3.0.0-nullsafety.0" meta: dependency: transitive description: @@ -77,7 +63,7 @@ packages: name: petitparser url: "https://pub.dartlang.org" source: hosted - version: "3.1.0" + version: "4.0.2" source_span: dependency: transitive description: @@ -112,13 +98,13 @@ packages: name: xml url: "https://pub.dartlang.org" source: hosted - version: "4.5.1" + version: "5.0.2" yaml: dependency: "direct main" description: name: yaml url: "https://pub.dartlang.org" source: hosted - version: "2.2.1" + version: "3.0.0" sdks: dart: ">=2.12.0-0.0 <3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 25dea8e..aa7da72 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,15 +1,15 @@ name: flutter_native_splash description: Generates native code to customize Flutter's default white native splash screen with background color and splash image. Supports dark mode, full screen, and more. -version: 0.3.0 +version: 1.0.0 homepage: https://github.com/jonbhanson/flutter_native_splash environment: - sdk: ">=2.2.0 <3.0.0" + sdk: '>=2.12.0-0 <3.0.0' dependencies: - yaml: ^2.2.1 - image: ^2.1.19 - xml: ^4.5.1 + yaml: ^3.0.0 + image: ^3.0.0-nullsafety.0 + xml: ^5.0.2 dev_dependencies: - pedantic: ^1.9.2 + pedantic: ^1.10.0