diff --git a/lerna.json b/lerna.json index 7fb7212e2..fdc55a556 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,6 @@ { "packages": [ + "screen-reader", "text-zoom" ], "command": { diff --git a/package.json b/package.json index 114090c65..755b20dce 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "build": "lerna run build", "watch": "lerna run --parallel --stream watch", "lint": "lerna run lint", + "fmt": "lerna run fmt", "toggle-local": "node ./scripts/toggle-local.mjs && lerna bootstrap", "postinstall": "lerna bootstrap" }, diff --git a/screen-reader/.gitignore b/screen-reader/.gitignore new file mode 100644 index 000000000..40511aec5 --- /dev/null +++ b/screen-reader/.gitignore @@ -0,0 +1,60 @@ +# node files +dist/ +node_modules/ + +# iOS files +Pods +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/screen-reader/.prettierignore b/screen-reader/.prettierignore new file mode 100644 index 000000000..9d0b71a3c --- /dev/null +++ b/screen-reader/.prettierignore @@ -0,0 +1,2 @@ +build +dist diff --git a/screen-reader/CapacitorScreenReader.podspec b/screen-reader/CapacitorScreenReader.podspec new file mode 100644 index 000000000..b40850f5d --- /dev/null +++ b/screen-reader/CapacitorScreenReader.podspec @@ -0,0 +1,17 @@ +require 'json' + +package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) + +Pod::Spec.new do |s| + s.name = 'CapacitorScreenReader' + 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/screen-reader/android/.gitignore b/screen-reader/android/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/screen-reader/android/.gitignore @@ -0,0 +1 @@ +/build diff --git a/screen-reader/android/build.gradle b/screen-reader/android/build.gradle new file mode 100644 index 000000000..9d6618f87 --- /dev/null +++ b/screen-reader/android/build.gradle @@ -0,0 +1,56 @@ +ext { + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.12' + 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.0.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 { + targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_1_8 + } +} + +repositories { + google() + jcenter() + mavenCentral() +} + + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation project(':capacitor-android') + testImplementation "junit:junit:$junitVersion" + androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" + androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion" +} diff --git a/screen-reader/android/gradle.properties b/screen-reader/android/gradle.properties new file mode 100644 index 000000000..0566c221d --- /dev/null +++ b/screen-reader/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/screen-reader/android/gradle/wrapper/gradle-wrapper.jar b/screen-reader/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..f3d88b1c2 Binary files /dev/null and b/screen-reader/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/screen-reader/android/gradle/wrapper/gradle-wrapper.properties b/screen-reader/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..4e1cc9db6 --- /dev/null +++ b/screen-reader/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.1.1-all.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/screen-reader/android/gradlew b/screen-reader/android/gradlew new file mode 100755 index 000000000..2fe81a7d9 --- /dev/null +++ b/screen-reader/android/gradlew @@ -0,0 +1,183 @@ +#!/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/screen-reader/android/gradlew.bat b/screen-reader/android/gradlew.bat new file mode 100644 index 000000000..9618d8d96 --- /dev/null +++ b/screen-reader/android/gradlew.bat @@ -0,0 +1,100 @@ +@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 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/screen-reader/android/proguard-rules.pro b/screen-reader/android/proguard-rules.pro new file mode 100644 index 000000000..f1b424510 --- /dev/null +++ b/screen-reader/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/screen-reader/android/settings.gradle b/screen-reader/android/settings.gradle new file mode 100644 index 000000000..1e5b8431f --- /dev/null +++ b/screen-reader/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/screen-reader/android/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.java b/screen-reader/android/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.java new file mode 100644 index 000000000..58020e16c --- /dev/null +++ b/screen-reader/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/screen-reader/android/src/main/AndroidManifest.xml b/screen-reader/android/src/main/AndroidManifest.xml new file mode 100644 index 000000000..7df89d1e7 --- /dev/null +++ b/screen-reader/android/src/main/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/screen-reader/android/src/main/java/com/capacitorjs/plugins/screenreader/ScreenReader.java b/screen-reader/android/src/main/java/com/capacitorjs/plugins/screenreader/ScreenReader.java new file mode 100644 index 000000000..4fe9936b3 --- /dev/null +++ b/screen-reader/android/src/main/java/com/capacitorjs/plugins/screenreader/ScreenReader.java @@ -0,0 +1,58 @@ +package com.capacitorjs.plugins.screenreader; + +import android.content.Context; +import android.speech.tts.TextToSpeech; +import android.view.accessibility.AccessibilityManager; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +public class ScreenReader { + private Context context; + private AccessibilityManager accessibilityManager; + private List stateChangeListeners = new ArrayList<>(); + private TextToSpeech textToSpeech; + + public interface ScreenReaderStateChangeListener { + void onScreenReaderStateChanged(boolean enabled); + } + + ScreenReader(Context context) { + this.context = context; + this.accessibilityManager = (AccessibilityManager) this.context.getSystemService(Context.ACCESSIBILITY_SERVICE); + } + + public void addStateChangeListener(ScreenReaderStateChangeListener listener) { + stateChangeListeners.add(listener); + accessibilityManager.addTouchExplorationStateChangeListener(listener::onScreenReaderStateChanged); + } + + public void removeAllListeners() { + for (ScreenReaderStateChangeListener listener : stateChangeListeners) { + accessibilityManager.removeTouchExplorationStateChangeListener(listener::onScreenReaderStateChanged); + } + } + + public boolean isEnabled() { + return accessibilityManager.isTouchExplorationEnabled(); + } + + public void speak(String text) { + speak(text, "en"); + } + + public void speak(final String text, final String languageTag) { + if (isEnabled()) { + final Locale locale = Locale.forLanguageTag(languageTag); + + textToSpeech = + new TextToSpeech( + context, + status -> { + textToSpeech.setLanguage(locale); + textToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH, null, "capacitor-screen-reader" + System.currentTimeMillis()); + } + ); + } + } +} diff --git a/screen-reader/android/src/main/java/com/capacitorjs/plugins/screenreader/ScreenReaderPlugin.java b/screen-reader/android/src/main/java/com/capacitorjs/plugins/screenreader/ScreenReaderPlugin.java new file mode 100644 index 000000000..212047de5 --- /dev/null +++ b/screen-reader/android/src/main/java/com/capacitorjs/plugins/screenreader/ScreenReaderPlugin.java @@ -0,0 +1,47 @@ +package com.capacitorjs.plugins.screenreader; + +import com.getcapacitor.JSObject; +import com.getcapacitor.NativePlugin; +import com.getcapacitor.Plugin; +import com.getcapacitor.PluginCall; +import com.getcapacitor.PluginMethod; + +@NativePlugin(name = "ScreenReader") +public class ScreenReaderPlugin extends Plugin { + public static final String EVENT_SCREEN_READER_STATE_CHANGE = "screenReaderStateChange"; + private ScreenReader screenReader; + + @Override + public void load() { + screenReader = new ScreenReader(getContext()); + screenReader.addStateChangeListener( + enabled -> { + JSObject ret = new JSObject(); + ret.put("value", enabled); + notifyListeners(EVENT_SCREEN_READER_STATE_CHANGE, ret); + } + ); + } + + @Override + protected void handleOnDestroy() { + screenReader.removeAllListeners(); + } + + @SuppressWarnings("unused") + @PluginMethod + public void isEnabled(PluginCall call) { + JSObject ret = new JSObject(); + ret.put("value", screenReader.isEnabled()); + call.resolve(ret); + } + + @SuppressWarnings("unused") + @PluginMethod + public void speak(PluginCall call) { + String value = call.getString("value"); + String language = call.getString("language", "en"); + screenReader.speak(value, language); + call.resolve(); + } +} diff --git a/screen-reader/android/src/main/res/layout/bridge_layout_main.xml b/screen-reader/android/src/main/res/layout/bridge_layout_main.xml new file mode 100644 index 000000000..56fec1546 --- /dev/null +++ b/screen-reader/android/src/main/res/layout/bridge_layout_main.xml @@ -0,0 +1,15 @@ + + + + + + diff --git a/screen-reader/android/src/test/java/com/getcapacitor/ExampleUnitTest.java b/screen-reader/android/src/test/java/com/getcapacitor/ExampleUnitTest.java new file mode 100644 index 000000000..a0fed0cfb --- /dev/null +++ b/screen-reader/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/screen-reader/ios/Plugin.xcodeproj/project.pbxproj b/screen-reader/ios/Plugin.xcodeproj/project.pbxproj new file mode 100644 index 000000000..16fb63e4d --- /dev/null +++ b/screen-reader/ios/Plugin.xcodeproj/project.pbxproj @@ -0,0 +1,569 @@ +// !$*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 */; }; + 2F98D68224C9AAE500613A4C /* ScreenReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F98D68124C9AAE400613A4C /* ScreenReader.swift */; }; + 50ADFF92201F53D600D50D53 /* Plugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50ADFF88201F53D600D50D53 /* Plugin.framework */; }; + 50ADFF97201F53D600D50D53 /* PluginTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50ADFF96201F53D600D50D53 /* PluginTests.swift */; }; + 50ADFF99201F53D600D50D53 /* ScreenReaderPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 50ADFF8B201F53D600D50D53 /* ScreenReaderPlugin.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 50ADFFA42020D75100D50D53 /* Capacitor.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50ADFFA52020D75100D50D53 /* Capacitor.framework */; }; + 50ADFFA82020EE4F00D50D53 /* ScreenReaderPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 50ADFFA72020EE4F00D50D53 /* ScreenReaderPlugin.m */; }; + 50E1A94820377CB70090CE1A /* ScreenReaderPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E1A94720377CB70090CE1A /* ScreenReaderPlugin.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 */ + 2F98D68124C9AAE400613A4C /* ScreenReader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScreenReader.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 /* ScreenReaderPlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ScreenReaderPlugin.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 /* PluginTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PluginTests.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 /* ScreenReaderPlugin.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ScreenReaderPlugin.m; sourceTree = ""; }; + 50E1A94720377CB70090CE1A /* ScreenReaderPlugin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScreenReaderPlugin.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 = ( + 50E1A94720377CB70090CE1A /* ScreenReaderPlugin.swift */, + 2F98D68124C9AAE400613A4C /* ScreenReader.swift */, + 50ADFF8B201F53D600D50D53 /* ScreenReaderPlugin.h */, + 50ADFFA72020EE4F00D50D53 /* ScreenReaderPlugin.m */, + 50ADFF8C201F53D600D50D53 /* Info.plist */, + ); + path = Plugin; + sourceTree = ""; + }; + 50ADFF95201F53D600D50D53 /* PluginTests */ = { + isa = PBXGroup; + children = ( + 50ADFF96201F53D600D50D53 /* PluginTests.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 /* ScreenReaderPlugin.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 /* ScreenReaderPlugin.swift in Sources */, + 2F98D68224C9AAE500613A4C /* ScreenReader.swift in Sources */, + 50ADFFA82020EE4F00D50D53 /* ScreenReaderPlugin.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 50ADFF8D201F53D600D50D53 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 50ADFF97201F53D600D50D53 /* PluginTests.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/screen-reader/ios/Plugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/screen-reader/ios/Plugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/screen-reader/ios/Plugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/screen-reader/ios/Plugin.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/screen-reader/ios/Plugin.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/screen-reader/ios/Plugin.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/screen-reader/ios/Plugin.xcodeproj/xcshareddata/xcschemes/Plugin.xcscheme b/screen-reader/ios/Plugin.xcodeproj/xcshareddata/xcschemes/Plugin.xcscheme new file mode 100644 index 000000000..303f2621b --- /dev/null +++ b/screen-reader/ios/Plugin.xcodeproj/xcshareddata/xcschemes/Plugin.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/screen-reader/ios/Plugin.xcodeproj/xcshareddata/xcschemes/PluginTests.xcscheme b/screen-reader/ios/Plugin.xcodeproj/xcshareddata/xcschemes/PluginTests.xcscheme new file mode 100644 index 000000000..3d8c88d25 --- /dev/null +++ b/screen-reader/ios/Plugin.xcodeproj/xcshareddata/xcschemes/PluginTests.xcscheme @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/screen-reader/ios/Plugin.xcworkspace/contents.xcworkspacedata b/screen-reader/ios/Plugin.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..afad624ec --- /dev/null +++ b/screen-reader/ios/Plugin.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/screen-reader/ios/Plugin.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/screen-reader/ios/Plugin.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/screen-reader/ios/Plugin.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/screen-reader/ios/Plugin/Info.plist b/screen-reader/ios/Plugin/Info.plist new file mode 100644 index 000000000..1007fd9dd --- /dev/null +++ b/screen-reader/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/screen-reader/ios/Plugin/ScreenReaderPlugin.h b/screen-reader/ios/Plugin/ScreenReaderPlugin.h new file mode 100644 index 000000000..f2bd9e0bb --- /dev/null +++ b/screen-reader/ios/Plugin/ScreenReaderPlugin.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/screen-reader/ios/Plugin/ScreenReaderPlugin.m b/screen-reader/ios/Plugin/ScreenReaderPlugin.m new file mode 100644 index 000000000..86dec5bb2 --- /dev/null +++ b/screen-reader/ios/Plugin/ScreenReaderPlugin.m @@ -0,0 +1,10 @@ +#import +#import + +// Define the plugin using the CAP_PLUGIN Macro, and +// each method the plugin supports using the CAP_PLUGIN_METHOD macro. +CAP_PLUGIN(ScreenReaderPlugin, "ScreenReader", + CAP_PLUGIN_METHOD(speak, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(isEnabled, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(removeAllListeners, CAPPluginReturnNone); +) diff --git a/screen-reader/ios/Plugin/ScreenReaderPlugin.swift b/screen-reader/ios/Plugin/ScreenReaderPlugin.swift new file mode 100644 index 000000000..70e06fde4 --- /dev/null +++ b/screen-reader/ios/Plugin/ScreenReaderPlugin.swift @@ -0,0 +1,47 @@ +import Foundation +import Capacitor + +@objc(ScreenReaderPlugin) +public class ScreenReaderPlugin: CAPPlugin { + static let screenReaderStateChangeEvent = "screenReaderStateChange" + + override public func load() { + NotificationCenter.default.addObserver(self, + selector: #selector(self.onVoiceOverStateChanged(notification:)), + name: UIAccessibility.voiceOverStatusDidChangeNotification, + object: nil) + } + + deinit { + NotificationCenter.default.removeObserver(self) + } + + @objc func isEnabled(_ call: CAPPluginCall) { + let enabled = UIAccessibility.isVoiceOverRunning + + call.resolve([ + "value": enabled + ]) + } + + @objc func speak(_ call: CAPPluginCall) { + guard let value = call.getString("value") else { + call.error("No value provided") + return + } + + if UIAccessibility.isVoiceOverRunning { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { + UIAccessibility.post(notification: .announcement, argument: value) + } + } + + call.resolve() + } + + @objc private func onVoiceOverStateChanged(notification: NSNotification) { + notifyListeners(ScreenReaderPlugin.screenReaderStateChangeEvent, data: [ + "value": UIAccessibility.isVoiceOverRunning + ]) + } +} diff --git a/screen-reader/ios/PluginTests/Info.plist b/screen-reader/ios/PluginTests/Info.plist new file mode 100644 index 000000000..6c40a6cd0 --- /dev/null +++ b/screen-reader/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/screen-reader/ios/PluginTests/PluginTests.swift b/screen-reader/ios/PluginTests/PluginTests.swift new file mode 100644 index 000000000..84183f9bc --- /dev/null +++ b/screen-reader/ios/PluginTests/PluginTests.swift @@ -0,0 +1,16 @@ +import XCTest +@testable import Plugin + +class ScreenReaderTests: 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/screen-reader/ios/Podfile b/screen-reader/ios/Podfile new file mode 100644 index 000000000..350751435 --- /dev/null +++ b/screen-reader/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/screen-reader/ios/Podfile.lock b/screen-reader/ios/Podfile.lock new file mode 100644 index 000000000..d4ad9c250 --- /dev/null +++ b/screen-reader/ios/Podfile.lock @@ -0,0 +1,22 @@ +PODS: + - Capacitor (3.0.0-alpha.0): + - CapacitorCordova + - CapacitorCordova (3.0.0-alpha.0) + +DEPENDENCIES: + - "Capacitor (from `../node_modules/@capacitor/ios`)" + - "CapacitorCordova (from `../node_modules/@capacitor/ios`)" + +EXTERNAL SOURCES: + Capacitor: + :path: "../node_modules/@capacitor/ios" + CapacitorCordova: + :path: "../node_modules/@capacitor/ios" + +SPEC CHECKSUMS: + Capacitor: 7108ccc9b0dd2b48c0468666e0d9efd1d42998e5 + CapacitorCordova: d5c0f46dfad616eed2dcf244ba8e3e830d584f06 + +PODFILE CHECKSUM: e66d6fa04b0daaf06d8498d39637adf77139c716 + +COCOAPODS: 1.9.3 diff --git a/screen-reader/package-lock.json b/screen-reader/package-lock.json new file mode 100644 index 000000000..139e6334f --- /dev/null +++ b/screen-reader/package-lock.json @@ -0,0 +1,808 @@ +{ + "name": "@capacitor/screen-reader", + "version": "0.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@capacitor/android": { + "version": "3.0.0-alpha.0", + "resolved": "https://registry.npmjs.org/@capacitor/android/-/android-3.0.0-alpha.0.tgz", + "integrity": "sha512-z0UPbOMXDJUfSjz7cTKxfwPDhh7z3TlHrdODW4wEbzZtkYXD5EJSzVFBZQllj0i8J0+4D7gznQb2E9YNHv6XMw==", + "dev": true + }, + "@capacitor/core": { + "version": "3.0.0-alpha.0", + "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-3.0.0-alpha.0.tgz", + "integrity": "sha512-sKzdeFTWnqetXySmt4EM8kb6WY4TSqdz35FsRmYWrdlBrS4+H7rkZq0u7CwhwA3aitO+P3+WrcqxCd/iy6q6+g==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "@capacitor/ios": { + "version": "3.0.0-alpha.0", + "resolved": "https://registry.npmjs.org/@capacitor/ios/-/ios-3.0.0-alpha.0.tgz", + "integrity": "sha512-Iz2vLEL6Lhgnm5svsy12qaDgOObY+tOx96T0XgGymMOoEG+xkngVAc2OfmfM6gjmmSFW9GCeEOjP2ueqbx94Xg==", + "dev": true + }, + "@ionic/prettier-config": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@ionic/prettier-config/-/prettier-config-1.0.0.tgz", + "integrity": "sha512-5GDPYT05fmVypV9nfMOIPaaQz/V+cdtSKLqGCJmZeDx4yJ4RYlY+I/HS8N9vOSEH8w1/ypUNes6wI5/+acqtmQ==", + "dev": true + }, + "@ionic/swiftlint-config": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@ionic/swiftlint-config/-/swiftlint-config-1.1.1.tgz", + "integrity": "sha512-wxkuUjmHTy0keqIBqPGWj+Qb0qOdWhE72Te1rJXspvR25Az/7cXTWDydPf/DO4DW1g9DZVy+Hgz+F1QQ7F7/2Q==", + "dev": true + }, + "@ionic/utils-array": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@ionic/utils-array/-/utils-array-2.1.3.tgz", + "integrity": "sha512-IV7oK7kj6UZEkZ5lbS78gNSUSTqZtLOEKu9G+MqBpRTX+YKKnmsAxQuvZrnsy/pHmzJ7aKlj1V0gNAFO6w/NOA==", + "dev": true, + "requires": { + "debug": "^4.0.0", + "tslib": "1.11.2" + }, + "dependencies": { + "tslib": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.2.tgz", + "integrity": "sha512-tTSkux6IGPnUGUd1XAZHcpu85MOkIl5zX49pO+jfsie3eP0B6pyhOlLXm3cAC6T7s+euSDDUUV+Acop5WmtkVg==", + "dev": true + } + } + }, + "@ionic/utils-fs": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@ionic/utils-fs/-/utils-fs-3.1.3.tgz", + "integrity": "sha512-xMZhlB1XgZQchvKZFQt6NcKgLsCdSTt3lmU0Gl0HIWdGHjwI5QSyLCYPTvfa8Wm4vCn7XYiMy05bWxWtY0+FxQ==", + "dev": true, + "requires": { + "debug": "^4.0.0", + "fs-extra": "^9.0.0", + "through2": "^3.0.0", + "tslib": "1.11.2" + }, + "dependencies": { + "tslib": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.2.tgz", + "integrity": "sha512-tTSkux6IGPnUGUd1XAZHcpu85MOkIl5zX49pO+jfsie3eP0B6pyhOlLXm3cAC6T7s+euSDDUUV+Acop5WmtkVg==", + "dev": true + } + } + }, + "@ionic/utils-object": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@ionic/utils-object/-/utils-object-2.1.3.tgz", + "integrity": "sha512-iJQjC2RBWACCgwafsKKJN+G2hxTxRhVT0gtdGK29jH8ZZMIJGEEIA2hlpPsL9OR/yRMwByATyO1usC2jEM8qDQ==", + "dev": true, + "requires": { + "debug": "^4.0.0", + "tslib": "1.11.2" + }, + "dependencies": { + "tslib": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.2.tgz", + "integrity": "sha512-tTSkux6IGPnUGUd1XAZHcpu85MOkIl5zX49pO+jfsie3eP0B6pyhOlLXm3cAC6T7s+euSDDUUV+Acop5WmtkVg==", + "dev": true + } + } + }, + "@ionic/utils-process": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@ionic/utils-process/-/utils-process-2.1.3.tgz", + "integrity": "sha512-FMW9kc+waKv01/dNuMOP3NrJLyhMv8Ij73B2KVlZyI6UiFMjghvEApttQVi2ewKw6z1ipbkSFRaICxPIvGwABw==", + "dev": true, + "requires": { + "@ionic/utils-object": "2.1.3", + "@ionic/utils-terminal": "2.1.3", + "debug": "^4.0.0", + "lodash": "^4.17.5", + "tree-kill": "^1.2.2", + "tslib": "1.11.2" + }, + "dependencies": { + "tslib": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.2.tgz", + "integrity": "sha512-tTSkux6IGPnUGUd1XAZHcpu85MOkIl5zX49pO+jfsie3eP0B6pyhOlLXm3cAC6T7s+euSDDUUV+Acop5WmtkVg==", + "dev": true + } + } + }, + "@ionic/utils-stream": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@ionic/utils-stream/-/utils-stream-3.1.3.tgz", + "integrity": "sha512-vhYVJMT/5HNhTe3ypPkgll4e4O6fRXqAEXntJzBy3COWllXkERB/tWn2x8TSLcosmzN8f8FONCjznnq6Uq54LQ==", + "dev": true, + "requires": { + "debug": "^4.0.0", + "tslib": "1.11.2" + }, + "dependencies": { + "tslib": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.2.tgz", + "integrity": "sha512-tTSkux6IGPnUGUd1XAZHcpu85MOkIl5zX49pO+jfsie3eP0B6pyhOlLXm3cAC6T7s+euSDDUUV+Acop5WmtkVg==", + "dev": true + } + } + }, + "@ionic/utils-subprocess": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@ionic/utils-subprocess/-/utils-subprocess-2.1.3.tgz", + "integrity": "sha512-jTEz97eFxNLj+Cw8CQvfkNThEBT98wrbPfE2C3MO9E+gw+h7gX2/KWoUgg9U0lAyiOUggCVir/44SLbevhtPBw==", + "dev": true, + "requires": { + "@ionic/utils-array": "2.1.3", + "@ionic/utils-fs": "3.1.3", + "@ionic/utils-process": "2.1.3", + "@ionic/utils-stream": "3.1.3", + "@ionic/utils-terminal": "2.1.3", + "cross-spawn": "^7.0.0", + "debug": "^4.0.0", + "tslib": "1.11.2" + }, + "dependencies": { + "tslib": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.2.tgz", + "integrity": "sha512-tTSkux6IGPnUGUd1XAZHcpu85MOkIl5zX49pO+jfsie3eP0B6pyhOlLXm3cAC6T7s+euSDDUUV+Acop5WmtkVg==", + "dev": true + } + } + }, + "@ionic/utils-terminal": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@ionic/utils-terminal/-/utils-terminal-2.1.3.tgz", + "integrity": "sha512-By0tp8pBcghIqTMKnRQw55cnUhDGrE+UTfdY81iDiXaMxRy8vwJjXgq9jiCKLF/qH1elQpIzDo2ePdu+MrNMFg==", + "dev": true, + "requires": { + "debug": "^4.0.0", + "tslib": "1.11.2" + }, + "dependencies": { + "tslib": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.2.tgz", + "integrity": "sha512-tTSkux6IGPnUGUd1XAZHcpu85MOkIl5zX49pO+jfsie3eP0B6pyhOlLXm3cAC6T7s+euSDDUUV+Acop5WmtkVg==", + "dev": true + } + } + }, + "@rollup/plugin-node-resolve": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-8.4.0.tgz", + "integrity": "sha512-LFqKdRLn0ShtQyf6SBYO69bGE1upV6wUhBX0vFOUnLAyzx5cwp8svA0eHUnu8+YU57XOkrMtfG63QOpQx25pHQ==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "builtin-modules": "^3.1.0", + "deep-freeze": "^0.0.1", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.17.0" + } + }, + "@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, + "requires": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + } + }, + "@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + }, + "@types/node": { + "version": "14.0.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.27.tgz", + "integrity": "sha512-kVrqXhbclHNHGu9ztnAwSncIgJv/FaxmzXJvGXNdcCpV1b8u1/Mi6z6m0vwy0LzKeXFTPLH0NzwmoJ3fNCIq0g==", + "dev": true + }, + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, + "@types/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "builtin-modules": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz", + "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==", + "dev": true + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chevrotain": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-6.5.0.tgz", + "integrity": "sha512-BwqQ/AgmKJ8jcMEjaSnfMybnKMgGTrtDKowfTP3pX4jwVy0kNjRsT/AP6h+wC3+3NC+X8X15VWBnTCQlX+wQFg==", + "dev": true, + "requires": { + "regexp-to-ast": "0.4.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "dev": true, + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-freeze": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/deep-freeze/-/deep-freeze-0.0.1.tgz", + "integrity": "sha1-OgsABd4YZygZ39OM0x+RF5yJPoQ=", + "dev": true + }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true + }, + "fs-extra": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz", + "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^1.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "import-fresh": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "java-parser": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/java-parser/-/java-parser-0.8.0.tgz", + "integrity": "sha512-8MOu9EDjWlAcBnxjVI8jblcOX/zJt9XVLaMLrXYvmJYk3gvRqTUKsEp/PxaooJQc6wh+nPEyqEbhCy3BWIgi0g==", + "dev": true, + "requires": { + "chevrotain": "6.5.0", + "lodash": "4.17.15" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "jsonfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz", + "integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^1.0.0" + } + }, + "lines-and-columns": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", + "dev": true + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.1.tgz", + "integrity": "sha512-ztoZ4/DYeXQq4E21v169sC8qWINGpcosGv9XhTDvg9/hWvx/zrFkc9BiWxR58OJLHGk28j5BL0SDLeV2WmFZlQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1", + "lines-and-columns": "^1.1.6" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true + }, + "prettier": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.0.5.tgz", + "integrity": "sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==", + "dev": true + }, + "prettier-plugin-java": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/prettier-plugin-java/-/prettier-plugin-java-0.8.0.tgz", + "integrity": "sha512-+4qdhUfFQIj4bLGSDrAGmUZKXQRjJYpQFbmRh04atEZe7QEZUF6NHVyRjJ73Cgwhc5NaiyIpFhtcXgLf9J9V6A==", + "dev": true, + "requires": { + "java-parser": "^0.8.0", + "lodash": "4.17.15", + "prettier": "2.0.4" + }, + "dependencies": { + "prettier": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.0.4.tgz", + "integrity": "sha512-SVJIQ51spzFDvh4fIbCLvciiDMCrRhlN3mbZvv/+ycjvmF5E73bKdGfU8QDLNmjYJf+lsGnDBC4UUnvTe5OO0w==", + "dev": true + } + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "regexp-to-ast": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/regexp-to-ast/-/regexp-to-ast-0.4.0.tgz", + "integrity": "sha512-4qf/7IsIKfSNHQXSwial1IFmfM1Cc/whNBQqRwe0V2stPe7KmN1U0tWQiIx6JiirgSrisjE0eECdNf7Tav1Ntw==", + "dev": true + }, + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "rollup": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.23.0.tgz", + "integrity": "sha512-vLNmZFUGVwrnqNAJ/BvuLk1MtWzu4IuoqsH9UWK5AIdO3rt8/CSiJNvPvCIvfzrbNsqKbNzPAG1V2O4eTe2XZg==", + "dev": true, + "requires": { + "fsevents": "~2.1.2" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "swiftlint": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/swiftlint/-/swiftlint-1.0.1.tgz", + "integrity": "sha512-HV/fCJTpwgCeoMw5W21J5PnhXSAVg2dtgTPrAbHqFZR1dDHEdEiM7tObw/w+CEGW/68xwWWTgKfyyvyY/6uUxA==", + "dev": true, + "requires": { + "@ionic/utils-fs": "^3.1.3", + "@ionic/utils-subprocess": "^2.1.3", + "cosmiconfig": "^6.0.0" + } + }, + "through2": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", + "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", + "dev": true, + "requires": { + "inherits": "^2.0.4", + "readable-stream": "2 || 3" + } + }, + "tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true + }, + "tslib": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", + "dev": true + }, + "typescript": { + "version": "3.9.7", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz", + "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==", + "dev": true + }, + "universalify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", + "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "yaml": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz", + "integrity": "sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==", + "dev": true + } + } +} diff --git a/screen-reader/package.json b/screen-reader/package.json new file mode 100644 index 000000000..816939cff --- /dev/null +++ b/screen-reader/package.json @@ -0,0 +1,62 @@ +{ + "name": "@capacitor/screen-reader", + "version": "0.0.1", + "description": "Screen Reader APIs", + "main": "dist/plugin.js", + "module": "dist/esm/index.js", + "types": "dist/esm/index.d.ts", + "scripts": { + "lint": "npm run prettier -- --check && npm run swiftlint -- lint", + "fmt": "npm run prettier -- --write && npm run swiftlint -- autocorrect --format", + "prettier": "prettier \"**/*.{css,html,ts,js,java}\"", + "swiftlint": "node-swiftlint", + "build": "npm run clean && tsc && rollup -c rollup.config.js", + "clean": "rimraf ./dist", + "watch": "tsc --watch", + "prepublishOnly": "npm run build" + }, + "author": "Ionic ", + "license": "MIT", + "devDependencies": { + "@capacitor/android": "next", + "@capacitor/core": "next", + "@capacitor/ios": "next", + "@ionic/prettier-config": "^1.0.0", + "@ionic/swiftlint-config": "^1.0.0", + "@rollup/plugin-node-resolve": "^8.1.0", + "prettier": "^2.0.5", + "prettier-plugin-java": "^0.8.0", + "rimraf": "^3.0.0", + "rollup": "^2.21.0", + "swiftlint": "^1.0.1", + "typescript": "~3.9.7" + }, + "peerDependencies": { + "@capacitor/core": "^3.0.0-alpha.0" + }, + "files": [ + "dist/", + "ios/", + "android/", + "CapacitorScreenReader.podspec" + ], + "keywords": [ + "capacitor", + "plugin", + "native" + ], + "capacitor": { + "ios": { + "src": "ios" + }, + "android": { + "src": "android" + } + }, + "prettier": "@ionic/prettier-config", + "swiftlint": "@ionic/swiftlint-config", + "repository": { + "type": "git", + "url": "https://github.com/ionic-team/capacitor-plugins" + } +} diff --git a/screen-reader/rollup.config.js b/screen-reader/rollup.config.js new file mode 100644 index 000000000..b89cb0452 --- /dev/null +++ b/screen-reader/rollup.config.js @@ -0,0 +1,21 @@ +import nodeResolve from '@rollup/plugin-node-resolve'; + +export default { + input: 'dist/esm/index.js', + output: { + file: 'dist/plugin.js', + format: 'iife', + name: 'capacitorScreenReader', + globals: { + '@capacitor/core': 'capacitorExports', + }, + sourcemap: true, + }, + plugins: [ + nodeResolve({ + // allowlist of dependencies to bundle in + // @see https://github.com/rollup/plugins/tree/HEAD/packages/node-resolve#resolveonly + resolveOnly: ['lodash'], + }), + ], +}; diff --git a/screen-reader/src/definitions.ts b/screen-reader/src/definitions.ts new file mode 100644 index 000000000..ff1287b29 --- /dev/null +++ b/screen-reader/src/definitions.ts @@ -0,0 +1,84 @@ +import { PluginListenerHandle } from '@capacitor/core'; + +declare module '@capacitor/core' { + interface PluginRegistry { + ScreenReader: ScreenReaderPlugin; + } +} + +export interface ScreenReaderSpeakOptions { + /** + * The text to speak. + * + * @since 1.0.0 + */ + value: string; + + /** + * The language to speak the text in, as its [ISO 639-1 + * Code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g.: "en"). + * + * This option is only supported on Android. + * + * @since 1.0.0 + */ + language?: string; +} + +export type ScreenReaderStateChangeListener = (state: { + /** + * Whether a Screen Reader is currently active. + * + * @since 1.0.0 + */ + value: boolean; +}) => any; + +export interface ScreenReaderPlugin { + /** + * Whether a Screen Reader is currently active. + * + * This method is not supported on web (it is not possible to detect Screen + * Readers). + * + * @since 1.0.0 + */ + isEnabled(): Promise<{ value: boolean }>; + + /** + * Text-to-Speech functionality. + * + * This function will only work if a Screen Reader is currently active. + * + * On web, browsers must support the [SpeechSynthesis + * API](https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesis), or + * this method will throw an error. + * + * For more text-to-speech capabilities, please see the [Capacitor Community + * Text-to-Speech + * plugin](https://github.com/capacitor-community/text-to-speech). + * + * @since 1.0.0 + */ + speak(options: ScreenReaderSpeakOptions): Promise; + + /** + * Add a listener + * + * This method is not supported on web (it is not possible to detect Screen + * Readers). + * + * @since 1.0.0 + */ + addListener( + eventName: 'screenReaderStateChange', + listener: ScreenReaderStateChangeListener, + ): PluginListenerHandle; + + /** + * Remove all the listeners that are attached to this plugin. + * + * @since 1.0.0 + */ + removeAllListeners(): void; +} diff --git a/screen-reader/src/index.ts b/screen-reader/src/index.ts new file mode 100644 index 000000000..a3f7c56a8 --- /dev/null +++ b/screen-reader/src/index.ts @@ -0,0 +1,21 @@ +import { + Plugins, + PluginImplementations, + registerPlugin, +} from '@capacitor/core'; + +import { ScreenReaderPlugin } from './definitions'; +import { ScreenReaderWeb } from './web'; + +const implementations: PluginImplementations = { + android: Plugins.ScreenReader, + ios: Plugins.ScreenReader, + web: new ScreenReaderWeb(), +}; + +const ScreenReader = registerPlugin( + 'ScreenReader', + implementations, +).getImplementation(); + +export { ScreenReader }; diff --git a/screen-reader/src/web.ts b/screen-reader/src/web.ts new file mode 100644 index 000000000..c7b33ee05 --- /dev/null +++ b/screen-reader/src/web.ts @@ -0,0 +1,30 @@ +import { UnsupportedBrowserException, WebPlugin } from '@capacitor/core'; +import { ScreenReaderPlugin, ScreenReaderSpeakOptions } from './definitions'; + +export class ScreenReaderWeb extends WebPlugin implements ScreenReaderPlugin { + constructor() { + super({ name: 'ScreenReader' }); + } + + async isEnabled(): Promise { + throw new UnsupportedBrowserException( + 'This feature is not available in the browser.', + ); + } + + async speak(options: ScreenReaderSpeakOptions): Promise { + if (!('speechSynthesis' in window)) { + throw new UnsupportedBrowserException( + 'Browser does not support the SpeechSynthesis API', + ); + } + + const utterance = new SpeechSynthesisUtterance(options.value); + + if (options.language) { + utterance.lang = options.language; + } + + speechSynthesis.speak(utterance); + } +} diff --git a/screen-reader/tsconfig.json b/screen-reader/tsconfig.json new file mode 100644 index 000000000..9f458f6e8 --- /dev/null +++ b/screen-reader/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "allowUnreachableCode": false, + "declaration": true, + "esModuleInterop": true, + "lib": [ + "dom", + "es2015" + ], + "module": "es2015", + "moduleResolution": "node", + "noFallthroughCasesInSwitch": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "outDir": "dist/esm", + "pretty": true, + "sourceMap": true, + "strict": true, + "target": "es2015" + }, + "files": [ + "src/index.ts" + ] +}