From 51b074c024c9d6e1f7f15594e71eae255748d81f Mon Sep 17 00:00:00 2001 From: Jon Hanson Date: Mon, 11 Jan 2021 09:37:09 -0500 Subject: [PATCH] Further modifications to raise pub points: The public API's need to have dartdoc comments, so all public declarations that did not need to be public were changed to private. Added doc comments for public APIs. --- CHANGELOG.md | 6 ++ README.md | 2 +- lib/android.dart | 148 ++++++++++++++++----------------- lib/constants.dart | 30 +++---- lib/exceptions.dart | 30 +++---- lib/flutter_native_splash.dart | 6 +- lib/ios.dart | 118 +++++++++++++------------- lib/supported_platform.dart | 33 ++++++-- lib/templates.dart | 62 +++++++------- lib/unsupported_platform.dart | 12 ++- pubspec.yaml | 2 +- 11 files changed, 239 insertions(+), 210 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f11d842..2247d0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [0.2.3] - (2021-Jan-11) + +* Further modifications to raise [pub points](https://pub.dev/help/scoring): The +public API's need to have dartdoc comments, so all public declarations that did not +need to be public were changed to private. Added doc comments for public APIs. + ## [0.2.2] - (2021-Jan-09) * Corrected color of background PNG for iOS. ([The channel order of a uint32 encoded color is BGRA.](https://pub.dev/documentation/image/latest/image/Color/fromRgb.html)) ([#115](https://github.com/henriquearthur/flutter_native_splash/issues/115)) diff --git a/README.md b/README.md index 6ac19b3..45d1bd1 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ First, add `flutter_native_splash` as a [dev dependency in your pubspec.yaml fil ```yaml dev_dependencies: - flutter_native_splash: ^0.2.2 + flutter_native_splash: ^0.2.3 ``` Don't forget to `flutter pub get`. diff --git a/lib/android.dart b/lib/android.dart index e13b732..7aab05d 100644 --- a/lib/android.dart +++ b/lib/android.dart @@ -1,45 +1,39 @@ -import 'dart:io'; +part of flutter_native_splash_supported_platform; -import 'package:color/color.dart'; -import 'package:flutter_native_splash/constants.dart'; -import 'package:flutter_native_splash/exceptions.dart'; -import 'package:flutter_native_splash/templates.dart' as templates; -import 'package:image/image.dart'; - -// Image template -class AndroidDrawableTemplate { +/// Image template +class _AndroidDrawableTemplate { final String directoryName; final double divider; - - AndroidDrawableTemplate({this.directoryName, this.divider}); + _AndroidDrawableTemplate({this.directoryName, this.divider}); } -final List splashImages = [ - AndroidDrawableTemplate(directoryName: 'drawable-mdpi', divider: 2.0), - AndroidDrawableTemplate(directoryName: 'drawable-hdpi', divider: 1.8), - AndroidDrawableTemplate(directoryName: 'drawable-xhdpi', divider: 1.4), - AndroidDrawableTemplate(directoryName: 'drawable-xxhdpi', divider: 1.2), - AndroidDrawableTemplate(directoryName: 'drawable-xxxhdpi', divider: 1.0), +final List<_AndroidDrawableTemplate> _splashImages = <_AndroidDrawableTemplate>[ + _AndroidDrawableTemplate(directoryName: 'drawable-mdpi', divider: 2.0), + _AndroidDrawableTemplate(directoryName: 'drawable-hdpi', divider: 1.8), + _AndroidDrawableTemplate(directoryName: 'drawable-xhdpi', divider: 1.4), + _AndroidDrawableTemplate(directoryName: 'drawable-xxhdpi', divider: 1.2), + _AndroidDrawableTemplate(directoryName: 'drawable-xxxhdpi', divider: 1.0), ]; -final List splashImagesDark = - [ - AndroidDrawableTemplate(directoryName: 'drawable-night-mdpi', divider: 2.0), - AndroidDrawableTemplate(directoryName: 'drawable-night-hdpi', divider: 1.8), - AndroidDrawableTemplate(directoryName: 'drawable-night-xhdpi', divider: 1.4), - AndroidDrawableTemplate(directoryName: 'drawable-night-xxhdpi', divider: 1.2), - AndroidDrawableTemplate( +final List<_AndroidDrawableTemplate> _splashImagesDark = + <_AndroidDrawableTemplate>[ + _AndroidDrawableTemplate(directoryName: 'drawable-night-mdpi', divider: 2.0), + _AndroidDrawableTemplate(directoryName: 'drawable-night-hdpi', divider: 1.8), + _AndroidDrawableTemplate(directoryName: 'drawable-night-xhdpi', divider: 1.4), + _AndroidDrawableTemplate( + directoryName: 'drawable-night-xxhdpi', divider: 1.2), + _AndroidDrawableTemplate( directoryName: 'drawable-night-xxxhdpi', divider: 1.0), ]; /// Create Android splash screen -void createSplash(String imagePath, String darkImagePath, String color, +void _createAndroidSplash(String imagePath, String darkImagePath, String color, String darkColor, bool fill, bool androidDisableFullscreen) async { if (imagePath.isNotEmpty) { - await _applyImage(imagePath); + await _applyImageAndroid(imagePath); } if (darkImagePath.isNotEmpty) { - await _applyImage(darkImagePath, dark: true); + await _applyImageAndroid(darkImagePath, dark: true); } await _applyLaunchBackgroundXml(imagePath, fill); @@ -72,26 +66,26 @@ String _generatePrimaryColorDarkFromColor(String color) { } /// Create splash screen as drawables for multiple screens (dpi) -void _applyImage(String imagePath, {bool dark = false}) { +void _applyImageAndroid(String imagePath, {bool dark = false}) { print('[Android] Creating ' + (dark ? 'dark mode ' : '') + 'splash images'); final file = File(imagePath); if (!file.existsSync()) { - throw NoImageFileFoundException('The file $imagePath was not found.'); + throw _NoImageFileFoundException('The file $imagePath was not found.'); } final image = decodeImage(File(imagePath).readAsBytesSync()); - for (var template in dark ? splashImagesDark : splashImages) { - _saveImage(template, image); + for (var template in dark ? _splashImagesDark : _splashImages) { + _saveImageAndroid(template, image); } } /// 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 _saveImage(AndroidDrawableTemplate template, Image image) { +void _saveImageAndroid(_AndroidDrawableTemplate template, Image image) { var newFile = copyResize( image, width: image.width ~/ template.divider, @@ -99,7 +93,7 @@ void _saveImage(AndroidDrawableTemplate template, Image image) { interpolation: Interpolation.linear, ); - File(androidResFolder + template.directoryName + '/' + 'splash.png') + File(_androidResFolder + template.directoryName + '/' + 'splash.png') .create(recursive: true) .then((File file) { file.writeAsBytesSync(encodePng(newFile)); @@ -110,7 +104,7 @@ void _saveImage(AndroidDrawableTemplate template, Image image) { Future _applyLaunchBackgroundXml(String imagePath, bool fill, {bool dark = false}) { final launchBackgroundFile = File( - dark ? androidLaunchDarkBackgroundFile : androidLaunchBackgroundFile); + dark ? _androidLaunchDarkBackgroundFile : _androidLaunchBackgroundFile); if (launchBackgroundFile.existsSync()) { if (imagePath.isNotEmpty) { @@ -135,8 +129,8 @@ Future _applyLaunchBackgroundXml(String imagePath, bool fill, /// Updates launch_background.xml adding splash image path Future _updateLaunchBackgroundFileWithImagePath(bool fill, bool dark) async { final launchBackgroundFile = dark - ? File(androidLaunchDarkBackgroundFile) - : File(androidLaunchBackgroundFile); + ? File(_androidLaunchDarkBackgroundFile) + : File(_androidLaunchBackgroundFile); final lines = await launchBackgroundFile.readAsLines(); var foundExisting = false; @@ -153,14 +147,13 @@ Future _updateLaunchBackgroundFileWithImagePath(bool fill, bool dark) async { // Add new line if we didn't find an existing value if (!foundExisting) { if (lines.isEmpty) { - throw InvalidNativeFile("File 'launch_background.xml' contains 0 lines."); + throw _InvalidNativeFile( + "File 'launch_background.xml' contains 0 lines."); } else { if (fill == null || !fill) { - lines.insert( - lines.length - 1, templates.androidLaunchBackgroundItemXml); + lines.insert(lines.length - 1, _androidLaunchBackgroundItemXml); } else { - lines.insert( - lines.length - 1, templates.androidLaunchBackgroundItemXmlFill); + lines.insert(lines.length - 1, _androidLaunchBackgroundItemXmlFill); } } } @@ -171,24 +164,23 @@ Future _updateLaunchBackgroundFileWithImagePath(bool fill, bool dark) async { /// Creates launch_background.xml with splash image path Future _createLaunchBackgroundFileWithImagePath( String imagePath, bool fill, bool dark) async { - var file = await File( - dark ? androidLaunchDarkBackgroundFile : androidLaunchBackgroundFile) + var file = await File(dark + ? _androidLaunchDarkBackgroundFile + : _androidLaunchBackgroundFile) .create(recursive: true); String fileContent; if (fill == null || !fill) { - fileContent = templates.androidLaunchBackgroundXml; + fileContent = _androidLaunchBackgroundXml; if (imagePath.isEmpty) { - fileContent = - fileContent.replaceAll(templates.androidLaunchBackgroundItemXml, ''); + fileContent = fileContent.replaceAll(_androidLaunchBackgroundItemXml, ''); } } else { - fileContent = templates.androidLaunchBackgroundXmlFill; + fileContent = _androidLaunchBackgroundXmlFill; if (imagePath.isEmpty) { - fileContent = - fileContent.replaceAll(templates.androidLaunchBackgroundXmlFill, ''); + fileContent = fileContent.replaceAll(_androidLaunchBackgroundXmlFill, ''); } } return await file.writeAsString(fileContent); @@ -196,7 +188,7 @@ Future _createLaunchBackgroundFileWithImagePath( /// Create or update colors.xml adding splash screen background color void _applyColor(color, {bool dark = false}) { - final colorsXml = File(dark ? androidColorsDarkFile : androidColorsFile); + final colorsXml = File(dark ? _androidColorsDarkFile : _androidColorsFile); if (!color.contains('#')) { color = '#' + color; @@ -241,7 +233,7 @@ void _updateColorsFileWithColor(File colorsFile, String color) { // Add new line if we didn't find an existing value if (!foundExisting) { if (lines.isEmpty) { - throw InvalidNativeFile("File 'colors.xml' contains 0 lines."); + throw _InvalidNativeFile("File 'colors.xml' contains 0 lines."); } else { lines.insert( lines.length - 1, '\t$color'); @@ -254,7 +246,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) { colorsXml.create(recursive: true).then((File colorsFile) { - colorsFile.writeAsString(templates.androidColorsXml).then((File file) { + colorsFile.writeAsString(_androidColorsXml).then((File file) { _updateColorsFileWithColor(colorsFile, color); }); }); @@ -267,7 +259,7 @@ void _createColorsFile(String color, File colorsXml) { Future _overwriteLaunchBackgroundWithNewSplashColor( String color, bool dark) async { final launchBackgroundFile = File( - dark ? androidLaunchDarkBackgroundFile : androidLaunchBackgroundFile); + dark ? _androidLaunchDarkBackgroundFile : _androidLaunchBackgroundFile); final lines = await launchBackgroundFile.readAsLines(); for (var x = 0; x < lines.length; x++) { @@ -292,7 +284,7 @@ Future _overwriteLaunchBackgroundWithNewSplashColor( /// Create or update styles.xml full screen mode setting void _applyStylesXml({bool dark = false}) { - final stylesFile = File(dark ? androidStylesDarkFile : androidStylesFile); + final stylesFile = File(dark ? _androidStylesDarkFile : _androidStylesFile); if (stylesFile.existsSync()) { print('[Android] Updating ' + @@ -331,9 +323,9 @@ Future _updateStylesFileWithImagePath(File stylesFile) async { // Add new line if we didn't find an existing value if (!foundExisting) { if (lines.isEmpty) { - throw InvalidNativeFile("File 'styles.xml' contains 0 lines."); + throw _InvalidNativeFile("File 'styles.xml' contains 0 lines."); } else { - lines.insert(endStyleLine, templates.androidStylesItemXml); + lines.insert(endStyleLine, _androidStylesItemXml); } } @@ -343,7 +335,7 @@ Future _updateStylesFileWithImagePath(File stylesFile) async { /// Creates styles.xml with full screen property void _createStylesFileWithImagePath(File stylesFile) { stylesFile.create(recursive: true).then((File colorsFile) { - colorsFile.writeAsString(templates.androidStylesXml); + colorsFile.writeAsString(_androidStylesXml); }); } @@ -376,14 +368,14 @@ Future _javaOrKotlin() async { } else if (File(mainActivityKotlinPath).existsSync()) { return 'kotlin'; } else { - throw CantFindMainActivityPath( + throw _CantFindMainActivityPath( "Not able to determinate MainActivity path. Maybe the problem is your package path OR your AndroidManifest.xml 'package' attribute on manifest."); } } /// Get MainActivity.java path based on package name on AndroidManifest.xml Future _getMainActivityJavaPath() async { - var androidManifest = File(androidManifestFile); + var androidManifest = File(_androidManifestFile); final lines = await androidManifest.readAsLines(); var foundPath = false; @@ -416,7 +408,7 @@ Future _getMainActivityJavaPath() async { /// Get MainActivity.kt path based on package name on AndroidManifest.xml Future _getMainActivityKotlinPath() async { - var androidManifest = File(androidManifestFile); + var androidManifest = File(_androidManifestFile); final lines = await androidManifest.readAsLines(); var foundPath = false; @@ -491,16 +483,16 @@ Future _addMainActivitySplashLines(String language, File mainActivityFile, // Before 'public class ...' add the following lines if (line.contains(javaReferenceLines[0])) { // If import not added already - if (!lines.contains(templates.androidMainActivityJavaImportLines1)) { - newLines.add(templates.androidMainActivityJavaImportLines1); + if (!lines.contains(_androidMainActivityJavaImportLines1)) { + newLines.add(_androidMainActivityJavaImportLines1); } - if (!lines.contains(templates.androidMainActivityJavaImportLines2)) { - newLines.add(templates.androidMainActivityJavaImportLines2); + if (!lines.contains(_androidMainActivityJavaImportLines2)) { + newLines.add(_androidMainActivityJavaImportLines2); } - if (!lines.contains(templates.androidMainActivityJavaImportLines3)) { - newLines.add(templates.androidMainActivityJavaImportLines3); + if (!lines.contains(_androidMainActivityJavaImportLines3)) { + newLines.add(_androidMainActivityJavaImportLines3); } } @@ -508,13 +500,13 @@ Future _addMainActivitySplashLines(String language, File mainActivityFile, // After 'super.onCreate ...' add the following lines if (line.contains(javaReferenceLines[1])) { - newLines.add(templates.androidMainActivityJavaLines2WithStatusBar - .replaceFirst('{{{primaryColorDark}}}', '0xff$primaryColorDark')); + newLines.add(_androidMainActivityJavaLines2WithStatusBar.replaceFirst( + '{{{primaryColorDark}}}', '0xff$primaryColorDark')); } // After 'GeneratedPluginRegistrant ...' add the following lines if (line.contains(javaReferenceLines[2])) { - newLines.add(templates.androidMainActivityJavaLines3); + newLines.add(_androidMainActivityJavaLines3); } } @@ -522,16 +514,16 @@ Future _addMainActivitySplashLines(String language, File mainActivityFile, // Before 'class MainActivity ...' add the following lines if (line.contains(kotlinReferenceLines[0])) { // If import not added already - if (!lines.contains(templates.androidMainActivityKotlinImportLines1)) { - newLines.add(templates.androidMainActivityKotlinImportLines1); + if (!lines.contains(_androidMainActivityKotlinImportLines1)) { + newLines.add(_androidMainActivityKotlinImportLines1); } - if (!lines.contains(templates.androidMainActivityKotlinImportLines2)) { - newLines.add(templates.androidMainActivityKotlinImportLines2); + if (!lines.contains(_androidMainActivityKotlinImportLines2)) { + newLines.add(_androidMainActivityKotlinImportLines2); } - if (!lines.contains(templates.androidMainActivityKotlinImportLines3)) { - newLines.add(templates.androidMainActivityKotlinImportLines3); + if (!lines.contains(_androidMainActivityKotlinImportLines3)) { + newLines.add(_androidMainActivityKotlinImportLines3); } } @@ -539,13 +531,13 @@ Future _addMainActivitySplashLines(String language, File mainActivityFile, // After 'super.onCreate ...' add the following lines if (line.contains(kotlinReferenceLines[1])) { - newLines.add(templates.androidMainActivityKotlinLines2WithStatusBar - .replaceFirst('{{{primaryColorDark}}}', '0xff$primaryColorDark')); + newLines.add(_androidMainActivityKotlinLines2WithStatusBar.replaceFirst( + '{{{primaryColorDark}}}', '0xff$primaryColorDark')); } // After 'GeneratedPluginRegistrant ...' add the following lines if (line.contains(kotlinReferenceLines[2])) { - newLines.add(templates.androidMainActivityKotlinLines3); + newLines.add(_androidMainActivityKotlinLines3); } } } diff --git a/lib/constants.dart b/lib/constants.dart index abe001e..73b18e6 100644 --- a/lib/constants.dart +++ b/lib/constants.dart @@ -1,24 +1,26 @@ +part of flutter_native_splash_supported_platform; + // Android-related constants -const String androidColorsFile = 'android/app/src/main/res/values/colors.xml'; -const String androidColorsDarkFile = +const String _androidColorsFile = 'android/app/src/main/res/values/colors.xml'; +const String _androidColorsDarkFile = 'android/app/src/main/res/values-night/colors.xml'; -const String androidManifestFile = 'android/app/src/main/AndroidManifest.xml'; -const String androidLaunchBackgroundFile = +const String _androidManifestFile = 'android/app/src/main/AndroidManifest.xml'; +const String _androidLaunchBackgroundFile = 'android/app/src/main/res/drawable/launch_background.xml'; -const String androidLaunchDarkBackgroundFile = +const String _androidLaunchDarkBackgroundFile = 'android/app/src/main/res/drawable-night/launch_background.xml'; -const String androidStylesFile = 'android/app/src/main/res/values/styles.xml'; -const String androidStylesDarkFile = +const String _androidStylesFile = 'android/app/src/main/res/values/styles.xml'; +const String _androidStylesDarkFile = 'android/app/src/main/res/values-night/styles.xml'; -const String androidResFolder = 'android/app/src/main/res/'; +const String _androidResFolder = 'android/app/src/main/res/'; // iOS-related constants -const String iOSAssetsLaunchImageFolder = +const String _iOSAssetsLaunchImageFolder = 'ios/Runner/Assets.xcassets/LaunchImage.imageset/'; -const String iOSLaunchScreenStoryboardFile = +const String _iOSLaunchScreenStoryboardFile = 'ios/Runner/Base.lproj/LaunchScreen.storyboard'; -const String iOSInfoPlistFile = 'ios/Runner/Info.plist'; -const String iOSAppDelegateObjCFile = 'ios/Runner/AppDelegate.m'; -const String iOSAppDelegateSwiftFile = 'ios/Runner/AppDelegate.swift'; -const String iOSAssetsLaunchImageBackgroundFolder = +const String _iOSInfoPlistFile = 'ios/Runner/Info.plist'; +const String _iOSAppDelegateObjCFile = 'ios/Runner/AppDelegate.m'; +const String _iOSAppDelegateSwiftFile = 'ios/Runner/AppDelegate.swift'; +const String _iOSAssetsLaunchImageBackgroundFolder = 'ios/Runner/Assets.xcassets/LaunchBackground.imageset/'; diff --git a/lib/exceptions.dart b/lib/exceptions.dart index f49f3e2..2aeb3a7 100644 --- a/lib/exceptions.dart +++ b/lib/exceptions.dart @@ -1,5 +1,7 @@ -class NoConfigFoundException implements Exception { - const NoConfigFoundException([this.message]); +part of flutter_native_splash_supported_platform; + +class _NoConfigFoundException implements Exception { + const _NoConfigFoundException([this.message]); final String message; @override @@ -10,8 +12,8 @@ class NoConfigFoundException implements Exception { } } -class InvalidConfigException implements Exception { - const InvalidConfigException([this.message]); +class _InvalidConfigException implements Exception { + const _InvalidConfigException([this.message]); final String message; @override @@ -22,8 +24,8 @@ class InvalidConfigException implements Exception { } } -class NoImageFileFoundException implements Exception { - const NoImageFileFoundException([this.message]); +class _NoImageFileFoundException implements Exception { + const _NoImageFileFoundException([this.message]); final String message; @override @@ -34,8 +36,8 @@ class NoImageFileFoundException implements Exception { } } -class CantFindMainActivityPath implements Exception { - const CantFindMainActivityPath([this.message]); +class _CantFindMainActivityPath implements Exception { + const _CantFindMainActivityPath([this.message]); final String message; @override @@ -46,8 +48,8 @@ class CantFindMainActivityPath implements Exception { } } -class CantFindAppDelegatePath implements Exception { - const CantFindAppDelegatePath([this.message]); +class _CantFindAppDelegatePath implements Exception { + const _CantFindAppDelegatePath([this.message]); final String message; @override @@ -58,8 +60,8 @@ class CantFindAppDelegatePath implements Exception { } } -class InvalidNativeFile implements Exception { - const InvalidNativeFile([this.message]); +class _InvalidNativeFile implements Exception { + const _InvalidNativeFile([this.message]); final String message; @override @@ -70,8 +72,8 @@ class InvalidNativeFile implements Exception { } } -class LaunchScreenStoryboardModified implements Exception { - const LaunchScreenStoryboardModified([this.message]); +class _LaunchScreenStoryboardModified implements Exception { + const _LaunchScreenStoryboardModified([this.message]); final String message; @override diff --git a/lib/flutter_native_splash.dart b/lib/flutter_native_splash.dart index ba11f99..67589a2 100644 --- a/lib/flutter_native_splash.dart +++ b/lib/flutter_native_splash.dart @@ -1,3 +1,6 @@ +/// ## Flutter Native Splash +/// +/// This is the main entry point for the Flutter Native Splash package. library flutter_native_splash; /* @@ -9,11 +12,12 @@ library flutter_native_splash; import 'unsupported_platform.dart' // Stub implementation if (dart.library.io) 'supported_platform.dart'; // dart:io implementation -/// Create splash screen for Android and iOS +/// Create splash screens for Android and iOS Future createSplash() async { await tryCreateSplash(); } +/// Create splash screens for Android and iOS based on a config argument Future createSplashByConfig(Map config) async { tryCreateSplashByConfig(config); } diff --git a/lib/ios.dart b/lib/ios.dart index 399d9fe..80665ee 100644 --- a/lib/ios.dart +++ b/lib/ios.dart @@ -1,40 +1,37 @@ -import 'dart:io'; - -import 'package:flutter_native_splash/constants.dart'; -import 'package:flutter_native_splash/exceptions.dart'; -import 'package:flutter_native_splash/templates.dart' as templates; -import 'package:image/image.dart' as img; +part of flutter_native_splash_supported_platform; // Image template -class IosLaunchImageTemplate { +class _IosLaunchImageTemplate { final String fileName; final double divider; - IosLaunchImageTemplate({this.fileName, this.divider}); + _IosLaunchImageTemplate({this.fileName, this.divider}); } -final List splashImages = [ - IosLaunchImageTemplate(fileName: 'LaunchImage.png', divider: 3), - IosLaunchImageTemplate(fileName: 'LaunchImage@2x.png', divider: 2), - IosLaunchImageTemplate( +final List<_IosLaunchImageTemplate> _iOSSplashImages = + <_IosLaunchImageTemplate>[ + _IosLaunchImageTemplate(fileName: 'LaunchImage.png', divider: 3), + _IosLaunchImageTemplate(fileName: 'LaunchImage@2x.png', divider: 2), + _IosLaunchImageTemplate( fileName: 'LaunchImage@3x.png', divider: 1), // original image must be @3x ]; -final List splashImagesDark = [ - IosLaunchImageTemplate(fileName: 'LaunchImageDark.png', divider: 3), - IosLaunchImageTemplate(fileName: 'LaunchImageDark@2x.png', divider: 2), - IosLaunchImageTemplate(fileName: 'LaunchImageDark@3x.png', divider: 1), +final List<_IosLaunchImageTemplate> _iOSSplashImagesDark = + <_IosLaunchImageTemplate>[ + _IosLaunchImageTemplate(fileName: 'LaunchImageDark.png', divider: 3), + _IosLaunchImageTemplate(fileName: 'LaunchImageDark@2x.png', divider: 2), + _IosLaunchImageTemplate(fileName: 'LaunchImageDark@3x.png', divider: 1), // original image must be @3x ]; /// Create iOS splash screen -void createSplash(String imagePath, String darkImagePath, String color, +void _createiOSSplash(String imagePath, String darkImagePath, String color, String darkColor) async { if (imagePath.isNotEmpty) { - await _applyImage(imagePath); + await _applyImageiOS(imagePath); } if (darkImagePath.isNotEmpty) { - await _applyImage(darkImagePath, dark: true); + await _applyImageiOS(darkImagePath, dark: true); } await _applyLaunchScreenStoryboard(imagePath, color); @@ -44,41 +41,40 @@ void createSplash(String imagePath, String darkImagePath, String color, } /// Create splash screen images for original size, @2x and @3x -void _applyImage(String imagePath, {bool dark = false}) { +void _applyImageiOS(String imagePath, {bool dark = false}) { print('[iOS] Creating ' + (dark ? 'dark mode ' : '') + 'splash images'); final file = File(imagePath); if (!file.existsSync()) { - throw NoImageFileFoundException('The file $imagePath was not found.'); + throw _NoImageFileFoundException('The file $imagePath was not found.'); } - final image = img.decodeImage(File(imagePath).readAsBytesSync()); + final image = decodeImage(File(imagePath).readAsBytesSync()); - for (var template in dark ? splashImagesDark : splashImages) { - _saveImage(template, image); + for (var template in dark ? _iOSSplashImagesDark : _iOSSplashImages) { + _saveImageiOS(template, image); } - File(iOSAssetsLaunchImageFolder + 'Contents.json') + File(_iOSAssetsLaunchImageFolder + 'Contents.json') .create(recursive: true) .then((File file) { - file.writeAsStringSync( - dark ? templates.iOSContentsJsonDark : templates.iOSContentsJson); + file.writeAsStringSync(dark ? _iOSContentsJsonDark : _iOSContentsJson); }); } /// Saves splash screen image to the project -void _saveImage(IosLaunchImageTemplate template, img.Image image) { - var newFile = img.copyResize( +void _saveImageiOS(_IosLaunchImageTemplate template, Image image) { + var newFile = copyResize( image, width: image.width ~/ template.divider, height: image.height ~/ template.divider, - interpolation: img.Interpolation.linear, + interpolation: Interpolation.linear, ); - File(iOSAssetsLaunchImageFolder + template.fileName) + File(_iOSAssetsLaunchImageFolder + template.fileName) .create(recursive: true) .then((File file) { - file.writeAsBytesSync(img.encodePng(newFile)); + file.writeAsBytesSync(encodePng(newFile)); }); } @@ -88,7 +84,7 @@ Future _applyLaunchScreenStoryboard(String imagePath, String color) { color = '#' + color; } - final file = File(iOSLaunchScreenStoryboardFile); + final file = File(_iOSLaunchScreenStoryboardFile); if (file.existsSync()) { print( @@ -104,7 +100,7 @@ Future _applyLaunchScreenStoryboard(String imagePath, String color) { /// Updates LaunchScreen.storyboard adding splash image path Future _updateLaunchScreenStoryboard(String imagePath, String color) async { - final file = File(iOSLaunchScreenStoryboardFile); + final file = File(_iOSLaunchScreenStoryboardFile); final lines = await file.readAsLines(); var foundExistingBackgroundImage = false; @@ -151,28 +147,27 @@ Future _updateLaunchScreenStoryboard(String imagePath, String color) async { if (foundExistingImage) { if (!foundExistingLaunchBackgroundSubview) { if (subviewCount != 1) { - throw LaunchScreenStoryboardModified( + throw _LaunchScreenStoryboardModified( 'Multiple subviews found. Did you modify your default LaunchScreen.storyboard file?'); } if (constraintCount != 1) { - throw LaunchScreenStoryboardModified( + throw _LaunchScreenStoryboardModified( 'Multiple constraint blocks found. Did you modify your default LaunchScreen.storyboard file?'); } lines[subviewTagLine] = - lines[subviewTagLine] + '\n' + templates.iOSLaunchBackgroundSubview; + lines[subviewTagLine] + '\n' + _iOSLaunchBackgroundSubview; lines[constraintClosingTagLine] = - templates.iOSLaunchBackgroundConstraints + - lines[constraintClosingTagLine]; + _iOSLaunchBackgroundConstraints + lines[constraintClosingTagLine]; } if (imagePath.isNotEmpty) { final file = File(imagePath); if (!file.existsSync()) { - throw NoImageFileFoundException('The file $imagePath was not found.'); + throw _NoImageFileFoundException('The file $imagePath was not found.'); } - final image = img.decodeImage(File(imagePath).readAsBytesSync()); + final image = decodeImage(File(imagePath).readAsBytesSync()); var width = image.width; var height = image.height; @@ -186,7 +181,7 @@ Future _updateLaunchScreenStoryboard(String imagePath, String color) async { lines[imageLine]; } } else { - throw LaunchScreenStoryboardModified( + 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?"); } @@ -195,24 +190,24 @@ Future _updateLaunchScreenStoryboard(String imagePath, String color) async { /// Creates LaunchScreen.storyboard with splash image path Future _createLaunchScreenStoryboard(String imagePath, String color) async { - var file = await File(iOSLaunchScreenStoryboardFile).create(recursive: true); - await file.writeAsString(templates.iOSLaunchScreenStoryboardContent); + var file = await File(_iOSLaunchScreenStoryboardFile).create(recursive: true); + await file.writeAsString(_iOSLaunchScreenStoryboardContent); return _updateLaunchScreenStoryboard(imagePath, color); } Future _createBackgroundColor( String colorString, String darkColorString, bool dark) async { - var background = img.Image(1, 1); + var background = Image(1, 1); colorString = colorString.replaceFirst('#', ''); var redChannel = int.parse(colorString.substring(0, 2), radix: 16); var greenChannel = int.parse(colorString.substring(2, 4), radix: 16); var blueChannel = int.parse(colorString.substring(4, 6), radix: 16); background.fill( 0xFF000000 + (blueChannel << 16) + (greenChannel << 8) + redChannel); - await File(iOSAssetsLaunchImageBackgroundFolder + 'background.png') + await File(_iOSAssetsLaunchImageBackgroundFolder + 'background.png') .create(recursive: true) - .then((File file) => file.writeAsBytesSync(img.encodePng(background))); + .then((File file) => file.writeAsBytesSync(encodePng(background))); if (darkColorString.isNotEmpty) { darkColorString = darkColorString.replaceFirst('#', ''); @@ -221,23 +216,22 @@ Future _createBackgroundColor( blueChannel = int.parse(darkColorString.substring(4, 6), radix: 16); background.fill( 0xFF000000 + (blueChannel << 16) + (greenChannel << 8) + redChannel); - await File(iOSAssetsLaunchImageBackgroundFolder + 'darkbackground.png') + await File(_iOSAssetsLaunchImageBackgroundFolder + 'darkbackground.png') .create(recursive: true) - .then((File file) => file.writeAsBytesSync(img.encodePng(background))); + .then((File file) => file.writeAsBytesSync(encodePng(background))); } - return File(iOSAssetsLaunchImageBackgroundFolder + 'Contents.json') + return File(_iOSAssetsLaunchImageBackgroundFolder + 'Contents.json') .create(recursive: true) .then((File file) { - file.writeAsStringSync(dark - ? templates.iOSLaunchBackgroundDarkJson - : templates.iOSLaunchBackgroundJson); + file.writeAsStringSync( + dark ? _iOSLaunchBackgroundDarkJson : _iOSLaunchBackgroundJson); }); } /// Update Info.plist for status bar behaviour (hidden/visible) Future _applyInfoPList() async { - final infoPlistFile = File(iOSInfoPlistFile); + final infoPlistFile = File(_iOSInfoPlistFile); final lines = await infoPlistFile.readAsLines(); if (_needToUpdateInfoPlist(lines)) { @@ -281,7 +275,7 @@ Future _updateInfoPlistFile(File infoPlistFile, List lines) async { } // Before last '' add the lines - newLines.insert(lastDictLine, templates.iOSInfoPlistLines); + newLines.insert(lastDictLine, _iOSInfoPlistLines); await infoPlistFile.writeAsString(newLines.join('\n')); } @@ -292,9 +286,9 @@ Future _applyAppDelegate() async { String appDelegatePath; if (language == 'objective-c') { - appDelegatePath = iOSAppDelegateObjCFile; + appDelegatePath = _iOSAppDelegateObjCFile; } else if (language == 'swift') { - appDelegatePath = iOSAppDelegateSwiftFile; + appDelegatePath = _iOSAppDelegateSwiftFile; } final appDelegateFile = File(appDelegatePath); @@ -307,12 +301,12 @@ Future _applyAppDelegate() async { } Future _objectiveCOrSwift() async { - if (File(iOSAppDelegateObjCFile).existsSync()) { + if (File(_iOSAppDelegateObjCFile).existsSync()) { return 'objective-c'; - } else if (File(iOSAppDelegateSwiftFile).existsSync()) { + } else if (File(_iOSAppDelegateSwiftFile).existsSync()) { return 'swift'; } else { - throw CantFindAppDelegatePath('Not able to determinate AppDelegate path.'); + throw _CantFindAppDelegatePath('Not able to determinate AppDelegate path.'); } } @@ -352,7 +346,7 @@ Future _updateAppDelegate( if (language == 'objective-c') { // Before '[GeneratedPlugin ...' add the following lines if (line.contains(objectiveCReferenceLine)) { - newLines.add(templates.iOSAppDelegateObjectiveCLines); + newLines.add(_iOSAppDelegateObjectiveCLines); } newLines.add(line); @@ -361,7 +355,7 @@ Future _updateAppDelegate( if (language == 'swift') { // Before 'GeneratedPlugin ...' add the following lines if (line.contains(swiftReferenceLine)) { - newLines.add(templates.iOSAppDelegateSwiftLines); + newLines.add(_iOSAppDelegateSwiftLines); } newLines.add(line); diff --git a/lib/supported_platform.dart b/lib/supported_platform.dart index ad53257..34601af 100644 --- a/lib/supported_platform.dart +++ b/lib/supported_platform.dart @@ -1,15 +1,32 @@ +/// ## If the current platform is supported, load dart.io. +/// +/// Creating images necessary for the splash screens requires the io.dart package, which +/// unfortunately does not have support for JS. Because pub.dev docks pub points for +/// packages not being cross-platform, it is necessary to use +/// [conditional imports](https://dart.dev/guides/libraries/create-library-packages#conditionally-importing-and-exporting-library-files) +/// to avoid losing pub points. This library is included when the package is loaded on +/// a supported platform, loads dart.io and the rest of the package. +library flutter_native_splash_supported_platform; + import 'dart:io'; -import 'package:flutter_native_splash/android.dart' as android; -import 'package:flutter_native_splash/exceptions.dart'; -import 'package:flutter_native_splash/ios.dart' as ios; +import 'package:color/color.dart'; +import 'package:image/image.dart'; import 'package:yaml/yaml.dart'; +part 'android.dart'; +part 'constants.dart'; +part 'exceptions.dart'; +part 'ios.dart'; +part 'templates.dart'; + +/// Function that will be called on supported platforms to create the splash screens. Future tryCreateSplash() async { var config = await _getConfig(); await tryCreateSplashByConfig(config); } +/// Function that will be called on supported platforms to create the splash screen based on a config argument. Future tryCreateSplashByConfig(Map config) async { String image = config['image'] ?? ''; String darkImage = config['image_dark'] ?? ''; @@ -19,12 +36,12 @@ Future tryCreateSplashByConfig(Map config) async { bool androidDisableFullscreen = config['android_disable_fullscreen'] ?? false; if (!config.containsKey('android') || config['android']) { - await android.createSplash( + await _createAndroidSplash( image, darkImage, color, darkColor, fill, androidDisableFullscreen); } if (!config.containsKey('ios') || config['ios']) { - await ios.createSplash(image, darkImage, color, darkColor); + await _createiOSSplash(image, darkImage, color, darkColor); } } @@ -41,7 +58,7 @@ Map _getConfig() { final Map yamlMap = loadYaml(yamlString); if (yamlMap == null || !(yamlMap['flutter_native_splash'] is Map)) { - stderr.writeln(NoConfigFoundException( + stderr.writeln(_NoConfigFoundException( 'Your `$filePath` file does not contain a `flutter_native_splash` section.')); exit(1); } @@ -54,13 +71,13 @@ Map _getConfig() { } if (!config.containsKey('color')) { - stderr.writeln(InvalidConfigException( + stderr.writeln(_InvalidConfigException( 'Your `flutter_native_splash` section does not contain a `color`.')); exit(1); } if (config.containsKey('image_dark') && !config.containsKey('color_dark')) { - stderr.writeln(InvalidConfigException( + stderr.writeln(_InvalidConfigException( 'Your `flutter_native_splash` section contains `image_dark` but does not contain a `color_dark`.')); exit(1); } diff --git a/lib/templates.dart b/lib/templates.dart index 0e1fd26..674b321 100644 --- a/lib/templates.dart +++ b/lib/templates.dart @@ -1,62 +1,64 @@ +part of flutter_native_splash_supported_platform; + // Android-related templates -const String androidColorsXml = ''' +const String _androidColorsXml = ''' #2196F3 '''; -const String androidLaunchBackgroundItemXml = ''' +const String _androidLaunchBackgroundItemXml = ''' '''; -const String androidLaunchBackgroundXml = ''' +const String _androidLaunchBackgroundXml = ''' - $androidLaunchBackgroundItemXml + $_androidLaunchBackgroundItemXml '''; -const String androidLaunchBackgroundItemXmlFill = ''' +const String _androidLaunchBackgroundItemXmlFill = ''' '''; -const String androidLaunchBackgroundXmlFill = ''' +const String _androidLaunchBackgroundXmlFill = ''' - $androidLaunchBackgroundItemXmlFill + $_androidLaunchBackgroundItemXmlFill '''; -const String androidStylesItemXml = ''' +const String _androidStylesItemXml = ''' true '''; -const String androidStylesXml = ''' +const String _androidStylesXml = ''' '''; -const String androidMainActivityJavaImportLines1 = 'import android.os.Build;'; -const String androidMainActivityJavaImportLines2 = +const String _androidMainActivityJavaImportLines1 = 'import android.os.Build;'; +const String _androidMainActivityJavaImportLines2 = 'import android.view.ViewTreeObserver;'; -const String androidMainActivityJavaImportLines3 = +const String _androidMainActivityJavaImportLines3 = 'import android.view.WindowManager;'; -const String androidMainActivityJavaLines2WithStatusBar = ''' +const String _androidMainActivityJavaLines2WithStatusBar = ''' boolean flutter_native_splash = true; int originalStatusBarColor = 0; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { @@ -66,7 +68,7 @@ const String androidMainActivityJavaLines2WithStatusBar = ''' int originalStatusBarColorFinal = originalStatusBarColor; '''; -const String androidMainActivityJavaLines3 = ''' +const String _androidMainActivityJavaLines3 = ''' ViewTreeObserver vto = getFlutterView().getViewTreeObserver(); vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override @@ -80,13 +82,13 @@ const String androidMainActivityJavaLines3 = ''' }); '''; -const String androidMainActivityKotlinImportLines1 = 'import android.os.Build'; -const String androidMainActivityKotlinImportLines2 = +const String _androidMainActivityKotlinImportLines1 = 'import android.os.Build'; +const String _androidMainActivityKotlinImportLines2 = 'import android.view.ViewTreeObserver'; -const String androidMainActivityKotlinImportLines3 = +const String _androidMainActivityKotlinImportLines3 = 'import android.view.WindowManager'; -const String androidMainActivityKotlinLines2WithStatusBar = ''' +const String _androidMainActivityKotlinLines2WithStatusBar = ''' val flutter_native_splash = true var originalStatusBarColor = 0 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { @@ -96,7 +98,7 @@ const String androidMainActivityKotlinLines2WithStatusBar = ''' val originalStatusBarColorFinal = originalStatusBarColor '''; -const String androidMainActivityKotlinLines3 = ''' +const String _androidMainActivityKotlinLines3 = ''' val vto = flutterView.viewTreeObserver vto.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { override fun onGlobalLayout() { @@ -110,7 +112,7 @@ const String androidMainActivityKotlinLines3 = ''' '''; // iOS-related templates -const String iOSLaunchScreenStoryboardContent = ''' +const String _iOSLaunchScreenStoryboardContent = ''' @@ -150,22 +152,22 @@ const String iOSLaunchScreenStoryboardContent = ''' '''; -String iOSInfoPlistLines = ''' +String _iOSInfoPlistLines = ''' UIStatusBarHidden '''; -String iOSAppDelegateObjectiveCLines = ''' +String _iOSAppDelegateObjectiveCLines = ''' int flutter_native_splash = 1; UIApplication.sharedApplication.statusBarHidden = false; '''; -String iOSAppDelegateSwiftLines = ''' +String _iOSAppDelegateSwiftLines = ''' var flutter_native_splash = 1 UIApplication.shared.isStatusBarHidden = false '''; -const String iOSContentsJson = ''' +const String _iOSContentsJson = ''' { "images" : [ { @@ -191,7 +193,7 @@ const String iOSContentsJson = ''' } '''; -const String iOSContentsJsonDark = ''' +const String _iOSContentsJsonDark = ''' { "images" : [ { @@ -250,7 +252,7 @@ const String iOSContentsJsonDark = ''' } '''; -const String iOSLaunchBackgroundJson = ''' +const String _iOSLaunchBackgroundJson = ''' { "images" : [ { @@ -274,7 +276,7 @@ const String iOSLaunchBackgroundJson = ''' } '''; -const String iOSLaunchBackgroundDarkJson = ''' +const String _iOSLaunchBackgroundDarkJson = ''' { "images" : [ { @@ -329,12 +331,12 @@ const String iOSLaunchBackgroundDarkJson = ''' } '''; -const String iOSLaunchBackgroundSubview = ''' +const String _iOSLaunchBackgroundSubview = ''' '''; -const String iOSLaunchBackgroundConstraints = ''' +const String _iOSLaunchBackgroundConstraints = ''' diff --git a/lib/unsupported_platform.dart b/lib/unsupported_platform.dart index ed9e382..9f8fe66 100644 --- a/lib/unsupported_platform.dart +++ b/lib/unsupported_platform.dart @@ -1,10 +1,20 @@ -// If the current platform is unsupported, throw an error. +/// ## If the current platform is unsupported, throw an error. +/// +/// Creating images necessary for the splash screens requires the io.dart package, which +/// unfortunately does not have support for JS. Because pub.dev docks pub points for +/// packages not being cross-platform, it is necessary to use +/// [conditional imports](https://dart.dev/guides/libraries/create-library-packages#conditionally-importing-and-exporting-library-files) +/// to avoid losing pub points. This library is included when the package is loaded on +/// an unsupported platform, and its only purpose is to trigger an exception. +library flutter_native_splash_unsupported_platform; +/// Function that will be called on unsupported platforms, triggering exception. void tryCreateSplashByConfig(Map config) async { throw UnsupportedError( 'This package requires dart:io, which is unsupported by this platform.'); } +/// Function that will be called on unsupported platforms, triggering exception. void tryCreateSplash() async { throw UnsupportedError( 'This package requires dart:io, which is unsupported by this platform.'); diff --git a/pubspec.yaml b/pubspec.yaml index cb9b617..77faaf4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_native_splash description: Automatically generates native code for adding splash screens in Android and iOS. Customize with specific platform, background color and splash image. -version: 0.2.2 +version: 0.2.3 homepage: https://github.com/henriquearthur/flutter_native_splash environment: