diff --git a/lerna.json b/lerna.json index e7925c906..34c132351 100644 --- a/lerna.json +++ b/lerna.json @@ -16,6 +16,7 @@ "network", "screen-reader", "share", + "splash-screen", "status-bar", "storage", "text-zoom", diff --git a/splash-screen/.eslintignore b/splash-screen/.eslintignore new file mode 100644 index 000000000..9d0b71a3c --- /dev/null +++ b/splash-screen/.eslintignore @@ -0,0 +1,2 @@ +build +dist diff --git a/splash-screen/.gitignore b/splash-screen/.gitignore new file mode 100644 index 000000000..70ccbf713 --- /dev/null +++ b/splash-screen/.gitignore @@ -0,0 +1,61 @@ +# node files +dist +node_modules + +# iOS files +Pods +Podfile.lock +Build +xcuserdata + +# macOS files +.DS_Store + + + +# Based on Android gitignore template: https://github.com/github/gitignore/blob/HEAD/Android.gitignore + +# Built application files +*.apk +*.ap_ + +# Files for the ART/Dalvik VM +*.dex + +# Java class files +*.class + +# Generated files +bin +gen +out + +# Gradle files +.gradle +build + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard + +# Log Files +*.log + +# Android Studio Navigation editor temp files +.navigation + +# Android Studio captures folder +captures + +# IntelliJ +*.iml +.idea + +# Keystore files +# Uncomment the following line if you do not want to check your keystore files in. +#*.jks + +# External native build folder generated in Android Studio 2.2 and later +.externalNativeBuild diff --git a/splash-screen/.prettierignore b/splash-screen/.prettierignore new file mode 100644 index 000000000..9d0b71a3c --- /dev/null +++ b/splash-screen/.prettierignore @@ -0,0 +1,2 @@ +build +dist diff --git a/splash-screen/CapacitorSplashScreen.podspec b/splash-screen/CapacitorSplashScreen.podspec new file mode 100644 index 000000000..97d7fba54 --- /dev/null +++ b/splash-screen/CapacitorSplashScreen.podspec @@ -0,0 +1,17 @@ +require 'json' + +package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) + +Pod::Spec.new do |s| + s.name = 'CapacitorSplashScreen' + s.version = package['version'] + s.summary = package['description'] + s.license = package['license'] + s.homepage = package['repository']['url'] + s.author = package['author'] + s.source = { :git => package['repository']['url'], :tag => s.version.to_s } + s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' + s.ios.deployment_target = '11.0' + s.dependency 'Capacitor' + s.swift_version = '5.1' +end diff --git a/splash-screen/LICENSE b/splash-screen/LICENSE new file mode 100644 index 000000000..6652495cb --- /dev/null +++ b/splash-screen/LICENSE @@ -0,0 +1,23 @@ +Copyright 2020-present Ionic +https://ionic.io + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/splash-screen/README.md b/splash-screen/README.md new file mode 100644 index 000000000..a564bd3a1 --- /dev/null +++ b/splash-screen/README.md @@ -0,0 +1,78 @@ +# @capacitor/splash-screen + +The Splash Screen API provides methods for showing or hiding a Splash image. + +## Install + +```bash +npm install @capacitor/splash-screen +npx cap sync +``` + +## API + + + +* [`show(...)`](#show) +* [`hide(...)`](#hide) +* [Interfaces](#interfaces) + + + + + + +### show(...) + +```typescript +show(options?: SplashScreenShowOptions | undefined) => Promise +``` + +Show the splash screen + +| Param | Type | +| ------------- | --------------------------------------------------------------------------- | +| **`options`** | SplashScreenShowOptions | + +**Since:** 1.0.0 + +-------------------- + + +### hide(...) + +```typescript +hide(options?: SplashScreenHideOptions | undefined) => Promise +``` + +Hide the splash screen + +| Param | Type | +| ------------- | --------------------------------------------------------------------------- | +| **`options`** | SplashScreenHideOptions | + +**Since:** 1.0.0 + +-------------------- + + +### Interfaces + + +#### SplashScreenShowOptions + +| Prop | Type | Description | Default | Since | +| --------------------- | -------------------- | ------------------------------------------------------------------- | ----------------- | ----- | +| **`autoHide`** | boolean | Whether to auto hide the splash after showDuration | | 1.0.0 | +| **`fadeInDuration`** | number | How long (in ms) to fade in. | 200 | 1.0.0 | +| **`fadeOutDuration`** | number | How long (in ms) to fade out. | 200 | 1.0.0 | +| **`showDuration`** | number | How long to show the splash screen when autoHide is enabled (in ms) | 3000 | 1.0.0 | + + +#### SplashScreenHideOptions + +| Prop | Type | Description | Default | Since | +| --------------------- | ------------------- | ----------------------------- | ---------------- | ----- | +| **`fadeOutDuration`** | number | How long (in ms) to fade out. | 200 | 1.0.0 | + + diff --git a/splash-screen/android/.gitignore b/splash-screen/android/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/splash-screen/android/.gitignore @@ -0,0 +1 @@ +/build diff --git a/splash-screen/android/build.gradle b/splash-screen/android/build.gradle new file mode 100644 index 000000000..be79102f6 --- /dev/null +++ b/splash-screen/android/build.gradle @@ -0,0 +1,58 @@ +ext { + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.12' + androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.1.0' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.1' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.2.0' +} + +buildscript { + repositories { + google() + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:4.1.1' + } +} + +apply plugin: 'com.android.library' + +android { + compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 29 + defaultConfig { + minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 21 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 29 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + lintOptions { + abortOnError false + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +repositories { + google() + jcenter() + mavenCentral() +} + + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation project(':capacitor-android') + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" + testImplementation "junit:junit:$junitVersion" + androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" + androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion" +} diff --git a/splash-screen/android/gradle.properties b/splash-screen/android/gradle.properties new file mode 100644 index 000000000..0566c221d --- /dev/null +++ b/splash-screen/android/gradle.properties @@ -0,0 +1,24 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx1536m + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true + +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Automatically convert third-party libraries to use AndroidX +android.enableJetifier=true diff --git a/splash-screen/android/gradle/wrapper/gradle-wrapper.jar b/splash-screen/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..62d4c0535 Binary files /dev/null and b/splash-screen/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/splash-screen/android/gradle/wrapper/gradle-wrapper.properties b/splash-screen/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..186b71557 --- /dev/null +++ b/splash-screen/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/splash-screen/android/gradlew b/splash-screen/android/gradlew new file mode 100755 index 000000000..fbd7c5158 --- /dev/null +++ b/splash-screen/android/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/splash-screen/android/gradlew.bat b/splash-screen/android/gradlew.bat new file mode 100644 index 000000000..5093609d5 --- /dev/null +++ b/splash-screen/android/gradlew.bat @@ -0,0 +1,104 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/splash-screen/android/proguard-rules.pro b/splash-screen/android/proguard-rules.pro new file mode 100644 index 000000000..f1b424510 --- /dev/null +++ b/splash-screen/android/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/splash-screen/android/settings.gradle b/splash-screen/android/settings.gradle new file mode 100644 index 000000000..1e5b8431f --- /dev/null +++ b/splash-screen/android/settings.gradle @@ -0,0 +1,2 @@ +include ':capacitor-android' +project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor') \ No newline at end of file diff --git a/splash-screen/android/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.java b/splash-screen/android/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.java new file mode 100644 index 000000000..58020e16c --- /dev/null +++ b/splash-screen/android/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.getcapacitor.android; + +import static org.junit.Assert.*; + +import android.content.Context; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + + @Test + public void useAppContext() throws Exception { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + + assertEquals("com.getcapacitor.android", appContext.getPackageName()); + } +} diff --git a/splash-screen/android/src/main/AndroidManifest.xml b/splash-screen/android/src/main/AndroidManifest.xml new file mode 100644 index 000000000..18ff164eb --- /dev/null +++ b/splash-screen/android/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + diff --git a/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashListener.java b/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashListener.java new file mode 100644 index 000000000..9271b679c --- /dev/null +++ b/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashListener.java @@ -0,0 +1,6 @@ +package com.capacitorjs.plugins.splashscreen; + +public interface SplashListener { + void completed(); + void error(); +} diff --git a/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashScreen.java b/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashScreen.java new file mode 100644 index 000000000..d6ea42b58 --- /dev/null +++ b/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashScreen.java @@ -0,0 +1,354 @@ +package com.capacitorjs.plugins.splashscreen; + +import android.animation.Animator; +import android.content.Context; +import android.content.res.ColorStateList; +import android.content.res.Resources; +import android.graphics.PixelFormat; +import android.graphics.drawable.Animatable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; +import android.os.Handler; +import android.view.Gravity; +import android.view.View; +import android.view.WindowManager; +import android.view.animation.LinearInterpolator; +import android.widget.ImageView; +import android.widget.ProgressBar; +import androidx.appcompat.app.AppCompatActivity; +import com.getcapacitor.Logger; + +/** + * A Splash Screen service for showing and hiding a splash screen in the app. + */ +public class SplashScreen { + + private ImageView splashImage; + private ProgressBar spinnerBar; + private WindowManager windowManager; + private boolean isVisible = false; + private boolean isHiding = false; + private Context context; + private SplashScreenConfig config; + + SplashScreen(Context context, SplashScreenConfig config) { + this.context = context; + this.config = config; + } + + /** + * Show the splash screen on launch without fading in + * + * @param activity + */ + public void showOnLaunch(final AppCompatActivity activity) { + if (config.getLaunchShowDuration() == 0) { + return; + } + SplashScreenSettings settings = new SplashScreenSettings(); + settings.setShowDuration(config.getLaunchShowDuration()); + settings.setAutoHide(config.isLaunchAutoHide()); + settings.setFadeInDuration(config.getLaunchFadeInDuration()); + + show(activity, settings, null, true); + } + + /** + * Show the Splash Screen + * + * @param activity + * @param settings Settings used to show the Splash Screen + * @param splashListener A listener to handle the finish of the animation (if any) + */ + public void show(final AppCompatActivity activity, final SplashScreenSettings settings, final SplashListener splashListener) { + show(activity, settings, splashListener, false); + } + + /** + * Hide the Splash Screen + * + * @param settings Settings used to hide the Splash Screen + */ + public void hide(SplashScreenSettings settings) { + hide(settings.getFadeOutDuration(), false); + } + + public void onPause() { + tearDown(true); + } + + public void onDestroy() { + tearDown(true); + } + + private void buildViews() { + if (splashImage == null) { + int splashId = context.getResources().getIdentifier(config.getResourceName(), "drawable", context.getPackageName()); + + Drawable splash; + try { + splash = context.getResources().getDrawable(splashId, context.getTheme()); + } catch (Resources.NotFoundException ex) { + Logger.warn("No splash screen found, not displaying"); + return; + } + + if (splash instanceof Animatable) { + ((Animatable) splash).start(); + } + + if (splash instanceof LayerDrawable) { + LayerDrawable layeredSplash = (LayerDrawable) splash; + + for (int i = 0; i < layeredSplash.getNumberOfLayers(); i++) { + Drawable layerDrawable = layeredSplash.getDrawable(i); + + if (layerDrawable instanceof Animatable) { + ((Animatable) layerDrawable).start(); + } + } + } + + splashImage = new ImageView(context); + + splashImage.setFitsSystemWindows(true); + + if (config.isImmersive()) { + final int flags = + View.SYSTEM_UI_FLAG_LAYOUT_STABLE | + View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | + View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_FULLSCREEN | + View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; + splashImage.setSystemUiVisibility(flags); + } else if (config.isFullScreen()) { + splashImage.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN); + } + + // Stops flickers dead in their tracks + // https://stackoverflow.com/a/21847579/32140 + splashImage.setDrawingCacheEnabled(true); + + if (config.getBackgroundColor() != null) { + splashImage.setBackgroundColor(config.getBackgroundColor()); + } + + splashImage.setScaleType(config.getScaleType()); + splashImage.setImageDrawable(splash); + } + + if (spinnerBar == null) { + if (config.getSpinnerStyle() != null) { + int spinnerBarStyle = config.getSpinnerStyle(); + spinnerBar = new ProgressBar(context, null, spinnerBarStyle); + } else { + spinnerBar = new ProgressBar(context); + } + spinnerBar.setIndeterminate(true); + + Integer spinnerBarColor = config.getSpinnerColor(); + if (spinnerBarColor != null) { + int[][] states = new int[][] { + new int[] { android.R.attr.state_enabled }, // enabled + new int[] { -android.R.attr.state_enabled }, // disabled + new int[] { -android.R.attr.state_checked }, // unchecked + new int[] { android.R.attr.state_pressed } // pressed + }; + int[] colors = new int[] { spinnerBarColor, spinnerBarColor, spinnerBarColor, spinnerBarColor }; + ColorStateList colorStateList = new ColorStateList(states, colors); + spinnerBar.setIndeterminateTintList(colorStateList); + } + } + } + + private void show( + final AppCompatActivity activity, + final SplashScreenSettings settings, + final SplashListener splashListener, + final boolean isLaunchSplash + ) { + windowManager = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE); + + if (activity.isFinishing()) { + return; + } + + buildViews(); + + if (isVisible) { + splashListener.completed(); + return; + } + + final Animator.AnimatorListener listener = new Animator.AnimatorListener() { + @Override + public void onAnimationEnd(Animator animator) { + isVisible = true; + + if (settings.isAutoHide()) { + new Handler() + .postDelayed( + () -> { + hide(settings.getFadeOutDuration(), isLaunchSplash); + + if (splashListener != null) { + splashListener.completed(); + } + }, + settings.getShowDuration() + ); + } else { + // If no autoHide, call complete + if (splashListener != null) { + splashListener.completed(); + } + } + } + + @Override + public void onAnimationCancel(Animator animator) {} + + @Override + public void onAnimationRepeat(Animator animator) {} + + @Override + public void onAnimationStart(Animator animator) {} + }; + + Handler mainHandler = new Handler(context.getMainLooper()); + + mainHandler.post( + () -> { + WindowManager.LayoutParams params = new WindowManager.LayoutParams(); + params.gravity = Gravity.CENTER; + params.flags = activity.getWindow().getAttributes().flags; + + // Required to enable the view to actually fade + params.format = PixelFormat.TRANSLUCENT; + + try { + windowManager.addView(splashImage, params); + } catch (IllegalStateException | IllegalArgumentException ex) { + Logger.debug("Could not add splash view"); + return; + } + + splashImage.setAlpha(0f); + + splashImage + .animate() + .alpha(1f) + .setInterpolator(new LinearInterpolator()) + .setDuration(settings.getFadeInDuration()) + .setListener(listener) + .start(); + + splashImage.setVisibility(View.VISIBLE); + + if (spinnerBar != null) { + spinnerBar.setVisibility(View.INVISIBLE); + + if (spinnerBar.getParent() != null) { + windowManager.removeView(spinnerBar); + } + + params.height = WindowManager.LayoutParams.WRAP_CONTENT; + params.width = WindowManager.LayoutParams.WRAP_CONTENT; + + windowManager.addView(spinnerBar, params); + + if (config.isShowSpinner()) { + spinnerBar.setAlpha(0f); + + spinnerBar + .animate() + .alpha(1f) + .setInterpolator(new LinearInterpolator()) + .setDuration(settings.getFadeInDuration()) + .start(); + + spinnerBar.setVisibility(View.VISIBLE); + } + } + } + ); + } + + private void hide(final int fadeOutDuration, boolean isLaunchSplash) { + // Warn the user if the splash was hidden automatically, which means they could be experiencing an app + // that feels slower than it actually is. + if (isLaunchSplash && isVisible) { + Logger.debug( + "SplashScreen was automatically hidden after the launch timeout. " + + "You should call `SplashScreen.hide()` as soon as your web app is loaded (or increase the timeout)." + + "Read more at https://capacitorjs.com/docs/apis/splash-screen#hiding-the-splash-screen" + ); + } + + if (isHiding || splashImage == null || splashImage.getParent() == null) { + return; + } + + isHiding = true; + + final Animator.AnimatorListener listener = new Animator.AnimatorListener() { + @Override + public void onAnimationEnd(Animator animator) { + tearDown(false); + } + + @Override + public void onAnimationCancel(Animator animator) { + tearDown(false); + } + + @Override + public void onAnimationStart(Animator animator) {} + + @Override + public void onAnimationRepeat(Animator animator) {} + }; + + Handler mainHandler = new Handler(context.getMainLooper()); + + mainHandler.post( + () -> { + if (spinnerBar != null) { + spinnerBar.setAlpha(1f); + + spinnerBar.animate().alpha(0).setInterpolator(new LinearInterpolator()).setDuration(fadeOutDuration).start(); + } + + splashImage.setAlpha(1f); + + splashImage + .animate() + .alpha(0) + .setInterpolator(new LinearInterpolator()) + .setDuration(fadeOutDuration) + .setListener(listener) + .start(); + } + ); + } + + private void tearDown(boolean removeSpinner) { + if (spinnerBar != null && spinnerBar.getParent() != null) { + spinnerBar.setVisibility(View.INVISIBLE); + + if (removeSpinner) { + windowManager.removeView(spinnerBar); + } + } + + if (splashImage != null && splashImage.getParent() != null) { + splashImage.setVisibility(View.INVISIBLE); + + windowManager.removeView(splashImage); + } + + isHiding = false; + isVisible = false; + } +} diff --git a/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashScreenConfig.java b/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashScreenConfig.java new file mode 100644 index 000000000..9066b8521 --- /dev/null +++ b/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashScreenConfig.java @@ -0,0 +1,102 @@ +package com.capacitorjs.plugins.splashscreen; + +import android.widget.ImageView.ScaleType; + +public class SplashScreenConfig { + + private Integer backgroundColor; + private Integer spinnerStyle; + private Integer spinnerColor; + private boolean showSpinner = false; + private Integer launchShowDuration = 0; + private boolean launchAutoHide = true; + private Integer launchFadeInDuration = 0; + private String resourceName = "splash"; + private boolean immersive = false; + private boolean fullScreen = false; + private ScaleType scaleType = ScaleType.FIT_XY; + + public Integer getBackgroundColor() { + return backgroundColor; + } + + public void setBackgroundColor(Integer backgroundColor) { + this.backgroundColor = backgroundColor; + } + + public Integer getSpinnerStyle() { + return spinnerStyle; + } + + public void setSpinnerStyle(Integer spinnerStyle) { + this.spinnerStyle = spinnerStyle; + } + + public Integer getSpinnerColor() { + return spinnerColor; + } + + public void setSpinnerColor(Integer spinnerColor) { + this.spinnerColor = spinnerColor; + } + + public boolean isShowSpinner() { + return showSpinner; + } + + public void setShowSpinner(boolean showSpinner) { + this.showSpinner = showSpinner; + } + + public Integer getLaunchShowDuration() { + return launchShowDuration; + } + + public void setLaunchShowDuration(Integer launchShowDuration) { + this.launchShowDuration = launchShowDuration; + } + + public boolean isLaunchAutoHide() { + return launchAutoHide; + } + + public void setLaunchAutoHide(boolean launchAutoHide) { + this.launchAutoHide = launchAutoHide; + } + + public Integer getLaunchFadeInDuration() { + return launchFadeInDuration; + } + + public String getResourceName() { + return resourceName; + } + + public void setResourceName(String resourceName) { + this.resourceName = resourceName; + } + + public boolean isImmersive() { + return immersive; + } + + public void setImmersive(boolean immersive) { + this.immersive = immersive; + } + + public boolean isFullScreen() { + return fullScreen; + } + + public void setFullScreen(boolean fullScreen) { + this.fullScreen = fullScreen; + } + + public ScaleType getScaleType() { + return scaleType; + } + + public void setScaleType(ScaleType scaleType) { + this.scaleType = scaleType; + } +} diff --git a/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashScreenPlugin.java b/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashScreenPlugin.java new file mode 100644 index 000000000..70c22ffdb --- /dev/null +++ b/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashScreenPlugin.java @@ -0,0 +1,147 @@ +package com.capacitorjs.plugins.splashscreen; + +import android.widget.ImageView; +import com.getcapacitor.Logger; +import com.getcapacitor.Plugin; +import com.getcapacitor.PluginCall; +import com.getcapacitor.PluginMethod; +import com.getcapacitor.annotation.CapacitorPlugin; +import com.getcapacitor.util.WebColor; + +@CapacitorPlugin(name = "SplashScreen") +public class SplashScreenPlugin extends Plugin { + + private SplashScreen splashScreen; + + public void load() { + SplashScreenConfig config = getSplashScreenConfig(); + splashScreen = new SplashScreen(getContext(), config); + splashScreen.showOnLaunch(getActivity()); + } + + @PluginMethod + public void show(final PluginCall call) { + splashScreen.show( + getActivity(), + getSettings(call), + new SplashListener() { + @Override + public void completed() { + call.resolve(); + } + + @Override + public void error() { + call.reject("An error occurred while showing splash"); + } + } + ); + } + + @PluginMethod + public void hide(PluginCall call) { + splashScreen.hide(getSettings(call)); + call.resolve(); + } + + @Override + protected void handleOnPause() { + splashScreen.onPause(); + } + + @Override + protected void handleOnDestroy() { + splashScreen.onDestroy(); + } + + private SplashScreenSettings getSettings(PluginCall call) { + SplashScreenSettings settings = new SplashScreenSettings(); + if (call.getInt("showDuration") != null) { + settings.setShowDuration(call.getInt("showDuration")); + } + if (call.getInt("fadeInDuration") != null) { + settings.setFadeInDuration(call.getInt("fadeInDuration")); + } + if (call.getInt("fadeOutDuration") != null) { + settings.setFadeOutDuration(call.getInt("fadeOutDuration")); + } + if (call.getBoolean("autoHide") != null) { + settings.setAutoHide(call.getBoolean("autoHide")); + } + return settings; + } + + private SplashScreenConfig getSplashScreenConfig() { + SplashScreenConfig config = new SplashScreenConfig(); + String backgroundColor = getConfig().getString("backgroundColor"); + if (backgroundColor != null) { + try { + config.setBackgroundColor(WebColor.parseColor(backgroundColor)); + } catch (IllegalArgumentException ex) { + Logger.debug("Background color not applied"); + } + } + Integer duration = getConfig().getInt("launchShowDuration", config.getLaunchShowDuration()); + config.setLaunchShowDuration(duration); + Boolean autohide = getConfig().getBoolean("launchAutoHide", config.isLaunchAutoHide()); + config.setLaunchAutoHide(autohide); + if (getConfig().getString("androidSplashResourceName") != null) { + config.setResourceName(getConfig().getString("androidSplashResourceName")); + } + Boolean immersive = getConfig().getBoolean("splashImmersive", config.isImmersive()); + config.setImmersive(immersive); + + Boolean fullScreen = getConfig().getBoolean("splashFullScreen", config.isFullScreen()); + config.setFullScreen(fullScreen); + + String spinnerStyle = getConfig().getString("androidSpinnerStyle"); + if (spinnerStyle != null) { + int spinnerBarStyle = android.R.attr.progressBarStyleLarge; + + switch (spinnerStyle.toLowerCase()) { + case "horizontal": + spinnerBarStyle = android.R.attr.progressBarStyleHorizontal; + break; + case "small": + spinnerBarStyle = android.R.attr.progressBarStyleSmall; + break; + case "large": + spinnerBarStyle = android.R.attr.progressBarStyleLarge; + break; + case "inverse": + spinnerBarStyle = android.R.attr.progressBarStyleInverse; + break; + case "smallinverse": + spinnerBarStyle = android.R.attr.progressBarStyleSmallInverse; + break; + case "largeinverse": + spinnerBarStyle = android.R.attr.progressBarStyleLargeInverse; + break; + } + config.setSpinnerStyle(spinnerBarStyle); + } + String spinnerColor = getConfig().getString("spinnerColor"); + if (spinnerColor != null) { + try { + config.setSpinnerColor(WebColor.parseColor(spinnerColor)); + } catch (IllegalArgumentException ex) { + Logger.debug("Spinner color not applied"); + } + } + String scaleTypeName = getConfig().getString("androidScaleType"); + if (scaleTypeName != null) { + ImageView.ScaleType scaleType = null; + try { + scaleType = ImageView.ScaleType.valueOf(scaleTypeName); + } catch (IllegalArgumentException ex) { + scaleType = ImageView.ScaleType.FIT_XY; + } + config.setScaleType(scaleType); + } + + Boolean showSpinner = getConfig().getBoolean("showSpinner", config.isShowSpinner()); + config.setShowSpinner(showSpinner); + + return config; + } +} diff --git a/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashScreenSettings.java b/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashScreenSettings.java new file mode 100644 index 000000000..ca35dad7c --- /dev/null +++ b/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashScreenSettings.java @@ -0,0 +1,41 @@ +package com.capacitorjs.plugins.splashscreen; + +public class SplashScreenSettings { + + private Integer showDuration = 3000; + private Integer fadeInDuration = 200; + private Integer fadeOutDuration = 200; + private boolean autoHide = true; + + public Integer getShowDuration() { + return showDuration; + } + + public void setShowDuration(Integer showDuration) { + this.showDuration = showDuration; + } + + public Integer getFadeInDuration() { + return fadeInDuration; + } + + public void setFadeInDuration(Integer fadeInDuration) { + this.fadeInDuration = fadeInDuration; + } + + public Integer getFadeOutDuration() { + return fadeOutDuration; + } + + public void setFadeOutDuration(Integer fadeOutDuration) { + this.fadeOutDuration = fadeOutDuration; + } + + public boolean isAutoHide() { + return autoHide; + } + + public void setAutoHide(boolean autoHide) { + this.autoHide = autoHide; + } +} diff --git a/splash-screen/android/src/main/res/.gitkeep b/splash-screen/android/src/main/res/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/splash-screen/android/src/test/java/com/getcapacitor/ExampleUnitTest.java b/splash-screen/android/src/test/java/com/getcapacitor/ExampleUnitTest.java new file mode 100644 index 000000000..a0fed0cfb --- /dev/null +++ b/splash-screen/android/src/test/java/com/getcapacitor/ExampleUnitTest.java @@ -0,0 +1,18 @@ +package com.getcapacitor; + +import static org.junit.Assert.*; + +import org.junit.Test; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + + @Test + public void addition_isCorrect() throws Exception { + assertEquals(4, 2 + 2); + } +} diff --git a/splash-screen/ios/Plugin.xcodeproj/project.pbxproj b/splash-screen/ios/Plugin.xcodeproj/project.pbxproj new file mode 100644 index 000000000..54ace3155 --- /dev/null +++ b/splash-screen/ios/Plugin.xcodeproj/project.pbxproj @@ -0,0 +1,577 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 48; + objects = { + +/* Begin PBXBuildFile section */ + 03FC29A292ACC40490383A1F /* Pods_Plugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B2A61DA5A1F2DD4F959604D /* Pods_Plugin.framework */; }; + 20C0B05DCFC8E3958A738AF2 /* Pods_PluginTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6753A823D3815DB436415E3 /* Pods_PluginTests.framework */; }; + 2F94DB20258B85A6003E0C43 /* SplashScreenSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F94DB1F258B85A6003E0C43 /* SplashScreenSettings.swift */; }; + 2F94DB24258B85BE003E0C43 /* SplashScreenConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F94DB23258B85BE003E0C43 /* SplashScreenConfig.swift */; }; + 2F98D68224C9AAE500613A4C /* SplashScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F98D68124C9AAE400613A4C /* SplashScreen.swift */; }; + 50ADFF92201F53D600D50D53 /* Plugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50ADFF88201F53D600D50D53 /* Plugin.framework */; }; + 50ADFF97201F53D600D50D53 /* SplashScreenPluginTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50ADFF96201F53D600D50D53 /* SplashScreenPluginTests.swift */; }; + 50ADFF99201F53D600D50D53 /* SplashScreenPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 50ADFF8B201F53D600D50D53 /* SplashScreenPlugin.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 50ADFFA42020D75100D50D53 /* Capacitor.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50ADFFA52020D75100D50D53 /* Capacitor.framework */; }; + 50ADFFA82020EE4F00D50D53 /* SplashScreenPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 50ADFFA72020EE4F00D50D53 /* SplashScreenPlugin.m */; }; + 50E1A94820377CB70090CE1A /* SplashScreenPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E1A94720377CB70090CE1A /* SplashScreenPlugin.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 50ADFF93201F53D600D50D53 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 50ADFF7F201F53D600D50D53 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 50ADFF87201F53D600D50D53; + remoteInfo = Plugin; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 2F94DB1F258B85A6003E0C43 /* SplashScreenSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashScreenSettings.swift; sourceTree = ""; }; + 2F94DB23258B85BE003E0C43 /* SplashScreenConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashScreenConfig.swift; sourceTree = ""; }; + 2F98D68124C9AAE400613A4C /* SplashScreen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SplashScreen.swift; sourceTree = ""; }; + 3B2A61DA5A1F2DD4F959604D /* Pods_Plugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Plugin.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 50ADFF88201F53D600D50D53 /* Plugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Plugin.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 50ADFF8B201F53D600D50D53 /* SplashScreenPlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SplashScreenPlugin.h; sourceTree = ""; }; + 50ADFF8C201F53D600D50D53 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 50ADFF91201F53D600D50D53 /* PluginTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PluginTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 50ADFF96201F53D600D50D53 /* SplashScreenPluginTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashScreenPluginTests.swift; sourceTree = ""; }; + 50ADFF98201F53D600D50D53 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 50ADFFA52020D75100D50D53 /* Capacitor.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Capacitor.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 50ADFFA72020EE4F00D50D53 /* SplashScreenPlugin.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SplashScreenPlugin.m; sourceTree = ""; }; + 50E1A94720377CB70090CE1A /* SplashScreenPlugin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SplashScreenPlugin.swift; sourceTree = ""; }; + 5E23F77F099397094342571A /* Pods-Plugin.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Plugin.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Plugin/Pods-Plugin.debug.xcconfig"; sourceTree = ""; }; + 91781294A431A2A7CC6EB714 /* Pods-Plugin.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Plugin.release.xcconfig"; path = "Pods/Target Support Files/Pods-Plugin/Pods-Plugin.release.xcconfig"; sourceTree = ""; }; + 96ED1B6440D6672E406C8D19 /* Pods-PluginTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PluginTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests.debug.xcconfig"; sourceTree = ""; }; + F65BB2953ECE002E1EF3E424 /* Pods-PluginTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PluginTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests.release.xcconfig"; sourceTree = ""; }; + F6753A823D3815DB436415E3 /* Pods_PluginTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PluginTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 50ADFF84201F53D600D50D53 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 50ADFFA42020D75100D50D53 /* Capacitor.framework in Frameworks */, + 03FC29A292ACC40490383A1F /* Pods_Plugin.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 50ADFF8E201F53D600D50D53 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 50ADFF92201F53D600D50D53 /* Plugin.framework in Frameworks */, + 20C0B05DCFC8E3958A738AF2 /* Pods_PluginTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 50ADFF7E201F53D600D50D53 = { + isa = PBXGroup; + children = ( + 50ADFF8A201F53D600D50D53 /* Plugin */, + 50ADFF95201F53D600D50D53 /* PluginTests */, + 50ADFF89201F53D600D50D53 /* Products */, + 8C8E7744173064A9F6D438E3 /* Pods */, + A797B9EFA3DCEFEA1FBB66A9 /* Frameworks */, + ); + sourceTree = ""; + }; + 50ADFF89201F53D600D50D53 /* Products */ = { + isa = PBXGroup; + children = ( + 50ADFF88201F53D600D50D53 /* Plugin.framework */, + 50ADFF91201F53D600D50D53 /* PluginTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 50ADFF8A201F53D600D50D53 /* Plugin */ = { + isa = PBXGroup; + children = ( + 2F94DB23258B85BE003E0C43 /* SplashScreenConfig.swift */, + 2F94DB1F258B85A6003E0C43 /* SplashScreenSettings.swift */, + 50E1A94720377CB70090CE1A /* SplashScreenPlugin.swift */, + 2F98D68124C9AAE400613A4C /* SplashScreen.swift */, + 50ADFF8B201F53D600D50D53 /* SplashScreenPlugin.h */, + 50ADFFA72020EE4F00D50D53 /* SplashScreenPlugin.m */, + 50ADFF8C201F53D600D50D53 /* Info.plist */, + ); + path = Plugin; + sourceTree = ""; + }; + 50ADFF95201F53D600D50D53 /* PluginTests */ = { + isa = PBXGroup; + children = ( + 50ADFF96201F53D600D50D53 /* SplashScreenPluginTests.swift */, + 50ADFF98201F53D600D50D53 /* Info.plist */, + ); + path = PluginTests; + sourceTree = ""; + }; + 8C8E7744173064A9F6D438E3 /* Pods */ = { + isa = PBXGroup; + children = ( + 5E23F77F099397094342571A /* Pods-Plugin.debug.xcconfig */, + 91781294A431A2A7CC6EB714 /* Pods-Plugin.release.xcconfig */, + 96ED1B6440D6672E406C8D19 /* Pods-PluginTests.debug.xcconfig */, + F65BB2953ECE002E1EF3E424 /* Pods-PluginTests.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; + A797B9EFA3DCEFEA1FBB66A9 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 50ADFFA52020D75100D50D53 /* Capacitor.framework */, + 3B2A61DA5A1F2DD4F959604D /* Pods_Plugin.framework */, + F6753A823D3815DB436415E3 /* Pods_PluginTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 50ADFF85201F53D600D50D53 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 50ADFF99201F53D600D50D53 /* SplashScreenPlugin.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 50ADFF87201F53D600D50D53 /* Plugin */ = { + isa = PBXNativeTarget; + buildConfigurationList = 50ADFF9C201F53D600D50D53 /* Build configuration list for PBXNativeTarget "Plugin" */; + buildPhases = ( + AB5B3E54B4E897F32C2279DA /* [CP] Check Pods Manifest.lock */, + 50ADFF83201F53D600D50D53 /* Sources */, + 50ADFF84201F53D600D50D53 /* Frameworks */, + 50ADFF85201F53D600D50D53 /* Headers */, + 50ADFF86201F53D600D50D53 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Plugin; + productName = Plugin; + productReference = 50ADFF88201F53D600D50D53 /* Plugin.framework */; + productType = "com.apple.product-type.framework"; + }; + 50ADFF90201F53D600D50D53 /* PluginTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 50ADFF9F201F53D600D50D53 /* Build configuration list for PBXNativeTarget "PluginTests" */; + buildPhases = ( + 0596884F929ED6F1DE134961 /* [CP] Check Pods Manifest.lock */, + 50ADFF8D201F53D600D50D53 /* Sources */, + 50ADFF8E201F53D600D50D53 /* Frameworks */, + 50ADFF8F201F53D600D50D53 /* Resources */, + 8E97F58B69A94C6503FC9C85 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 50ADFF94201F53D600D50D53 /* PBXTargetDependency */, + ); + name = PluginTests; + productName = PluginTests; + productReference = 50ADFF91201F53D600D50D53 /* PluginTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 50ADFF7F201F53D600D50D53 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1160; + ORGANIZATIONNAME = "Max Lynch"; + TargetAttributes = { + 50ADFF87201F53D600D50D53 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + }; + 50ADFF90201F53D600D50D53 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 50ADFF82201F53D600D50D53 /* Build configuration list for PBXProject "Plugin" */; + compatibilityVersion = "Xcode 8.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 50ADFF7E201F53D600D50D53; + productRefGroup = 50ADFF89201F53D600D50D53 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 50ADFF87201F53D600D50D53 /* Plugin */, + 50ADFF90201F53D600D50D53 /* PluginTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 50ADFF86201F53D600D50D53 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 50ADFF8F201F53D600D50D53 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 0596884F929ED6F1DE134961 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-PluginTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 8E97F58B69A94C6503FC9C85 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-PluginTests/Pods-PluginTests-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/Capacitor/Capacitor.framework", + "${BUILT_PRODUCTS_DIR}/CapacitorCordova/Cordova.framework", + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Capacitor.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Cordova.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-PluginTests/Pods-PluginTests-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + AB5B3E54B4E897F32C2279DA /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Plugin-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 50ADFF83201F53D600D50D53 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 50E1A94820377CB70090CE1A /* SplashScreenPlugin.swift in Sources */, + 2F94DB20258B85A6003E0C43 /* SplashScreenSettings.swift in Sources */, + 2F94DB24258B85BE003E0C43 /* SplashScreenConfig.swift in Sources */, + 2F98D68224C9AAE500613A4C /* SplashScreen.swift in Sources */, + 50ADFFA82020EE4F00D50D53 /* SplashScreenPlugin.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 50ADFF8D201F53D600D50D53 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 50ADFF97201F53D600D50D53 /* SplashScreenPluginTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 50ADFF94201F53D600D50D53 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 50ADFF87201F53D600D50D53 /* Plugin */; + targetProxy = 50ADFF93201F53D600D50D53 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 50ADFF9A201F53D600D50D53 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + FRAMEWORK_SEARCH_PATHS = ( + "\"${BUILT_PRODUCTS_DIR}/Capacitor\"", + "\"${BUILT_PRODUCTS_DIR}/CapacitorCordova\"", + ); + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 50ADFF9B201F53D600D50D53 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + FRAMEWORK_SEARCH_PATHS = ( + "\"${BUILT_PRODUCTS_DIR}/Capacitor\"", + "\"${BUILT_PRODUCTS_DIR}/CapacitorCordova\"", + ); + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 50ADFF9D201F53D600D50D53 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5E23F77F099397094342571A /* Pods-Plugin.debug.xcconfig */; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Automatic; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = Plugin/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)"; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 50ADFF9E201F53D600D50D53 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 91781294A431A2A7CC6EB714 /* Pods-Plugin.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Automatic; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = Plugin/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)"; + ONLY_ACTIVE_ARCH = NO; + PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + 50ADFFA0201F53D600D50D53 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 96ED1B6440D6672E406C8D19 /* Pods-PluginTests.debug.xcconfig */; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = PluginTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.PluginTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 50ADFFA1201F53D600D50D53 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F65BB2953ECE002E1EF3E424 /* Pods-PluginTests.release.xcconfig */; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = PluginTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.PluginTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 50ADFF82201F53D600D50D53 /* Build configuration list for PBXProject "Plugin" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 50ADFF9A201F53D600D50D53 /* Debug */, + 50ADFF9B201F53D600D50D53 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 50ADFF9C201F53D600D50D53 /* Build configuration list for PBXNativeTarget "Plugin" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 50ADFF9D201F53D600D50D53 /* Debug */, + 50ADFF9E201F53D600D50D53 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 50ADFF9F201F53D600D50D53 /* Build configuration list for PBXNativeTarget "PluginTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 50ADFFA0201F53D600D50D53 /* Debug */, + 50ADFFA1201F53D600D50D53 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 50ADFF7F201F53D600D50D53 /* Project object */; +} diff --git a/splash-screen/ios/Plugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/splash-screen/ios/Plugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/splash-screen/ios/Plugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/splash-screen/ios/Plugin.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/splash-screen/ios/Plugin.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/splash-screen/ios/Plugin.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/splash-screen/ios/Plugin.xcodeproj/xcshareddata/xcschemes/Plugin.xcscheme b/splash-screen/ios/Plugin.xcodeproj/xcshareddata/xcschemes/Plugin.xcscheme new file mode 100644 index 000000000..303f2621b --- /dev/null +++ b/splash-screen/ios/Plugin.xcodeproj/xcshareddata/xcschemes/Plugin.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/splash-screen/ios/Plugin.xcodeproj/xcshareddata/xcschemes/PluginTests.xcscheme b/splash-screen/ios/Plugin.xcodeproj/xcshareddata/xcschemes/PluginTests.xcscheme new file mode 100644 index 000000000..3d8c88d25 --- /dev/null +++ b/splash-screen/ios/Plugin.xcodeproj/xcshareddata/xcschemes/PluginTests.xcscheme @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/splash-screen/ios/Plugin.xcworkspace/contents.xcworkspacedata b/splash-screen/ios/Plugin.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..afad624ec --- /dev/null +++ b/splash-screen/ios/Plugin.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/splash-screen/ios/Plugin.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/splash-screen/ios/Plugin.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/splash-screen/ios/Plugin.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/splash-screen/ios/Plugin/Info.plist b/splash-screen/ios/Plugin/Info.plist new file mode 100644 index 000000000..1007fd9dd --- /dev/null +++ b/splash-screen/ios/Plugin/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/splash-screen/ios/Plugin/SplashScreen.swift b/splash-screen/ios/Plugin/SplashScreen.swift new file mode 100644 index 000000000..e1ec3301e --- /dev/null +++ b/splash-screen/ios/Plugin/SplashScreen.swift @@ -0,0 +1,160 @@ +import Foundation +import Capacitor + +@objc public class SplashScreen: NSObject { + + var parentView: UIView + var imageView = UIImageView() + var image: UIImage? + var spinner = UIActivityIndicatorView() + var config: SplashScreenConfig = SplashScreenConfig() + var hideTask: Any? + var isVisible: Bool = false + + init(parentView: UIView, config: SplashScreenConfig) { + self.parentView = parentView + self.config = config + } + + public func showOnLaunch() { + buildViews() + if self.config.launchShowDuration == 0 { + return + } + var settings = SplashScreenSettings() + settings.showDuration = config.launchShowDuration + settings.fadeInDuration = config.launchFadeInDuration + showSplash(settings: settings, completion: {}, isLaunchSplash: true) + } + + public func show(settings: SplashScreenSettings, completion: @escaping () -> Void) { + self.showSplash(settings: settings, completion: completion, isLaunchSplash: false) + } + + public func hide(settings: SplashScreenSettings) { + hideSplash(fadeOutDuration: settings.fadeOutDuration, isLaunchSplash: false) + } + + private func showSplash(settings: SplashScreenSettings, completion: @escaping () -> Void, isLaunchSplash: Bool) { + DispatchQueue.main.async { [weak self] in + guard let strongSelf = self else { + return + } + if let backgroundColor = strongSelf.config.backgroundColor { + strongSelf.imageView.backgroundColor = backgroundColor + } + + if strongSelf.config.showSpinner { + if let style = strongSelf.config.spinnerStyle { + strongSelf.spinner.style = style + } + + if let spinnerColor = strongSelf.config.spinnerColor { + strongSelf.spinner.color = spinnerColor + } + } + + strongSelf.parentView.addSubview(strongSelf.imageView) + + if strongSelf.config.showSpinner { + strongSelf.parentView.addSubview(strongSelf.spinner) + strongSelf.spinner.centerXAnchor.constraint(equalTo: strongSelf.parentView.centerXAnchor).isActive = true + strongSelf.spinner.centerYAnchor.constraint(equalTo: strongSelf.parentView.centerYAnchor).isActive = true + } + + strongSelf.parentView.isUserInteractionEnabled = false + + UIView.transition(with: strongSelf.imageView, duration: TimeInterval(Double(settings.fadeInDuration) / 1000), options: .curveLinear, animations: { + strongSelf.imageView.alpha = 1 + + if strongSelf.config.showSpinner { + strongSelf.spinner.alpha = 1 + } + }) { (_: Bool) in + strongSelf.isVisible = true + + if settings.autoHide { + strongSelf.hideTask = DispatchQueue.main.asyncAfter( + deadline: DispatchTime.now() + (Double(settings.showDuration) / 1000) + ) { + strongSelf.hideSplash(fadeOutDuration: settings.fadeOutDuration, isLaunchSplash: isLaunchSplash) + completion() + } + } else { + completion() + } + } + } + } + + private func buildViews() { + // Find the image asset named "Splash" + // TODO: Find a way to not hard code this? + image = UIImage(named: "Splash") + + if image == nil { + CAPLog.print("Unable to find splash screen image. Make sure an image called Splash exists in your assets") + } + + // Observe for changes on frame and bounds to handle rotation resizing + parentView.addObserver(self, forKeyPath: "frame", options: .new, context: nil) + parentView.addObserver(self, forKeyPath: "bounds", options: .new, context: nil) + + updateSplashImageBounds() + if config.showSpinner { + spinner.translatesAutoresizingMaskIntoConstraints = false + spinner.startAnimating() + } + } + + private func tearDown() { + isVisible = false + parentView.isUserInteractionEnabled = true + imageView.removeFromSuperview() + + if config.showSpinner { + spinner.removeFromSuperview() + } + } + + // Update the bounds for the splash image. This will also be called when + // the parent view observers fire + private func updateSplashImageBounds() { + guard let delegate = UIApplication.shared.delegate else { + CAPLog.print("Unable to find root window object for SplashScreen bounds. Please file an issue") + return + } + + guard let window = delegate.window as? UIWindow else { + CAPLog.print("Unable to find root window object for SplashScreen bounds. Please file an issue") + return + } + imageView.image = image + imageView.frame = CGRect(origin: CGPoint(x: 0, y: 0), size: window.bounds.size) + imageView.contentMode = .scaleAspectFill + } + + override public func observeValue(forKeyPath keyPath: String?, of object: Any?, change _: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) { + updateSplashImageBounds() + } + + private func hideSplash(fadeOutDuration: Int, isLaunchSplash: Bool) { + if isLaunchSplash, isVisible { + CAPLog.print("SplashScreen.hideSplash: SplashScreen was automatically hidden after default timeout. " + + "You should call `SplashScreen.hide()` as soon as your web app is loaded (or increase the timeout). " + + "Read more at https://capacitorjs.com/docs/apis/splash-screen#hiding-the-splash-screen") + } + if !isVisible { return } + DispatchQueue.main.async { + UIView.transition(with: self.imageView, duration: TimeInterval(Double(fadeOutDuration) / 1000), options: .curveLinear, animations: { + self.imageView.alpha = 0 + + if self.config.showSpinner { + self.spinner.alpha = 0 + } + }) { (_: Bool) in + self.tearDown() + } + } + } +} diff --git a/splash-screen/ios/Plugin/SplashScreenConfig.swift b/splash-screen/ios/Plugin/SplashScreenConfig.swift new file mode 100644 index 000000000..a524216dd --- /dev/null +++ b/splash-screen/ios/Plugin/SplashScreenConfig.swift @@ -0,0 +1,11 @@ +import UIKit + +public struct SplashScreenConfig { + var backgroundColor: UIColor? + var spinnerStyle: UIActivityIndicatorView.Style? + var spinnerColor: UIColor? + var showSpinner = false + var launchShowDuration = 0 + var launchAutoHide = true + let launchFadeInDuration = 0 +} diff --git a/splash-screen/ios/Plugin/SplashScreenPlugin.h b/splash-screen/ios/Plugin/SplashScreenPlugin.h new file mode 100644 index 000000000..f2bd9e0bb --- /dev/null +++ b/splash-screen/ios/Plugin/SplashScreenPlugin.h @@ -0,0 +1,10 @@ +#import + +//! Project version number for Plugin. +FOUNDATION_EXPORT double PluginVersionNumber; + +//! Project version string for Plugin. +FOUNDATION_EXPORT const unsigned char PluginVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + diff --git a/splash-screen/ios/Plugin/SplashScreenPlugin.m b/splash-screen/ios/Plugin/SplashScreenPlugin.m new file mode 100644 index 000000000..01a7e8945 --- /dev/null +++ b/splash-screen/ios/Plugin/SplashScreenPlugin.m @@ -0,0 +1,9 @@ +#import +#import + +// Define the plugin using the CAP_PLUGIN Macro, and +// each method the plugin supports using the CAP_PLUGIN_METHOD macro. +CAP_PLUGIN(SplashScreenPlugin, "SplashScreen", + CAP_PLUGIN_METHOD(show, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(hide, CAPPluginReturnPromise); +) diff --git a/splash-screen/ios/Plugin/SplashScreenPlugin.swift b/splash-screen/ios/Plugin/SplashScreenPlugin.swift new file mode 100644 index 000000000..1fee828e9 --- /dev/null +++ b/splash-screen/ios/Plugin/SplashScreenPlugin.swift @@ -0,0 +1,88 @@ +import Foundation +import Capacitor + +@objc(SplashScreenPlugin) +public class SplashScreenPlugin: CAPPlugin { + private var splashScreen: SplashScreen? + + override public func load() { + if let view = bridge?.viewController?.view { + splashScreen = SplashScreen(parentView: view, config: splashScreenConfig()) + splashScreen?.showOnLaunch() + } + } + + // Show the splash screen + @objc public func show(_ call: CAPPluginCall) { + if let splash = splashScreen { + let settings = splashScreenSettings(from: call) + splash.show(settings: settings, + completion: { + call.resolve() + }) + } else { + call.reject("Unable to show Splash Screen") + } + + } + + // Hide the splash screen + @objc public func hide(_ call: CAPPluginCall) { + if let splash = splashScreen { + let settings = splashScreenSettings(from: call) + splash.hide(settings: settings) + call.resolve() + } else { + call.reject("Unable to hide Splash Screen") + } + } + + private func splashScreenSettings(from call: CAPPluginCall) -> SplashScreenSettings { + var settings = SplashScreenSettings() + + if let showDuration = call.getInt("showDuration") { + settings.showDuration = showDuration + } + if let fadeInDuration = call.getInt("fadeInDuration") { + settings.fadeInDuration = fadeInDuration + } + if let fadeOutDuration = call.getInt("fadeOutDuration") { + settings.fadeOutDuration = fadeOutDuration + } + if let autoHide = call.getBool("autoHide") { + settings.autoHide = autoHide + } + return settings + } + + private func splashScreenConfig() -> SplashScreenConfig { + var config = SplashScreenConfig() + + if let backgroundColor = getConfigValue("backgroundColor") as? String { + config.backgroundColor = UIColor.capacitor.color(fromHex: backgroundColor) + } + if let spinnerStyle = getConfigValue("iosSpinnerStyle") as? String { + switch spinnerStyle.lowercased() { + case "small": + config.spinnerStyle = .white + default: + config.spinnerStyle = .whiteLarge + } + } + if let spinnerColor = getConfigValue("spinnerColor") as? String { + config.spinnerColor = UIColor.capacitor.color(fromHex: spinnerColor) + } + if let showSpinner = getConfigValue("showSpinner") as? Bool { + config.showSpinner = showSpinner + } + + if let launchShowDuration = getConfigValue("launchShowDuration") as? Int { + config.launchShowDuration = launchShowDuration + } + if let launchAutoHide = getConfigValue("launchAutoHide") as? Bool { + config.launchAutoHide = launchAutoHide + } + return config + } + +} diff --git a/splash-screen/ios/Plugin/SplashScreenSettings.swift b/splash-screen/ios/Plugin/SplashScreenSettings.swift new file mode 100644 index 000000000..483bdfbd7 --- /dev/null +++ b/splash-screen/ios/Plugin/SplashScreenSettings.swift @@ -0,0 +1,8 @@ +import UIKit + +public struct SplashScreenSettings { + var showDuration = 3000 + var fadeInDuration = 200 + var fadeOutDuration = 200 + var autoHide = true +} diff --git a/splash-screen/ios/PluginTests/Info.plist b/splash-screen/ios/PluginTests/Info.plist new file mode 100644 index 000000000..6c40a6cd0 --- /dev/null +++ b/splash-screen/ios/PluginTests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/splash-screen/ios/PluginTests/SplashScreenPluginTests.swift b/splash-screen/ios/PluginTests/SplashScreenPluginTests.swift new file mode 100644 index 000000000..e40584a38 --- /dev/null +++ b/splash-screen/ios/PluginTests/SplashScreenPluginTests.swift @@ -0,0 +1,14 @@ +import XCTest +@testable import Plugin + +class SplashScreenTests: XCTestCase { + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } +} diff --git a/splash-screen/ios/Podfile b/splash-screen/ios/Podfile new file mode 100644 index 000000000..350751435 --- /dev/null +++ b/splash-screen/ios/Podfile @@ -0,0 +1,16 @@ +platform :ios, '11.0' + +def capacitor_pods + # Comment the next line if you're not using Swift and don't want to use dynamic frameworks + use_frameworks! + pod 'Capacitor', :path => '../node_modules/@capacitor/ios' + pod 'CapacitorCordova', :path => '../node_modules/@capacitor/ios' +end + +target 'Plugin' do + capacitor_pods +end + +target 'PluginTests' do + capacitor_pods +end diff --git a/splash-screen/package.json b/splash-screen/package.json new file mode 100644 index 000000000..a267342cf --- /dev/null +++ b/splash-screen/package.json @@ -0,0 +1,81 @@ +{ + "name": "@capacitor/splash-screen", + "version": "0.0.1", + "description": "The Splash Screen API provides methods for showing or hiding a Splash image.", + "main": "dist/esm/index.js", + "types": "dist/esm/index.d.ts", + "unpkg": "dist/plugin.js", + "files": [ + "android/src/main/", + "android/build.gradle", + "dist/", + "ios/Plugin/", + "CapacitorSplashScreen.podspec" + ], + "author": "Ionic ", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/ionic-team/capacitor-plugins.git" + }, + "bugs": { + "url": "https://github.com/ionic-team/capacitor-plugins/issues" + }, + "keywords": [ + "capacitor", + "plugin", + "native" + ], + "scripts": { + "verify": "npm run verify:ios && npm run verify:android && npm run verify:web", + "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin && cd ..", + "verify:android": "cd android && ./gradlew clean build test && cd ..", + "verify:web": "npm run build", + "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint", + "fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- autocorrect --format", + "eslint": "eslint . --ext ts", + "prettier": "prettier \"**/*.{css,html,ts,js,java}\"", + "swiftlint": "node-swiftlint", + "docgen": "docgen --api SplashScreenPlugin --output-readme README.md --output-json dist/docs.json", + "build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.js", + "clean": "rimraf ./dist", + "watch": "tsc --watch", + "prepublishOnly": "npm run build" + }, + "devDependencies": { + "@capacitor/android": "^3.0.0-alpha.10", + "@capacitor/cli": "^3.0.0-alpha.9", + "@capacitor/core": "^3.0.0-alpha.9", + "@capacitor/docgen": "0.0.14", + "@capacitor/ios": "^3.0.0-alpha.9", + "@ionic/eslint-config": "^0.3.0", + "@ionic/prettier-config": "~1.0.1", + "@ionic/swiftlint-config": "^1.1.2", + "eslint": "^7.11.0", + "prettier": "~2.2.0", + "prettier-plugin-java": "~1.0.0", + "rimraf": "^3.0.2", + "rollup": "^2.32.0", + "swiftlint": "^1.0.1", + "typescript": "~4.0.3" + }, + "peerDependencies": { + "@capacitor/core": "^3.0.0-alpha.9" + }, + "prettier": "@ionic/prettier-config", + "swiftlint": "@ionic/swiftlint-config", + "eslintConfig": { + "extends": "@ionic/eslint-config/recommended" + }, + "capacitor": { + "ios": { + "src": "ios" + }, + "android": { + "src": "android" + } + }, + "publishConfig": { + "access": "public" + } +} diff --git a/splash-screen/rollup.config.js b/splash-screen/rollup.config.js new file mode 100644 index 000000000..69ac2c720 --- /dev/null +++ b/splash-screen/rollup.config.js @@ -0,0 +1,14 @@ +export default { + input: 'dist/esm/index.js', + output: { + file: 'dist/plugin.js', + format: 'iife', + name: 'capacitorSplashScreen', + globals: { + '@capacitor/core': 'capacitorExports', + }, + sourcemap: true, + inlineDynamicImports: true, + }, + external: ['@capacitor/core'], +}; diff --git a/splash-screen/src/definitions.ts b/splash-screen/src/definitions.ts new file mode 100644 index 000000000..5a81fb5e7 --- /dev/null +++ b/splash-screen/src/definitions.ts @@ -0,0 +1,170 @@ +/// + +declare module '@capacitor/cli' { + export interface PluginsConfig { + SplashScreen?: { + /** + * How long to show the launch splash screen when autoHide is enabled (in ms) + * + * @since 1.0.0 + * @default 0 + */ + launchShowDuration?: number; + + /** + * Whether to auto hide the splash after launchShowDuration + * + * @since 1.0.0 + * @default true + */ + launchAutoHide?: boolean; + + /** + * Color of the background of the Splash Screen in hex format, #RRGGBB or #RRGGBBAA + * + * @since 1.0.0 + */ + backgroundColor?: string; + + /** + * Name of the resource to be used as Splash Screen + * + * Only available on Android + * + * @since 1.0.0 + * @default splash + */ + androidSplashResourceName?: string; + + /** + * The [ImageView.ScaleType](https://developer.android.com/reference/android/widget/ImageView.ScaleType) used to scale + * the Splash Screen image + * + * Only available on Android + * + * @since 1.0.0 + * @default FIT_XY + */ + androidScaleType?: + | 'CENTER' + | 'CENTER_CROP' + | 'CENTER_INSIDE' + | 'FIT_CENTER' + | 'FIT_END' + | 'FIT_START' + | 'FIT_XY' + | 'MATRIX'; + + /** + * Show a loading spinner on the Splash Screen + * + * @since 1.0.0 + */ + showSpinner?: boolean; + + /** + * Style of the Android spinner + * + * @since 1.0.0 + * @default large + */ + androidSpinnerStyle?: + | 'horizontal' + | 'small' + | 'large' + | 'inverse' + | 'smallInverse' + | 'largeInverse'; + + /** + * Style of the iOS spinner + * + * Only available on iOS. + * + * @since 1.0.0 + * @default large + */ + iosSpinnerStyle?: 'large' | 'small'; + + /** + * Color of the spinner in hex format, #RRGGBB or #RRGGBBAA + * + * @since 1.0.0 + */ + spinnerColor?: string; + + /** + * Hide the status bar on the Splash Screen + * + * Only available on Android + * + * @since 1.0.0 + */ + splashFullScreen?: boolean; + + /** + * Hide the status bar and the software navigation buttons on the Splash Screen + * + * Only available on Android + * + * @since 1.0.0 + */ + splashImmersive?: boolean; + }; + } +} + +export interface SplashScreenShowOptions { + /** + * Whether to auto hide the splash after showDuration + * + * @since 1.0.0 + */ + autoHide?: boolean; + /** + * How long (in ms) to fade in. + * + * @since 1.0.0 + * @default 200 + */ + fadeInDuration?: number; + /** + * How long (in ms) to fade out. + * + * @since 1.0.0 + * @default 200 + */ + fadeOutDuration?: number; + /** + * How long to show the splash screen when autoHide is enabled (in ms) + * + * @since 1.0.0 + * @default 3000 + */ + showDuration?: number; +} + +export interface SplashScreenHideOptions { + /** + * How long (in ms) to fade out. + * + * @since 1.0.0 + * @default 200 + */ + fadeOutDuration?: number; +} + +export interface SplashScreenPlugin { + /** + * Show the splash screen + * + * @since 1.0.0 + */ + show(options?: SplashScreenShowOptions): Promise; + /** + * Hide the splash screen + * + * @since 1.0.0 + */ + hide(options?: SplashScreenHideOptions): Promise; +} diff --git a/splash-screen/src/index.ts b/splash-screen/src/index.ts new file mode 100644 index 000000000..645e7f2af --- /dev/null +++ b/splash-screen/src/index.ts @@ -0,0 +1,9 @@ +import { registerPlugin } from '@capacitor/core'; + +import type { SplashScreenPlugin } from './definitions'; + +const SplashScreen = registerPlugin('SplashScreen', { + web: () => import('./web').then(m => new m.SplashScreenWeb()), +}); + +export { SplashScreen }; diff --git a/splash-screen/src/web.ts b/splash-screen/src/web.ts new file mode 100644 index 000000000..e9b39fb36 --- /dev/null +++ b/splash-screen/src/web.ts @@ -0,0 +1,17 @@ +import { WebPlugin } from '@capacitor/core'; + +import type { + SplashScreenPlugin, + SplashScreenShowOptions, + SplashScreenHideOptions, +} from './definitions'; + +export class SplashScreenWeb extends WebPlugin implements SplashScreenPlugin { + async show(_options?: SplashScreenShowOptions): Promise { + return undefined; + } + + async hide(_options?: SplashScreenHideOptions): Promise { + return undefined; + } +} diff --git a/splash-screen/tsconfig.json b/splash-screen/tsconfig.json new file mode 100644 index 000000000..3bb999d96 --- /dev/null +++ b/splash-screen/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "allowUnreachableCode": false, + "declaration": true, + "esModuleInterop": true, + "lib": ["dom"], + "module": "esnext", + "moduleResolution": "node", + "noFallthroughCasesInSwitch": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "outDir": "dist/esm", + "pretty": true, + "sourceMap": true, + "strict": true, + "target": "es2017" + }, + "files": ["src/index.ts"] +}