├── .npmrc
├── src
├── app
│ ├── app.component.scss
│ ├── modules
│ │ ├── home
│ │ │ ├── home.page.scss
│ │ │ ├── home.module.ts
│ │ │ ├── home-routing.module.ts
│ │ │ ├── home.page.html
│ │ │ ├── home.page.spec.ts
│ │ │ └── home.page.ts
│ │ ├── translation
│ │ │ ├── translation.page.scss
│ │ │ ├── translation.module.ts
│ │ │ ├── translation-routing.module.ts
│ │ │ ├── translation.page.spec.ts
│ │ │ ├── translation.page.ts
│ │ │ └── translation.page.html
│ │ ├── barcode-scanning
│ │ │ ├── barcode-scanning.page.scss
│ │ │ ├── barcode-scanning-routing.module.ts
│ │ │ ├── barcode-scanning.module.ts
│ │ │ ├── barcode-scanning.page.spec.ts
│ │ │ ├── barcode-scanning.page.ts
│ │ │ ├── barcode-scanning.page.html
│ │ │ └── barcode-scanning-modal.component.ts
│ │ ├── document-scanner
│ │ │ ├── document-scanner.page.scss
│ │ │ ├── document-scanner.module.ts
│ │ │ ├── document-scanner-routing.module.ts
│ │ │ ├── document-scanner.page.spec.ts
│ │ │ ├── document-scanner.page.ts
│ │ │ └── document-scanner.page.html
│ │ ├── face-detection
│ │ │ ├── face-detection.page.scss
│ │ │ ├── face-detection.module.ts
│ │ │ ├── face-detection-routing.module.ts
│ │ │ ├── face-detection.page.spec.ts
│ │ │ └── face-detection.page.ts
│ │ ├── selfie-segmentation
│ │ │ ├── selfie-segmentation.module.ts
│ │ │ ├── selfie-segmentation-routing.module.ts
│ │ │ ├── selfie-segmentation.page.spec.ts
│ │ │ ├── selfie-segmentation.page.scss
│ │ │ ├── selfie-segmentation.page.ts
│ │ │ └── selfie-segmentation.page.html
│ │ ├── subject-segmentation
│ │ │ ├── subject-segmentation.module.ts
│ │ │ ├── subject-segmentation-routing.module.ts
│ │ │ ├── subject-segmentation.page.spec.ts
│ │ │ ├── subject-segmentation.page.scss
│ │ │ ├── subject-segmentation.page.ts
│ │ │ └── subject-segmentation.page.html
│ │ └── face-mesh-detection
│ │ │ ├── face-mesh-detection-routing.module.ts
│ │ │ ├── face-mesh-detection.module.ts
│ │ │ ├── face-mesh-detection.page.spec.ts
│ │ │ ├── face-mesh-detection.page.scss
│ │ │ ├── face-mesh-detection.page.ts
│ │ │ ├── face-mesh-detection.pipe.ts
│ │ │ └── face-mesh-detection.page.html
│ ├── shared
│ │ ├── index.ts
│ │ └── shared.module.ts
│ ├── core
│ │ ├── index.ts
│ │ ├── services
│ │ │ ├── index.ts
│ │ │ ├── global-error-handler
│ │ │ │ ├── global-error-handler.service.spec.ts
│ │ │ │ └── global-error-handler.service.ts
│ │ │ └── dialog
│ │ │ │ ├── dialog.service.spec.ts
│ │ │ │ └── dialog.service.ts
│ │ └── core.module.ts
│ ├── app.component.html
│ ├── app.component.ts
│ ├── app.component.spec.ts
│ ├── app.module.ts
│ └── app-routing.module.ts
├── tests
│ ├── mocks
│ │ ├── index.ts
│ │ └── angular-mocks.ts
│ ├── spies
│ │ ├── index.ts
│ │ └── ionic-spies.ts
│ ├── modules
│ │ ├── index.ts
│ │ └── shared-testing.module.ts
│ └── test-setup.ts
├── environments
│ ├── environment.prod.ts
│ └── environment.ts
├── assets
│ ├── icon
│ │ └── favicon.png
│ └── shapes.svg
├── zone-flags.ts
├── main.ts
├── test.ts
├── index.html
├── global.scss
├── polyfills.ts
└── theme
│ └── variables.scss
├── android
├── app
│ ├── .gitignore
│ ├── src
│ │ ├── main
│ │ │ ├── res
│ │ │ │ ├── drawable
│ │ │ │ │ ├── splash.png
│ │ │ │ │ └── ic_launcher_background.xml
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ ├── push_icon.png
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ ├── ic_launcher_round.png
│ │ │ │ │ └── ic_launcher_foreground.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ ├── push_icon.png
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ ├── ic_launcher_round.png
│ │ │ │ │ └── ic_launcher_foreground.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ ├── push_icon.png
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ ├── ic_launcher_round.png
│ │ │ │ │ └── ic_launcher_foreground.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ ├── push_icon.png
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ ├── ic_launcher_round.png
│ │ │ │ │ └── ic_launcher_foreground.png
│ │ │ │ ├── drawable-land-hdpi
│ │ │ │ │ └── splash.png
│ │ │ │ ├── drawable-land-mdpi
│ │ │ │ │ └── splash.png
│ │ │ │ ├── drawable-land-xhdpi
│ │ │ │ │ └── splash.png
│ │ │ │ ├── drawable-port-hdpi
│ │ │ │ │ └── splash.png
│ │ │ │ ├── drawable-port-mdpi
│ │ │ │ │ └── splash.png
│ │ │ │ ├── drawable-port-xhdpi
│ │ │ │ │ └── splash.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ ├── push_icon.png
│ │ │ │ │ ├── ic_launcher_round.png
│ │ │ │ │ └── ic_launcher_foreground.png
│ │ │ │ ├── drawable-land-xxhdpi
│ │ │ │ │ └── splash.png
│ │ │ │ ├── drawable-land-xxxhdpi
│ │ │ │ │ └── splash.png
│ │ │ │ ├── drawable-port-xxhdpi
│ │ │ │ │ └── splash.png
│ │ │ │ ├── drawable-port-xxxhdpi
│ │ │ │ │ └── splash.png
│ │ │ │ ├── values
│ │ │ │ │ ├── ic_launcher_background.xml
│ │ │ │ │ ├── strings.xml
│ │ │ │ │ └── styles.xml
│ │ │ │ ├── xml
│ │ │ │ │ ├── config.xml
│ │ │ │ │ └── file_paths.xml
│ │ │ │ ├── mipmap-anydpi-v26
│ │ │ │ │ ├── ic_launcher.xml
│ │ │ │ │ └── ic_launcher_round.xml
│ │ │ │ ├── layout
│ │ │ │ │ └── activity_main.xml
│ │ │ │ └── drawable-v24
│ │ │ │ │ └── ic_launcher_foreground.xml
│ │ │ ├── java
│ │ │ │ └── dev
│ │ │ │ │ └── robingenz
│ │ │ │ │ └── capacitorjs
│ │ │ │ │ └── demo
│ │ │ │ │ └── mlkitplugins
│ │ │ │ │ └── MainActivity.java
│ │ │ ├── assets
│ │ │ │ ├── capacitor.config.json
│ │ │ │ └── capacitor.plugins.json
│ │ │ └── AndroidManifest.xml
│ │ ├── test
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── getcapacitor
│ │ │ │ └── myapp
│ │ │ │ └── ExampleUnitTest.java
│ │ └── androidTest
│ │ │ └── java
│ │ │ └── com
│ │ │ └── getcapacitor
│ │ │ └── myapp
│ │ │ └── ExampleInstrumentedTest.java
│ ├── proguard-rules.pro
│ ├── capacitor.build.gradle
│ └── build.gradle
├── .idea
│ ├── .gitignore
│ ├── compiler.xml
│ ├── deploymentTargetSelector.xml
│ ├── misc.xml
│ ├── deploymentTargetDropDown.xml
│ ├── runConfigurations.xml
│ └── jarRepositories.xml
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── settings.gradle
├── variables.gradle
├── build.gradle
├── gradle.properties
├── .gitignore
├── capacitor.settings.gradle
└── gradlew.bat
├── ios
├── App
│ ├── App
│ │ ├── Assets.xcassets
│ │ │ ├── Contents.json
│ │ │ ├── AppIcon.appiconset
│ │ │ │ ├── AppIcon-512@2x.png
│ │ │ │ └── Contents.json
│ │ │ └── Splash.imageset
│ │ │ │ ├── splash-2732x2732.png
│ │ │ │ ├── splash-2732x2732-1.png
│ │ │ │ ├── splash-2732x2732-2.png
│ │ │ │ └── Contents.json
│ │ ├── config.xml
│ │ ├── App.entitlements
│ │ ├── capacitor.config.json
│ │ ├── Base.lproj
│ │ │ ├── Main.storyboard
│ │ │ └── LaunchScreen.storyboard
│ │ ├── Info.plist
│ │ └── AppDelegate.swift
│ ├── App.xcodeproj
│ │ └── project.xcworkspace
│ │ │ └── contents.xcworkspacedata
│ ├── App.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ ├── Podfile
│ └── Podfile.lock
└── .gitignore
├── ionic.config.json
├── capacitor.config.json
├── tsconfig.app.json
├── .editorconfig
├── tsconfig.spec.json
├── .github
├── workflows
│ ├── lock.yml
│ ├── needs-reply.yml
│ ├── needs-triage.yml
│ ├── needs-reply-remove.yml
│ └── ci.yml
└── ISSUE_TEMPLATE
│ ├── feature_request.md
│ └── bug_report.md
├── .gitignore
├── tsconfig.json
├── LICENSE
├── .eslintrc.json
├── karma.conf.js
├── README.md
├── package.json
└── angular.json
/.npmrc:
--------------------------------------------------------------------------------
1 | save-exact=true
2 |
--------------------------------------------------------------------------------
/src/app/app.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/modules/home/home.page.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/modules/translation/translation.page.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/android/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build/*
2 | !/build/.npmkeep
3 |
--------------------------------------------------------------------------------
/src/app/modules/barcode-scanning/barcode-scanning.page.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/modules/document-scanner/document-scanner.page.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/shared/index.ts:
--------------------------------------------------------------------------------
1 | export * from './shared.module';
2 |
--------------------------------------------------------------------------------
/src/tests/mocks/index.ts:
--------------------------------------------------------------------------------
1 | export * from './angular-mocks';
2 |
--------------------------------------------------------------------------------
/src/tests/spies/index.ts:
--------------------------------------------------------------------------------
1 | export * from './ionic-spies';
2 |
--------------------------------------------------------------------------------
/src/tests/modules/index.ts:
--------------------------------------------------------------------------------
1 | export * from './shared-testing.module';
2 |
--------------------------------------------------------------------------------
/android/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/src/app/core/index.ts:
--------------------------------------------------------------------------------
1 | export * from './core.module';
2 | export * from './services';
3 |
--------------------------------------------------------------------------------
/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true,
3 | };
4 |
--------------------------------------------------------------------------------
/ios/App/App/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/src/assets/icon/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/src/assets/icon/favicon.png
--------------------------------------------------------------------------------
/src/app/core/services/index.ts:
--------------------------------------------------------------------------------
1 | export * from './dialog/dialog.service';
2 | export * from './global-error-handler/global-error-handler.service';
3 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/ionic.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "capacitor-mlkit-plugin-demo",
3 | "integrations": {
4 | "capacitor": {}
5 | },
6 | "type": "angular"
7 | }
8 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/android/app/src/main/res/drawable/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/push_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/android/app/src/main/res/mipmap-hdpi/push_icon.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/push_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/android/app/src/main/res/mipmap-mdpi/push_icon.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/push_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/android/app/src/main/res/mipmap-xhdpi/push_icon.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/push_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/android/app/src/main/res/mipmap-xxhdpi/push_icon.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-land-hdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/android/app/src/main/res/drawable-land-hdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-land-mdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/android/app/src/main/res/drawable-land-mdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-land-xhdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/android/app/src/main/res/drawable-land-xhdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-port-hdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/android/app/src/main/res/drawable-port-hdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-port-mdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/android/app/src/main/res/drawable-port-mdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-port-xhdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/android/app/src/main/res/drawable-port-xhdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/push_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/android/app/src/main/res/mipmap-xxxhdpi/push_icon.png
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | App/build
2 | App/Pods
3 | App/App/public
4 | DerivedData
5 | xcuserdata
6 |
7 | # Cordova plugins for Capacitor
8 | capacitor-cordova-ios-plugins
9 |
10 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-land-xxhdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/android/app/src/main/res/drawable-land-xxhdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-land-xxxhdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/android/app/src/main/res/drawable-land-xxxhdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-port-xxhdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/android/app/src/main/res/drawable-port-xxhdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-port-xxxhdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/android/app/src/main/res/drawable-port-xxxhdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png
--------------------------------------------------------------------------------
/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png
--------------------------------------------------------------------------------
/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robingenz/capacitor-mlkit-plugin-demo/HEAD/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png
--------------------------------------------------------------------------------
/src/app/modules/face-detection/face-detection.page.scss:
--------------------------------------------------------------------------------
1 | ion-list ion-list-header {
2 | height: 0;
3 | }
4 | ion-list ion-card {
5 | margin-left: 0;
6 | margin-top: 0;
7 | margin-right: 6px;
8 | }
9 |
--------------------------------------------------------------------------------
/android/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/ios/App/App/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/ios/App/App/App.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/ios/App/App.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/zone-flags.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Prevents Angular change detection from
3 | * running with certain Web Component callbacks
4 | */
5 | // eslint-disable-next-line no-underscore-dangle
6 | (window as any).__Zone_disable_customElements = true;
7 |
--------------------------------------------------------------------------------
/android/app/src/main/res/xml/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 | include ':capacitor-cordova-android-plugins'
3 | project(':capacitor-cordova-android-plugins').projectDir = new File('./capacitor-cordova-android-plugins/')
4 |
5 | apply from: 'capacitor.settings.gradle'
--------------------------------------------------------------------------------
/android/app/src/main/java/dev/robingenz/capacitorjs/demo/mlkitplugins/MainActivity.java:
--------------------------------------------------------------------------------
1 | package dev.robingenz.capacitorjs.demo.mlkitplugins;
2 |
3 | import com.getcapacitor.BridgeActivity;
4 |
5 | public class MainActivity extends BridgeActivity {}
6 |
--------------------------------------------------------------------------------
/src/tests/spies/ionic-spies.ts:
--------------------------------------------------------------------------------
1 | import { Platform } from '@ionic/angular';
2 |
3 | export const createPlatformSpy = (): jasmine.SpyObj =>
4 | jasmine.createSpyObj('Platform', {
5 | is: false,
6 | ready: Promise.resolve(),
7 | });
8 |
--------------------------------------------------------------------------------
/android/app/src/main/res/xml/file_paths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/capacitor.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "appId": "dev.robingenz.capacitorjs.demo.mlkitplugins",
3 | "appName": "capacitor-mlkit-plugin-demo",
4 | "bundledWebRuntime": false,
5 | "npmClient": "npm",
6 | "webDir": "www",
7 | "plugins": {},
8 | "cordova": {}
9 | }
10 |
--------------------------------------------------------------------------------
/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-root',
5 | templateUrl: 'app.component.html',
6 | styleUrls: ['app.component.scss'],
7 | })
8 | export class AppComponent {
9 | constructor() {}
10 | }
11 |
--------------------------------------------------------------------------------
/android/app/src/main/assets/capacitor.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "appId": "dev.robingenz.capacitorjs.demo.mlkitplugins",
3 | "appName": "capacitor-mlkit-plugin-demo",
4 | "bundledWebRuntime": false,
5 | "npmClient": "npm",
6 | "webDir": "www",
7 | "plugins": {},
8 | "cordova": {}
9 | }
10 |
--------------------------------------------------------------------------------
/ios/App/App.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-all.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/ios/App/App.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/app",
6 | "types": ["@types/emscripten"]
7 | },
8 | "files": ["src/main.ts", "src/polyfills.ts"],
9 | "include": ["src/**/*.d.ts"]
10 | }
11 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.ts]
12 | quote_type = single
13 |
14 | [*.md]
15 | max_line_length = off
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "AppIcon-512@2x.png",
5 | "idiom" : "universal",
6 | "platform" : "ios",
7 | "size" : "1024x1024"
8 | }
9 | ],
10 | "info" : {
11 | "author" : "xcode",
12 | "version" : 1
13 | }
14 | }
--------------------------------------------------------------------------------
/android/.idea/deploymentTargetSelector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/app/modules/home/home.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { SharedModule } from '@app/shared';
3 | import { HomePageRoutingModule } from './home-routing.module';
4 | import { HomePage } from './home.page';
5 |
6 | @NgModule({
7 | imports: [SharedModule, HomePageRoutingModule],
8 | declarations: [HomePage],
9 | })
10 | export class HomePageModule {}
11 |
--------------------------------------------------------------------------------
/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/spec",
6 | "types": [
7 | "jasmine"
8 | ]
9 | },
10 | "files": [
11 | "src/test.ts",
12 | "src/polyfills.ts"
13 | ],
14 | "include": [
15 | "src/**/*.spec.ts",
16 | "src/**/*.d.ts"
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | capacitor-mlkit-plugin-demo
4 | capacitor-mlkit-plugin-demo
5 | dev.robingenz.capacitorjs.demo.mlkitplugins
6 | dev.robingenz.capacitorjs.demo.mlkitplugins
7 |
8 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import { enableProdMode } from '@angular/core';
2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
3 |
4 | import { AppModule } from './app/app.module';
5 | import { environment } from './environments/environment';
6 |
7 | if (environment.production) {
8 | enableProdMode();
9 | }
10 |
11 | platformBrowserDynamic()
12 | .bootstrapModule(AppModule)
13 | .catch((err) => console.log(err));
14 |
--------------------------------------------------------------------------------
/src/app/modules/translation/translation.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { SharedModule } from '@app/shared';
3 |
4 | import { TranslationRoutingModule } from './translation-routing.module';
5 |
6 | import { TranslationPage } from './translation.page';
7 |
8 | @NgModule({
9 | imports: [SharedModule, TranslationRoutingModule],
10 | declarations: [TranslationPage],
11 | })
12 | export class TranslationModule {}
13 |
--------------------------------------------------------------------------------
/src/app/core/core.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule, Optional, SkipSelf } from '@angular/core';
2 |
3 | @NgModule({
4 | imports: [],
5 | providers: [],
6 | exports: [],
7 | })
8 | export class CoreModule {
9 | constructor(@Optional() @SkipSelf() parentModule: CoreModule) {
10 | if (parentModule) {
11 | throw new Error(
12 | 'CoreModule is already loaded. Import it in the AppModule only.',
13 | );
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/app/modules/home/home-routing.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { RouterModule, Routes } from '@angular/router';
3 | import { HomePage } from './home.page';
4 |
5 | const routes: Routes = [
6 | {
7 | path: '',
8 | component: HomePage,
9 | },
10 | ];
11 |
12 | @NgModule({
13 | imports: [RouterModule.forChild(routes)],
14 | exports: [RouterModule],
15 | })
16 | export class HomePageRoutingModule {}
17 |
--------------------------------------------------------------------------------
/.github/workflows/lock.yml:
--------------------------------------------------------------------------------
1 | name: Lock old issues and pull requests that are closed
2 |
3 | on:
4 | schedule:
5 | - cron: '0 17 * * *'
6 | workflow_dispatch:
7 |
8 | permissions:
9 | issues: write
10 | pull-requests: write
11 |
12 | concurrency:
13 | group: lock
14 |
15 | jobs:
16 | action:
17 | runs-on: ubuntu-latest
18 | steps:
19 | - uses: dessant/lock-threads@v3
20 | with:
21 | issue-inactive-days: '56'
22 |
--------------------------------------------------------------------------------
/src/app/modules/face-detection/face-detection.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { SharedModule } from '@app/shared';
3 |
4 | import { FaceDetectionRoutingModule } from './face-detection-routing.module';
5 |
6 | import { FaceDetectionPage } from './face-detection.page';
7 |
8 | @NgModule({
9 | imports: [SharedModule, FaceDetectionRoutingModule],
10 | declarations: [FaceDetectionPage],
11 | })
12 | export class FaceDetectionModule {}
13 |
--------------------------------------------------------------------------------
/src/app/modules/document-scanner/document-scanner.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { SharedModule } from '@app/shared';
3 |
4 | import { DocumentScannerRoutingModule } from './document-scanner-routing.module';
5 |
6 | import { DocumentScannerPage } from './document-scanner.page';
7 |
8 | @NgModule({
9 | imports: [SharedModule, DocumentScannerRoutingModule],
10 | declarations: [DocumentScannerPage],
11 | })
12 | export class DocumentScannerModule {}
13 |
--------------------------------------------------------------------------------
/src/app/shared/shared.module.ts:
--------------------------------------------------------------------------------
1 | import { CommonModule } from '@angular/common';
2 | import { NgModule } from '@angular/core';
3 | import { FormsModule, ReactiveFormsModule } from '@angular/forms';
4 | import { IonicModule } from '@ionic/angular';
5 |
6 | @NgModule({
7 | imports: [CommonModule, FormsModule, ReactiveFormsModule, IonicModule],
8 | declarations: [],
9 | exports: [CommonModule, FormsModule, ReactiveFormsModule, IonicModule],
10 | })
11 | export class SharedModule {}
12 |
--------------------------------------------------------------------------------
/src/app/modules/translation/translation-routing.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { RouterModule, Routes } from '@angular/router';
3 |
4 | import { TranslationPage } from './translation.page';
5 |
6 | const routes: Routes = [
7 | {
8 | path: '',
9 | component: TranslationPage,
10 | },
11 | ];
12 |
13 | @NgModule({
14 | imports: [RouterModule.forChild(routes)],
15 | exports: [RouterModule],
16 | })
17 | export class TranslationRoutingModule {}
18 |
--------------------------------------------------------------------------------
/android/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/app/modules/face-detection/face-detection-routing.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { RouterModule, Routes } from '@angular/router';
3 |
4 | import { FaceDetectionPage } from './face-detection.page';
5 |
6 | const routes: Routes = [
7 | {
8 | path: '',
9 | component: FaceDetectionPage,
10 | },
11 | ];
12 |
13 | @NgModule({
14 | imports: [RouterModule.forChild(routes)],
15 | exports: [RouterModule],
16 | })
17 | export class FaceDetectionRoutingModule {}
18 |
--------------------------------------------------------------------------------
/src/app/modules/home/home.page.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Demo
4 |
5 |
6 |
7 |
8 |
9 |
10 | Plugins
11 |
12 | @for (plugin of plugins; track plugin) {
13 |
14 | {{ plugin.name }}
15 |
16 | }
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/app/modules/selfie-segmentation/selfie-segmentation.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { SharedModule } from '@app/shared';
3 |
4 | import { SelfieSegmentationRoutingModule } from './selfie-segmentation-routing.module';
5 |
6 | import { SelfieSegmentationPage } from './selfie-segmentation.page';
7 |
8 | @NgModule({
9 | imports: [SharedModule, SelfieSegmentationRoutingModule],
10 | declarations: [SelfieSegmentationPage],
11 | })
12 | export class SelfieSegmentationModule {}
13 |
--------------------------------------------------------------------------------
/src/app/modules/barcode-scanning/barcode-scanning-routing.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { RouterModule, Routes } from '@angular/router';
3 |
4 | import { BarcodeScanningPage } from './barcode-scanning.page';
5 |
6 | const routes: Routes = [
7 | {
8 | path: '',
9 | component: BarcodeScanningPage,
10 | },
11 | ];
12 |
13 | @NgModule({
14 | imports: [RouterModule.forChild(routes)],
15 | exports: [RouterModule],
16 | })
17 | export class BarcodeScanningRoutingModule {}
18 |
--------------------------------------------------------------------------------
/src/app/modules/document-scanner/document-scanner-routing.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { RouterModule, Routes } from '@angular/router';
3 |
4 | import { DocumentScannerPage } from './document-scanner.page';
5 |
6 | const routes: Routes = [
7 | {
8 | path: '',
9 | component: DocumentScannerPage,
10 | },
11 | ];
12 |
13 | @NgModule({
14 | imports: [RouterModule.forChild(routes)],
15 | exports: [RouterModule],
16 | })
17 | export class DocumentScannerRoutingModule {}
18 |
--------------------------------------------------------------------------------
/src/app/modules/subject-segmentation/subject-segmentation.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { SharedModule } from '@app/shared';
3 |
4 | import { SubjectSegmentationRoutingModule } from './subject-segmentation-routing.module';
5 |
6 | import { SubjectSegmentationPage } from './subject-segmentation.page';
7 |
8 | @NgModule({
9 | imports: [SharedModule, SubjectSegmentationRoutingModule],
10 | declarations: [SubjectSegmentationPage],
11 | })
12 | export class SubjectSegmentationModule {}
13 |
--------------------------------------------------------------------------------
/src/app/modules/face-mesh-detection/face-mesh-detection-routing.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { RouterModule, Routes } from '@angular/router';
3 |
4 | import { FaceMeshDetectionPage } from './face-mesh-detection.page';
5 |
6 | const routes: Routes = [
7 | {
8 | path: '',
9 | component: FaceMeshDetectionPage,
10 | },
11 | ];
12 |
13 | @NgModule({
14 | imports: [RouterModule.forChild(routes)],
15 | exports: [RouterModule],
16 | })
17 | export class FaceMeshDetectionRoutingModule {}
18 |
--------------------------------------------------------------------------------
/src/app/modules/selfie-segmentation/selfie-segmentation-routing.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { RouterModule, Routes } from '@angular/router';
3 |
4 | import { SelfieSegmentationPage } from './selfie-segmentation.page';
5 |
6 | const routes: Routes = [
7 | {
8 | path: '',
9 | component: SelfieSegmentationPage,
10 | },
11 | ];
12 |
13 | @NgModule({
14 | imports: [RouterModule.forChild(routes)],
15 | exports: [RouterModule],
16 | })
17 | export class SelfieSegmentationRoutingModule {}
18 |
--------------------------------------------------------------------------------
/.github/workflows/needs-reply.yml:
--------------------------------------------------------------------------------
1 | name: Close old issues that need reply
2 |
3 | on:
4 | schedule:
5 | - cron: '0 0 * * *'
6 | workflow_dispatch:
7 |
8 | permissions:
9 | issues: write
10 |
11 | concurrency:
12 | group: needs-reply
13 |
14 | jobs:
15 | needs-reply:
16 | runs-on: ubuntu-latest
17 | steps:
18 | - name: Close old issues that need reply
19 | uses: dwieeb/needs-reply@v2
20 | with:
21 | repo-token: ${{ secrets.GITHUB_TOKEN }}
22 | issue-label: 'needs: reply'
23 |
--------------------------------------------------------------------------------
/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.getcapacitor.myapp;
2 |
3 | import static org.junit.Assert.*;
4 |
5 | import org.junit.Test;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 |
14 | @Test
15 | public void addition_isCorrect() throws Exception {
16 | assertEquals(4, 2 + 2);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/app/modules/subject-segmentation/subject-segmentation-routing.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { RouterModule, Routes } from '@angular/router';
3 |
4 | import { SubjectSegmentationPage } from './subject-segmentation.page';
5 |
6 | const routes: Routes = [
7 | {
8 | path: '',
9 | component: SubjectSegmentationPage,
10 | },
11 | ];
12 |
13 | @NgModule({
14 | imports: [RouterModule.forChild(routes)],
15 | exports: [RouterModule],
16 | })
17 | export class SubjectSegmentationRoutingModule {}
18 |
--------------------------------------------------------------------------------
/ios/App/App/Assets.xcassets/Splash.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "splash-2732x2732-2.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "splash-2732x2732-1.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "splash-2732x2732.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/src/tests/mocks/angular-mocks.ts:
--------------------------------------------------------------------------------
1 | import { Component, Pipe } from '@angular/core';
2 |
3 | export const createPipeMock = (options: Pipe): Pipe => {
4 | const metadata: Pipe = {
5 | name: options.name,
6 | };
7 | return Pipe(metadata)(class MockPipe {}) as Pipe;
8 | };
9 |
10 | export const createComponentMock = (options: Component): Component => {
11 | const metadata: Component = {
12 | selector: options.selector,
13 | inputs: options.inputs,
14 | };
15 | return Component(metadata)(class MockComponent {}) as Component;
16 | };
17 |
--------------------------------------------------------------------------------
/src/app/core/services/global-error-handler/global-error-handler.service.spec.ts:
--------------------------------------------------------------------------------
1 | import { TestBed } from '@angular/core/testing';
2 |
3 | import { GlobalErrorHandlerService } from './global-error-handler.service';
4 |
5 | describe('GlobalErrorHandlerService', () => {
6 | let service: GlobalErrorHandlerService;
7 |
8 | beforeEach(() => {
9 | TestBed.configureTestingModule({});
10 | service = TestBed.inject(GlobalErrorHandlerService);
11 | });
12 |
13 | it('should be created', () => {
14 | expect(service).toBeTruthy();
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/android/variables.gradle:
--------------------------------------------------------------------------------
1 | ext {
2 | minSdkVersion = 24
3 | compileSdkVersion = 36
4 | targetSdkVersion = 36
5 | androidxActivityVersion = '1.11.0'
6 | androidxAppCompatVersion = '1.7.1'
7 | androidxCoordinatorLayoutVersion = '1.3.0'
8 | androidxCoreVersion = '1.17.0'
9 | androidxFragmentVersion = '1.8.9'
10 | junitVersion = '4.13.2'
11 | androidxJunitVersion = '1.3.0'
12 | androidxEspressoCoreVersion = '3.7.0'
13 | cordovaAndroidVersion = '14.0.1'
14 | coreSplashScreenVersion = '1.2.0'
15 | androidxWebkitVersion = '1.14.0'
16 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.angular/cache
2 | # Specifies intentionally untracked files to ignore when using Git
3 | # http://git-scm.com/docs/gitignore
4 |
5 | *~
6 | *.sw[mnpcod]
7 | .tmp
8 | *.tmp
9 | *.tmp.*
10 | *.sublime-project
11 | *.sublime-workspace
12 | .DS_Store
13 | Thumbs.db
14 | UserInterfaceState.xcuserstate
15 | $RECYCLE.BIN/
16 |
17 | *.log
18 | log.txt
19 | npm-debug.log*
20 |
21 | /.idea
22 | /.ionic
23 | /.sass-cache
24 | /.sourcemaps
25 | /.versions
26 | /.vscode
27 | /coverage
28 | /dist
29 | /node_modules
30 | /platforms
31 | /plugins
32 | /www
33 | /cert.pem
34 | /key.pem
35 |
--------------------------------------------------------------------------------
/src/test.ts:
--------------------------------------------------------------------------------
1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files
2 |
3 | import 'zone.js/dist/zone-testing';
4 | import { getTestBed } from '@angular/core/testing';
5 | import {
6 | BrowserDynamicTestingModule,
7 | platformBrowserDynamicTesting,
8 | } from '@angular/platform-browser-dynamic/testing';
9 |
10 | // First, initialize the Angular testing environment.
11 | getTestBed().initTestEnvironment(
12 | BrowserDynamicTestingModule,
13 | platformBrowserDynamicTesting(),
14 | {
15 | teardown: { destroyAfterEach: false },
16 | },
17 | );
18 |
--------------------------------------------------------------------------------
/src/app/modules/barcode-scanning/barcode-scanning.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 |
3 | import { BarcodeScanningRoutingModule } from './barcode-scanning-routing.module';
4 |
5 | import { SharedTestingModule } from '@tests/modules';
6 | import { BarcodeScanningModalComponent } from './barcode-scanning-modal.component';
7 | import { BarcodeScanningPage } from './barcode-scanning.page';
8 |
9 | @NgModule({
10 | imports: [SharedTestingModule, BarcodeScanningRoutingModule],
11 | declarations: [BarcodeScanningPage, BarcodeScanningModalComponent],
12 | })
13 | export class BarcodeScanningModule {}
14 |
--------------------------------------------------------------------------------
/android/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/ios/App/App/capacitor.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "appId": "dev.robingenz.capacitorjs.demo.mlkitplugins",
3 | "appName": "capacitor-mlkit-plugin-demo",
4 | "bundledWebRuntime": false,
5 | "npmClient": "npm",
6 | "webDir": "www",
7 | "plugins": {},
8 | "cordova": {},
9 | "packageClassList": [
10 | "BarcodeScannerPlugin",
11 | "DocumentScannerPlugin",
12 | "FaceDetectionPlugin",
13 | "FaceMeshDetectionPlugin",
14 | "SelfieSegmentationPlugin",
15 | "SubjectSegmentationPlugin",
16 | "TranslationPlugin",
17 | "AppPlugin",
18 | "HapticsPlugin",
19 | "KeyboardPlugin",
20 | "StatusBarPlugin",
21 | "FilePickerPlugin"
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------
/android/.idea/deploymentTargetDropDown.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: "feat: "
5 | labels: ""
6 | assignees: ""
7 | ---
8 |
9 | **Is your feature request related to a problem? Please describe.**
10 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
11 |
12 | **Describe the solution you'd like**
13 | A clear and concise description of what you want to happen.
14 |
15 | **Describe alternatives you've considered**
16 | A clear and concise description of any alternative solutions or features you've considered.
17 |
18 | **Additional context**
19 | Add any other context or screenshots about the feature request here.
20 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 |
5 | repositories {
6 | google()
7 | mavenCentral()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:8.13.0'
11 |
12 | // NOTE: Do not place your application dependencies here; they belong
13 | // in the individual module build.gradle files
14 | }
15 | }
16 |
17 | apply from: "variables.gradle"
18 |
19 | allprojects {
20 | repositories {
21 | google()
22 | mavenCentral()
23 | }
24 | }
25 |
26 | task clean(type: Delete) {
27 | delete rootProject.buildDir
28 | }
29 |
--------------------------------------------------------------------------------
/src/app/app.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
2 | import { TestBed, waitForAsync } from '@angular/core/testing';
3 |
4 | import { AppComponent } from './app.component';
5 |
6 | describe('AppComponent', () => {
7 | beforeEach(waitForAsync(() => {
8 | TestBed.configureTestingModule({
9 | declarations: [AppComponent],
10 | schemas: [CUSTOM_ELEMENTS_SCHEMA],
11 | }).compileComponents();
12 | }));
13 |
14 | it('should create the app', () => {
15 | const fixture = TestBed.createComponent(AppComponent);
16 | const app = fixture.debugElement.componentInstance;
17 | expect(app).toBeTruthy();
18 | });
19 | // TODO: add more tests!
20 | });
21 |
--------------------------------------------------------------------------------
/.github/workflows/needs-triage.yml:
--------------------------------------------------------------------------------
1 | name: Add needs-triage label
2 |
3 | on:
4 | issues:
5 | types:
6 | - opened
7 |
8 | jobs:
9 | needs-triage:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: Add needs-triage label
13 | if: join(github.event.issue.labels) == ''
14 | run: |
15 | curl --request POST \
16 | --url 'https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.issue.number }}/labels' \
17 | --header 'Authorization: token ${{ secrets.GITHUB_TOKEN }}' \
18 | --header 'Content-Type: application/json' \
19 | --header 'Accept: application/vnd.github.v3+json' \
20 | --data-raw '{ "labels": ["needs: triage"] }'
21 |
--------------------------------------------------------------------------------
/src/tests/modules/shared-testing.module.ts:
--------------------------------------------------------------------------------
1 | import { CommonModule } from '@angular/common';
2 | import { NgModule } from '@angular/core';
3 | import { FormsModule, ReactiveFormsModule } from '@angular/forms';
4 | import { Router } from '@angular/router';
5 | import { IonicModule, NavController } from '@ionic/angular';
6 |
7 | @NgModule({
8 | imports: [
9 | CommonModule,
10 | FormsModule,
11 | ReactiveFormsModule,
12 | IonicModule.forRoot(),
13 | ],
14 | declarations: [],
15 | providers: [
16 | { provide: NavController, useValue: {} },
17 | { provide: Router, useValue: {} },
18 | ],
19 | exports: [CommonModule, FormsModule, ReactiveFormsModule, IonicModule],
20 | })
21 | export class SharedTestingModule {}
22 |
--------------------------------------------------------------------------------
/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | // This file can be replaced during build by using the `fileReplacements` array.
2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
3 | // The list of file replacements can be found in `angular.json`.
4 |
5 | export const environment = {
6 | production: false,
7 | };
8 |
9 | /*
10 | * For easier debugging in development mode, you can import the following file
11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
12 | *
13 | * This import should be commented out in production mode because it will have a negative impact
14 | * on performance if an error is thrown.
15 | */
16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI.
17 |
--------------------------------------------------------------------------------
/src/app/modules/face-mesh-detection/face-mesh-detection.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { SharedModule } from '@app/shared';
3 |
4 | import { FaceMeshDetectionRoutingModule } from './face-mesh-detection-routing.module';
5 |
6 | import { FaceMeshDetectionPage } from './face-mesh-detection.page';
7 | import {
8 | KeysPipe,
9 | ContourTitlePipe,
10 | ContourDescriptionPipe,
11 | ContourPipe,
12 | } from './face-mesh-detection.pipe';
13 |
14 | @NgModule({
15 | imports: [SharedModule, FaceMeshDetectionRoutingModule],
16 | declarations: [
17 | FaceMeshDetectionPage,
18 | KeysPipe,
19 | ContourTitlePipe,
20 | ContourDescriptionPipe,
21 | ContourPipe,
22 | ],
23 | })
24 | export class FaceMeshDetectionModule {}
25 |
--------------------------------------------------------------------------------
/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import { ErrorHandler, NgModule } from '@angular/core';
2 | import { BrowserModule } from '@angular/platform-browser';
3 | import { RouteReuseStrategy } from '@angular/router';
4 | import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
5 | import { AppRoutingModule } from './app-routing.module';
6 | import { AppComponent } from './app.component';
7 | import { GlobalErrorHandlerService } from './core';
8 |
9 | @NgModule({
10 | declarations: [AppComponent],
11 | imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule],
12 | providers: [
13 | { provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
14 | {
15 | provide: ErrorHandler,
16 | useClass: GlobalErrorHandlerService,
17 | },
18 | ],
19 | bootstrap: [AppComponent],
20 | })
21 | export class AppModule {}
22 |
--------------------------------------------------------------------------------
/src/app/modules/translation/translation.page.spec.ts:
--------------------------------------------------------------------------------
1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
2 | import { SharedTestingModule } from '@tests/modules';
3 | import { TranslationPage } from './translation.page';
4 |
5 | describe('TranslationPage', () => {
6 | let component: TranslationPage;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(waitForAsync(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [TranslationPage],
12 | imports: [SharedTestingModule],
13 | }).compileComponents();
14 |
15 | fixture = TestBed.createComponent(TranslationPage);
16 | component = fixture.componentInstance;
17 | fixture.detectChanges();
18 | }));
19 |
20 | it('should create', () => {
21 | expect(component).toBeTruthy();
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/src/app/modules/home/home.page.spec.ts:
--------------------------------------------------------------------------------
1 | import { ComponentFixture, TestBed } from '@angular/core/testing';
2 | import { SharedTestingModule } from '@tests/modules';
3 | import { HomePage } from './home.page';
4 |
5 | describe('HomePage', () => {
6 | let component: HomePage;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async () => {
10 | await TestBed.configureTestingModule({
11 | declarations: [HomePage],
12 | imports: [SharedTestingModule],
13 | }).compileComponents();
14 |
15 | fixture = TestBed.createComponent(HomePage);
16 | component = fixture.componentInstance;
17 | fixture.detectChanges();
18 | });
19 |
20 | afterEach(() => {
21 | fixture.nativeElement.remove();
22 | });
23 |
24 | it('should create', () => {
25 | expect(component).toBeTruthy();
26 | });
27 | });
28 |
--------------------------------------------------------------------------------
/.github/workflows/needs-reply-remove.yml:
--------------------------------------------------------------------------------
1 | name: Remove needs-reply label
2 |
3 | on:
4 | issue_comment:
5 | types:
6 | - created
7 |
8 | permissions:
9 | issues: write
10 |
11 | concurrency:
12 | group: needs-reply-remove-${{ github.event.issue.number }}
13 | cancel-in-progress: true
14 |
15 | jobs:
16 | needs-reply:
17 | runs-on: ubuntu-latest
18 | if: |
19 | github.event.comment.author_association != 'OWNER' &&
20 | github.event.comment.author_association != 'COLLABORATOR'
21 | steps:
22 | - name: Remove needs-reply label
23 | run: |
24 | curl --request DELETE \
25 | --url 'https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.issue.number }}/labels/needs%3A%20reply' \
26 | --header 'Authorization: token ${{ secrets.GITHUB_TOKEN }}'
27 |
--------------------------------------------------------------------------------
/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/src/app/modules/face-detection/face-detection.page.spec.ts:
--------------------------------------------------------------------------------
1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
2 | import { SharedTestingModule } from '@tests/modules';
3 | import { FaceDetectionPage } from './face-detection.page';
4 |
5 | describe('FaceDetectionPage', () => {
6 | let component: FaceDetectionPage;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(waitForAsync(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [FaceDetectionPage],
12 | imports: [SharedTestingModule],
13 | }).compileComponents();
14 |
15 | fixture = TestBed.createComponent(FaceDetectionPage);
16 | component = fixture.componentInstance;
17 | fixture.detectChanges();
18 | }));
19 |
20 | it('should create', () => {
21 | expect(component).toBeTruthy();
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/src/app/modules/barcode-scanning/barcode-scanning.page.spec.ts:
--------------------------------------------------------------------------------
1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
2 | import { IonicModule } from '@ionic/angular';
3 |
4 | import { BarcodeScanningPage } from './barcode-scanning.page';
5 |
6 | describe('BarcodeScanningPage', () => {
7 | let component: BarcodeScanningPage;
8 | let fixture: ComponentFixture;
9 |
10 | beforeEach(waitForAsync(() => {
11 | TestBed.configureTestingModule({
12 | declarations: [BarcodeScanningPage],
13 | imports: [IonicModule.forRoot()],
14 | }).compileComponents();
15 |
16 | fixture = TestBed.createComponent(BarcodeScanningPage);
17 | component = fixture.componentInstance;
18 | fixture.detectChanges();
19 | }));
20 |
21 | it('should create', () => {
22 | expect(component).toBeTruthy();
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/src/app/modules/document-scanner/document-scanner.page.spec.ts:
--------------------------------------------------------------------------------
1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
2 | import { IonicModule } from '@ionic/angular';
3 |
4 | import { DocumentScannerPage } from './document-scanner.page';
5 |
6 | describe('DocumentScannerPage', () => {
7 | let component: DocumentScannerPage;
8 | let fixture: ComponentFixture;
9 |
10 | beforeEach(waitForAsync(() => {
11 | TestBed.configureTestingModule({
12 | declarations: [DocumentScannerPage],
13 | imports: [IonicModule.forRoot()],
14 | }).compileComponents();
15 |
16 | fixture = TestBed.createComponent(DocumentScannerPage);
17 | component = fixture.componentInstance;
18 | fixture.detectChanges();
19 | }));
20 |
21 | it('should create', () => {
22 | expect(component).toBeTruthy();
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/src/app/modules/face-mesh-detection/face-mesh-detection.page.spec.ts:
--------------------------------------------------------------------------------
1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
2 | import { SharedTestingModule } from '@tests/modules';
3 | import { FaceMeshDetectionPage } from './face-mesh-detection.page';
4 |
5 | describe('FaceMeshDetectionPage', () => {
6 | let component: FaceMeshDetectionPage;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(waitForAsync(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [FaceMeshDetectionPage],
12 | imports: [SharedTestingModule],
13 | }).compileComponents();
14 |
15 | fixture = TestBed.createComponent(FaceMeshDetectionPage);
16 | component = fixture.componentInstance;
17 | fixture.detectChanges();
18 | }));
19 |
20 | it('should create', () => {
21 | expect(component).toBeTruthy();
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Ionic App
6 |
7 |
8 |
9 |
10 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/app/modules/selfie-segmentation/selfie-segmentation.page.spec.ts:
--------------------------------------------------------------------------------
1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
2 | import { SharedTestingModule } from '@tests/modules';
3 | import { SelfieSegmentationPage } from './selfie-segmentation.page';
4 |
5 | describe('SelfieSegmentationPage', () => {
6 | let component: SelfieSegmentationPage;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(waitForAsync(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [SelfieSegmentationPage],
12 | imports: [SharedTestingModule],
13 | }).compileComponents();
14 |
15 | fixture = TestBed.createComponent(SelfieSegmentationPage);
16 | component = fixture.componentInstance;
17 | fixture.detectChanges();
18 | }));
19 |
20 | it('should create', () => {
21 | expect(component).toBeTruthy();
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/src/app/modules/subject-segmentation/subject-segmentation.page.spec.ts:
--------------------------------------------------------------------------------
1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
2 | import { SharedTestingModule } from '@tests/modules';
3 | import { SubjectSegmentationPage } from './subject-segmentation.page';
4 |
5 | describe('SubjectSegmentationPage', () => {
6 | let component: SubjectSegmentationPage;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(waitForAsync(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [SubjectSegmentationPage],
12 | imports: [SharedTestingModule],
13 | }).compileComponents();
14 |
15 | fixture = TestBed.createComponent(SubjectSegmentationPage);
16 | component = fixture.componentInstance;
17 | fixture.detectChanges();
18 | }));
19 |
20 | it('should create', () => {
21 | expect(component).toBeTruthy();
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
11 |
12 |
17 |
18 |
19 |
22 |
--------------------------------------------------------------------------------
/src/app/modules/selfie-segmentation/selfie-segmentation.page.scss:
--------------------------------------------------------------------------------
1 | img {
2 | --backgroundColor: rgb(255, 255, 255);
3 | --squareColor: rgba(100, 100, 100, 0.5);
4 | --squareSize: 0.5em;
5 |
6 | @media (prefers-color-scheme: dark) {
7 | --backgroundColor: rgb(0, 0, 0);
8 | }
9 |
10 | background-color: var(--backgroundColor);
11 | background-image: linear-gradient(
12 | 45deg,
13 | var(--squareColor) 25%,
14 | transparent 25%
15 | ),
16 | linear-gradient(135deg, var(--squareColor) 25%, transparent 25%),
17 | linear-gradient(45deg, transparent 75%, var(--squareColor) 75%),
18 | linear-gradient(135deg, transparent 75%, var(--squareColor) 75%);
19 | background-position:
20 | 0 0,
21 | var(--squareSize) 0,
22 | var(--squareSize) calc(-1 * var(--squareSize)),
23 | 0 calc(-1 * var(--squareSize));
24 | background-size: calc(2 * var(--squareSize)) calc(2 * var(--squareSize));
25 | }
26 |
--------------------------------------------------------------------------------
/src/app/modules/subject-segmentation/subject-segmentation.page.scss:
--------------------------------------------------------------------------------
1 | img {
2 | --backgroundColor: rgb(255, 255, 255);
3 | --squareColor: rgba(100, 100, 100, 0.5);
4 | --squareSize: 0.5em;
5 |
6 | @media (prefers-color-scheme: dark) {
7 | --backgroundColor: rgb(0, 0, 0);
8 | }
9 |
10 | background-color: var(--backgroundColor);
11 | background-image: linear-gradient(
12 | 45deg,
13 | var(--squareColor) 25%,
14 | transparent 25%
15 | ),
16 | linear-gradient(135deg, var(--squareColor) 25%, transparent 25%),
17 | linear-gradient(45deg, transparent 75%, var(--squareColor) 75%),
18 | linear-gradient(135deg, transparent 75%, var(--squareColor) 75%);
19 | background-position:
20 | 0 0,
21 | var(--squareSize) 0,
22 | var(--squareSize) calc(-1 * var(--squareSize)),
23 | 0 calc(-1 * var(--squareSize));
24 | background-size: calc(2 * var(--squareSize)) calc(2 * var(--squareSize));
25 | }
26 |
--------------------------------------------------------------------------------
/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.getcapacitor.myapp;
2 |
3 | import static org.junit.Assert.*;
4 |
5 | import android.content.Context;
6 | import androidx.test.ext.junit.runners.AndroidJUnit4;
7 | import androidx.test.platform.app.InstrumentationRegistry;
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * @see Testing documentation
15 | */
16 | @RunWith(AndroidJUnit4.class)
17 | public class ExampleInstrumentedTest {
18 |
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
23 |
24 | assertEquals("com.getcapacitor.app", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/app/modules/home/home.page.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-home',
5 | templateUrl: './home.page.html',
6 | styleUrls: ['./home.page.scss'],
7 | })
8 | export class HomePage {
9 | public plugins = [
10 | {
11 | name: 'Barcode Scanning',
12 | url: '/barcode-scanning',
13 | },
14 | {
15 | name: 'Document Scanner',
16 | url: '/document-scanner',
17 | },
18 | {
19 | name: 'Face Detection',
20 | url: '/face-detection',
21 | },
22 | {
23 | name: 'Face Mesh Detection',
24 | url: '/face-mesh-detection',
25 | },
26 | {
27 | name: 'Selfie Segmentation',
28 | url: '/selfie-segmentation',
29 | },
30 | {
31 | name: 'Subject Segmentation',
32 | url: '/subject-segmentation',
33 | },
34 | {
35 | name: 'Translation',
36 | url: '/translation',
37 | },
38 | ];
39 |
40 | constructor() {}
41 | }
42 |
--------------------------------------------------------------------------------
/src/app/modules/face-mesh-detection/face-mesh-detection.page.scss:
--------------------------------------------------------------------------------
1 | ion-list ion-list-header {
2 | height: 0;
3 | }
4 | ion-list ion-card#face-mesh-points {
5 | width: 100%;
6 | }
7 | ion-list ion-card#face-mesh-points ion-item {
8 | --padding-start: 0px;
9 | --inner-padding-end: 0px;
10 | --min-height: auto;
11 | }
12 | ion-list ion-card#face-mesh-points ion-item ion-label {
13 | width: 40px;
14 | min-width: auto;
15 | flex: revert;
16 | margin: 0;
17 | margin-right: 10px;
18 | text-align: right;
19 | }
20 | ion-list ion-card#face-mesh-points ion-card-content {
21 | padding-top: 0;
22 | padding-bottom: 0;
23 | }
24 | ion-list ion-card#face-mesh-points ion-item ion-input {
25 | --padding-top: 0;
26 | --padding-bottom: 0;
27 | text-overflow: ellipsis;
28 | }
29 | ion-list ion-card#contours {
30 | width: 100%;
31 | }
32 | ion-list ion-card#contours ion-card-content {
33 | padding-left: 0;
34 | padding-right: 0;
35 | }
36 | ion-list ion-card#contours ion-card-content ion-card {
37 | margin: 0;
38 | }
39 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: "bug: "
5 | labels: ""
6 | assignees: ""
7 | ---
8 |
9 | **Describe the bug**
10 | A clear and concise description of what the bug is.
11 |
12 | **To Reproduce**
13 | Steps to reproduce the behavior:
14 |
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 |
28 | - OS: [e.g. iOS]
29 | - Browser [e.g. chrome, safari]
30 | - Version [e.g. 22]
31 |
32 | **Smartphone (please complete the following information):**
33 |
34 | - Device: [e.g. iPhone6]
35 | - OS: [e.g. iOS8.1]
36 | - Browser [e.g. stock browser, safari]
37 | - Version [e.g. 22]
38 |
39 | **Additional context**
40 | Add any other context about the problem here.
41 |
--------------------------------------------------------------------------------
/android/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
17 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
19 | # AndroidX package structure to make it clearer which packages are bundled with the
20 | # Android operating system, and which are packaged with your app's APK
21 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
22 | android.useAndroidX=true
23 |
24 |
--------------------------------------------------------------------------------
/ios/App/App/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "compileOnSave": false,
4 | "compilerOptions": {
5 | "baseUrl": "./",
6 | "outDir": "./dist/out-tsc",
7 | "sourceMap": true,
8 | "declaration": false,
9 | "downlevelIteration": true,
10 | "experimentalDecorators": true,
11 | "moduleResolution": "node",
12 | "importHelpers": true,
13 | "target": "ES2022",
14 | "module": "es2020",
15 | "lib": [
16 | "es2018",
17 | "dom"
18 | ],
19 | "strict": true,
20 | "paths": {
21 | "@app/*": [
22 | "src/app/*"
23 | ],
24 | "@env/*": [
25 | "src/environments/*"
26 | ],
27 | "@e2e/*": [
28 | "e2e/src/*"
29 | ],
30 | "@tests/*": [
31 | "src/tests/*"
32 | ]
33 | },
34 | "useDefineForClassFields": false
35 | },
36 | "angularCompilerOptions": {
37 | "enableI18nLegacyMessageIdFormat": false,
38 | "strictInjectionParameters": true,
39 | "strictInputAccessModifiers": true,
40 | "strictTemplates": true
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Robin Genz
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/assets/shapes.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/global.scss:
--------------------------------------------------------------------------------
1 | /*
2 | * App Global CSS
3 | * ----------------------------------------------------------------------------
4 | * Put style rules here that you want to apply globally. These styles are for
5 | * the entire app and not just one component. Additionally, this file can be
6 | * used as an entry point to import other CSS/Sass files to be included in the
7 | * output CSS.
8 | * For more information on global stylesheets, visit the documentation:
9 | * https://ionicframework.com/docs/layout/global-stylesheets
10 | */
11 |
12 | /* Core CSS required for Ionic components to work properly */
13 | @import "~@ionic/angular/css/core.css";
14 |
15 | /* Basic CSS for apps built with Ionic */
16 | @import "~@ionic/angular/css/normalize.css";
17 | @import "~@ionic/angular/css/structure.css";
18 | @import "~@ionic/angular/css/typography.css";
19 | @import "~@ionic/angular/css/display.css";
20 |
21 | /* Optional CSS utils that can be commented out */
22 | @import "~@ionic/angular/css/padding.css";
23 | @import "~@ionic/angular/css/float-elements.css";
24 | @import "~@ionic/angular/css/text-alignment.css";
25 | @import "~@ionic/angular/css/text-transformation.css";
26 | @import "~@ionic/angular/css/flex-utils.css";
27 |
--------------------------------------------------------------------------------
/android/app/capacitor.build.gradle:
--------------------------------------------------------------------------------
1 | // DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
2 |
3 | android {
4 | compileOptions {
5 | sourceCompatibility JavaVersion.VERSION_21
6 | targetCompatibility JavaVersion.VERSION_21
7 | }
8 | }
9 |
10 | apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
11 | dependencies {
12 | implementation project(':capacitor-mlkit-barcode-scanning')
13 | implementation project(':capacitor-mlkit-document-scanner')
14 | implementation project(':capacitor-mlkit-face-detection')
15 | implementation project(':capacitor-mlkit-face-mesh-detection')
16 | implementation project(':capacitor-mlkit-selfie-segmentation')
17 | implementation project(':capacitor-mlkit-subject-segmentation')
18 | implementation project(':capacitor-mlkit-translation')
19 | implementation project(':capacitor-app')
20 | implementation project(':capacitor-haptics')
21 | implementation project(':capacitor-keyboard')
22 | implementation project(':capacitor-status-bar')
23 | implementation project(':capawesome-capacitor-file-picker')
24 |
25 | }
26 |
27 |
28 | if (hasProperty('postBuildExtras')) {
29 | postBuildExtras()
30 | }
31 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "ignorePatterns": ["projects/**/*"],
4 | "overrides": [
5 | {
6 | "files": ["*.ts"],
7 | "parserOptions": {
8 | "project": ["tsconfig.json"],
9 | "createDefaultProgram": true
10 | },
11 | "plugins": ["@typescript-eslint"],
12 | "extends": [
13 | "plugin:@angular-eslint/recommended",
14 | "plugin:@angular-eslint/template/process-inline-templates"
15 | ],
16 | "rules": {
17 | "@angular-eslint/component-class-suffix": [
18 | "error",
19 | {
20 | "suffixes": ["Page", "Component"]
21 | }
22 | ],
23 | "@angular-eslint/component-selector": [
24 | "error",
25 | {
26 | "type": "element",
27 | "prefix": "app",
28 | "style": "kebab-case"
29 | }
30 | ],
31 | "@angular-eslint/directive-selector": [
32 | "error",
33 | {
34 | "type": "attribute",
35 | "prefix": "app",
36 | "style": "camelCase"
37 | }
38 | ]
39 | }
40 | },
41 | {
42 | "files": ["*.html"],
43 | "extends": ["plugin:@angular-eslint/template/recommended"],
44 | "rules": {}
45 | }
46 | ]
47 | }
48 |
--------------------------------------------------------------------------------
/android/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/tests/test-setup.ts:
--------------------------------------------------------------------------------
1 | // Source: https://github.com/angular/angular/issues/12313#issuecomment-561221167
2 |
3 | import { ChangeDetectorRef, Type } from '@angular/core';
4 | import { ComponentFixture, TestBed } from '@angular/core/testing';
5 |
6 | const runOnPushChangeDetection =
7 | (cf: ComponentFixture): (() => Promise) =>
8 | async () => {
9 | const cd: ChangeDetectorRef =
10 | cf.debugElement.injector.get(ChangeDetectorRef as any);
11 | cd.detectChanges();
12 | await cf.whenStable();
13 | };
14 |
15 | export const improveChangeDetection = () => {
16 | const originalCreate = TestBed.createComponent;
17 | TestBed.createComponent = (component: Type) => {
18 | const componentFixture: ComponentFixture = originalCreate(component);
19 | componentFixture.detectChanges = runOnPushChangeDetection(componentFixture);
20 | return componentFixture;
21 | };
22 | };
23 |
24 | // Source: https://github.com/ionic-team/ionic-framework/issues/19926#issuecomment-724188621
25 |
26 | export const muteIonicReInitializeWarning = () => {
27 | const originalWarn = console.warn;
28 | const patchedWarn = (warning: any, ...optionalParams: any[]) => {
29 | const suppress = `Ionic Angular was already initialized. Make sure IonicModule.forRoot() is just called once.`;
30 | if (warning === suppress) {
31 | return;
32 | }
33 | originalWarn(warning, ...optionalParams);
34 | };
35 | console.warn = patchedWarn;
36 | };
37 |
--------------------------------------------------------------------------------
/src/app/core/services/global-error-handler/global-error-handler.service.ts:
--------------------------------------------------------------------------------
1 | import { ErrorHandler, Injectable, Injector } from '@angular/core';
2 | import { DialogService } from '../dialog/dialog.service';
3 |
4 | const LOGTAG = '[GlobalErrorHandlerService]';
5 |
6 | @Injectable({
7 | providedIn: 'root',
8 | })
9 | export class GlobalErrorHandlerService implements ErrorHandler {
10 | constructor(private injector: Injector) {}
11 |
12 | public handleError(error: unknown): void {
13 | this.handle(error);
14 | }
15 |
16 | private async handle(error: unknown): Promise {
17 | try {
18 | console.error(error);
19 | const message = this.getMessageFromUnknownError(error);
20 | await this.showErrorAlert(message);
21 | } catch (errorHandlerError) {
22 | console.error(`${LOGTAG} Internal exception:`, errorHandlerError);
23 | }
24 | }
25 |
26 | private getMessageFromUnknownError(error: unknown): string {
27 | let message = 'An unknown error has occurred.';
28 | if (error instanceof Object && 'rejection' in error) {
29 | error = (error as any).rejection;
30 | }
31 | if (error instanceof Error && error.message) {
32 | message = error.message;
33 | }
34 | return message;
35 | }
36 |
37 | private async showErrorAlert(message: string): Promise {
38 | const dialogService: DialogService =
39 | this.injector.get(DialogService);
40 | await dialogService.showErrorAlert({ message });
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/app/core/services/dialog/dialog.service.spec.ts:
--------------------------------------------------------------------------------
1 | import { TestBed } from '@angular/core/testing';
2 | import {
3 | AlertController,
4 | AngularDelegate,
5 | LoadingController,
6 | ModalController,
7 | PopoverController,
8 | } from '@ionic/angular';
9 | import { SharedTestingModule } from '@tests/modules';
10 | import { DialogService } from './dialog.service';
11 |
12 | describe('DialogService', () => {
13 | let service: DialogService;
14 | let alertControllerSpy: jasmine.SpyObj;
15 | let loadingControllerSpy: jasmine.SpyObj;
16 | let popoverControllerSpy: jasmine.SpyObj;
17 |
18 | beforeEach(() => {
19 | alertControllerSpy = jasmine.createSpyObj('AlertController', ['create']);
20 | loadingControllerSpy = jasmine.createSpyObj('LoadingController', [
21 | 'create',
22 | ]);
23 | popoverControllerSpy = jasmine.createSpyObj('PopoverController', [
24 | 'create',
25 | ]);
26 |
27 | TestBed.configureTestingModule({
28 | providers: [
29 | ModalController,
30 | AngularDelegate,
31 | { provide: AlertController, useValue: alertControllerSpy },
32 | { provide: LoadingController, useValue: loadingControllerSpy },
33 | { provide: PopoverController, useValue: popoverControllerSpy },
34 | ],
35 | imports: [SharedTestingModule],
36 | });
37 | service = TestBed.inject(DialogService);
38 | });
39 |
40 | it('should be created', () => {
41 | expect(service).toBeTruthy();
42 | });
43 | });
44 |
--------------------------------------------------------------------------------
/android/app/src/main/assets/capacitor.plugins.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "pkg": "@capacitor-mlkit/barcode-scanning",
4 | "classpath": "io.capawesome.capacitorjs.plugins.mlkit.barcodescanning.BarcodeScannerPlugin"
5 | },
6 | {
7 | "pkg": "@capacitor-mlkit/document-scanner",
8 | "classpath": "io.capawesome.capacitorjs.plugins.mlkit.documentscanner.DocumentScannerPlugin"
9 | },
10 | {
11 | "pkg": "@capacitor-mlkit/face-detection",
12 | "classpath": "io.capawesome.capacitorjs.plugins.mlkit.facedetection.FaceDetectionPlugin"
13 | },
14 | {
15 | "pkg": "@capacitor-mlkit/face-mesh-detection",
16 | "classpath": "io.capawesome.capacitorjs.plugins.mlkit.facemeshdetection.FaceMeshDetectionPlugin"
17 | },
18 | {
19 | "pkg": "@capacitor-mlkit/selfie-segmentation",
20 | "classpath": "io.capawesome.capacitorjs.plugins.mlkit.selfiesegmentation.SelfieSegmentationPlugin"
21 | },
22 | {
23 | "pkg": "@capacitor-mlkit/subject-segmentation",
24 | "classpath": "io.capawesome.capacitorjs.plugins.mlkit.subjectsegmentation.SubjectSegmentationPlugin"
25 | },
26 | {
27 | "pkg": "@capacitor-mlkit/translation",
28 | "classpath": "io.capawesome.capacitorjs.plugins.mlkit.translation.TranslationPlugin"
29 | },
30 | {
31 | "pkg": "@capacitor/app",
32 | "classpath": "com.capacitorjs.plugins.app.AppPlugin"
33 | },
34 | {
35 | "pkg": "@capacitor/haptics",
36 | "classpath": "com.capacitorjs.plugins.haptics.HapticsPlugin"
37 | },
38 | {
39 | "pkg": "@capacitor/keyboard",
40 | "classpath": "com.capacitorjs.plugins.keyboard.KeyboardPlugin"
41 | },
42 | {
43 | "pkg": "@capacitor/status-bar",
44 | "classpath": "com.capacitorjs.plugins.statusbar.StatusBarPlugin"
45 | },
46 | {
47 | "pkg": "@capawesome/capacitor-file-picker",
48 | "classpath": "io.capawesome.capacitorjs.plugins.filepicker.FilePickerPlugin"
49 | }
50 | ]
51 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration file, see link for more information
2 | // https://karma-runner.github.io/1.0/config/configuration-file.html
3 |
4 | process.env.CHROME_BIN = require("puppeteer").executablePath();
5 |
6 | module.exports = function (config) {
7 | config.set({
8 | basePath: "",
9 | frameworks: ["jasmine", "@angular-devkit/build-angular"],
10 | plugins: [
11 | require("karma-jasmine"),
12 | require("karma-chrome-launcher"),
13 | require("karma-jasmine-html-reporter"),
14 | require("karma-coverage"),
15 | require("@angular-devkit/build-angular/plugins/karma"),
16 | ],
17 | client: {
18 | jasmine: {
19 | // you can add configuration options for Jasmine here
20 | // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
21 | // for example, you can disable the random execution with `random: false`
22 | // or set a specific seed with `seed: 4321`
23 | },
24 | clearContext: false, // leave Jasmine Spec Runner output visible in browser
25 | captureConsole: true,
26 | },
27 | jasmineHtmlReporter: {
28 | suppressAll: true, // removes the duplicated traces
29 | },
30 | coverageReporter: {
31 | dir: require("path").join(__dirname, "./coverage/ng-test"),
32 | subdir: ".",
33 | reporters: [{ type: "html" }, { type: "text-summary" }],
34 | },
35 | reporters: ["progress", "kjhtml"],
36 | port: 9876,
37 | colors: true,
38 | logLevel: config.LOG_INFO,
39 | autoWatch: true,
40 | browsers: ["Chrome", "HeadlessChrome"],
41 | customLaunchers: {
42 | HeadlessChrome: {
43 | base: "ChromeHeadless",
44 | flags: ["--no-sandbox", "--disable-gpu"],
45 | },
46 | },
47 | singleRun: false,
48 | });
49 | };
50 |
--------------------------------------------------------------------------------
/src/app/modules/face-mesh-detection/face-mesh-detection.page.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 | import { UntypedFormControl, UntypedFormGroup } from '@angular/forms';
3 | import {
4 | FaceMesh,
5 | FaceMeshDetection,
6 | Point3D,
7 | UseCase,
8 | } from '@capacitor-mlkit/face-mesh-detection';
9 | import { FilePicker } from '@capawesome/capacitor-file-picker';
10 |
11 | @Component({
12 | selector: 'app-face-mesh-detection',
13 | templateUrl: './face-mesh-detection.page.html',
14 | styleUrls: ['./face-mesh-detection.page.scss'],
15 | })
16 | export class FaceMeshDetectionPage {
17 | public readonly useCase = UseCase;
18 |
19 | public formGroup = new UntypedFormGroup({
20 | useCase: new UntypedFormControl(UseCase.FaceMesh),
21 | });
22 |
23 | public faceMeshs: FaceMesh[] = [];
24 |
25 | private readonly githubUrl =
26 | 'https://github.com/capawesome-team/capacitor-mlkit';
27 |
28 | constructor() {}
29 |
30 | public openOnGithub(): void {
31 | window.open(this.githubUrl, '_blank');
32 | }
33 |
34 | public async processImage(): Promise {
35 | const { files } = await FilePicker.pickImages({ limit: 1 });
36 | const path = files[0]?.path;
37 | if (!path) {
38 | return;
39 | }
40 |
41 | const useCase = this.formGroup.get('useCase')?.value;
42 |
43 | const { faceMeshs } = await FaceMeshDetection.processImage({
44 | path,
45 |
46 | useCase: useCase,
47 | });
48 | this.faceMeshs = faceMeshs;
49 | }
50 |
51 | public getPoint(point: Point3D) {
52 | return `(${point.x}, ${point.y}, ${point.z})`;
53 | }
54 |
55 | public getPoints(points: Point3D[]) {
56 | const results = [];
57 | for (const point of points) {
58 | results.push(this.getPoint(point));
59 | }
60 | return results.join(', ');
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/ios/App/App/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | capacitor-mlkit-plugin-demo
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | NSCameraUsageDescription
26 | The app enables the scanning of various barcodes.
27 | UIBackgroundModes
28 |
29 | fetch
30 | remote-notification
31 |
32 | UILaunchStoryboardName
33 | LaunchScreen
34 | UIMainStoryboardFile
35 | Main
36 | UIRequiredDeviceCapabilities
37 |
38 | armv7
39 |
40 | UISupportedInterfaceOrientations
41 |
42 | UIInterfaceOrientationPortrait
43 | UIInterfaceOrientationLandscapeLeft
44 | UIInterfaceOrientationLandscapeRight
45 |
46 | UISupportedInterfaceOrientations~ipad
47 |
48 | UIInterfaceOrientationPortrait
49 | UIInterfaceOrientationPortraitUpsideDown
50 | UIInterfaceOrientationLandscapeLeft
51 | UIInterfaceOrientationLandscapeRight
52 |
53 | UIViewControllerBasedStatusBarAppearance
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | # Using Android gitignore template: https://github.com/github/gitignore/blob/HEAD/Android.gitignore
2 |
3 | # Built application files
4 | *.apk
5 | *.aar
6 | *.ap_
7 | *.aab
8 |
9 | # Files for the ART/Dalvik VM
10 | *.dex
11 |
12 | # Java class files
13 | *.class
14 |
15 | # Generated files
16 | bin/
17 | gen/
18 | out/
19 | # Uncomment the following line in case you need and you don't have the release build type files in your app
20 | # release/
21 |
22 | # Gradle files
23 | .gradle/
24 | build/
25 |
26 | # Local configuration file (sdk path, etc)
27 | local.properties
28 |
29 | # Proguard folder generated by Eclipse
30 | proguard/
31 |
32 | # Log Files
33 | *.log
34 |
35 | # Android Studio Navigation editor temp files
36 | .navigation/
37 |
38 | # Android Studio captures folder
39 | captures/
40 |
41 | # IntelliJ
42 | *.iml
43 | .idea/workspace.xml
44 | .idea/tasks.xml
45 | .idea/gradle.xml
46 | .idea/assetWizardSettings.xml
47 | .idea/dictionaries
48 | .idea/libraries
49 | # Android Studio 3 in .gitignore file.
50 | .idea/caches
51 | .idea/modules.xml
52 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you
53 | .idea/navEditor.xml
54 |
55 | # Keystore files
56 | # Uncomment the following lines if you do not want to check your keystore files in.
57 | #*.jks
58 | #*.keystore
59 |
60 | # External native build folder generated in Android Studio 2.2 and later
61 | .externalNativeBuild
62 | .cxx/
63 |
64 | # Google Services (e.g. APIs or Firebase)
65 | # google-services.json
66 |
67 | # Freeline
68 | freeline.py
69 | freeline/
70 | freeline_project_description.json
71 |
72 | # fastlane
73 | fastlane/report.xml
74 | fastlane/Preview.html
75 | fastlane/screenshots
76 | fastlane/test_output
77 | fastlane/readme.md
78 |
79 | # Version control
80 | vcs.xml
81 |
82 | # lint
83 | lint/intermediates/
84 | lint/generated/
85 | lint/outputs/
86 | lint/tmp/
87 | # lint/reports/
88 |
89 | # Android Profiling
90 | *.hprof
91 |
92 | # Cordova plugins for Capacitor
93 | capacitor-cordova-android-plugins
94 |
95 | # Copied web assets
96 | app/src/main/assets/public
97 |
--------------------------------------------------------------------------------
/src/app/core/services/dialog/dialog.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import {
3 | AlertController,
4 | LoadingController,
5 | ModalController,
6 | PopoverController,
7 | } from '@ionic/angular';
8 | import {
9 | AlertOptions,
10 | LoadingOptions,
11 | ModalOptions,
12 | PopoverOptions,
13 | } from '@ionic/core';
14 |
15 | @Injectable({
16 | providedIn: 'root',
17 | })
18 | export class DialogService {
19 | constructor(
20 | private alertCtrl: AlertController,
21 | private modalCtrl: ModalController,
22 | private loadingCtrl: LoadingController,
23 | private popoverCtrl: PopoverController,
24 | ) {}
25 |
26 | public async dismissModal(data?: any): Promise {
27 | return this.modalCtrl.dismiss(data);
28 | }
29 |
30 | public async showAlert(opts?: AlertOptions): Promise {
31 | const alert = await this.alertCtrl.create(opts);
32 | await alert.present();
33 | return alert;
34 | }
35 |
36 | public async showErrorAlert(
37 | opts?: AlertOptions,
38 | ): Promise {
39 | const defaultOpts: AlertOptions = {
40 | header: 'Error',
41 | buttons: ['OK'],
42 | };
43 | opts = { ...defaultOpts, ...opts };
44 | return this.showAlert(opts);
45 | }
46 |
47 | public async showModal(opts: ModalOptions): Promise {
48 | const modal = await this.modalCtrl.create(opts);
49 | await modal.present();
50 | return modal;
51 | }
52 |
53 | public async showPopover(
54 | opts: PopoverOptions,
55 | ): Promise {
56 | const popover = await this.popoverCtrl.create(opts);
57 | await popover.present();
58 | return popover;
59 | }
60 |
61 | public async showLoading(
62 | opts?: LoadingOptions,
63 | ): Promise {
64 | const defaultOpts: LoadingOptions = {
65 | message: 'Please wait...',
66 | };
67 | opts = { ...defaultOpts, ...opts };
68 | const loading = await this.loadingCtrl.create(opts);
69 | await loading.present();
70 | return loading;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/ios/App/App/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/app/modules/selfie-segmentation/selfie-segmentation.page.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 | import { UntypedFormControl, UntypedFormGroup } from '@angular/forms';
3 | import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
4 | import {
5 | ProcessImageResult,
6 | SelfieSegmentation,
7 | } from '@capacitor-mlkit/selfie-segmentation';
8 | import { Capacitor } from '@capacitor/core';
9 | import { FilePicker } from '@capawesome/capacitor-file-picker';
10 |
11 | @Component({
12 | selector: 'app-selfie-segmentation',
13 | templateUrl: './selfie-segmentation.page.html',
14 | styleUrls: ['./selfie-segmentation.page.scss'],
15 | })
16 | export class SelfieSegmentationPage {
17 | public formGroup = new UntypedFormGroup({
18 | width: new UntypedFormControl(512),
19 | height: new UntypedFormControl(),
20 | confidence: new UntypedFormControl(9),
21 | });
22 | public result: ProcessImageResult | undefined;
23 |
24 | private readonly githubUrl =
25 | 'https://github.com/capawesome-team/capacitor-mlkit';
26 |
27 | constructor(private readonly domSanitizer: DomSanitizer) {}
28 |
29 | public openOnGithub(): void {
30 | window.open(this.githubUrl, '_blank');
31 | }
32 |
33 | public pinFormatter(value: number): string {
34 | return `${value / 10.0}`;
35 | }
36 |
37 | public async processImage(): Promise {
38 | const { files } = await FilePicker.pickImages({ limit: 1 });
39 | const path = files[0]?.path;
40 | if (!path) {
41 | return;
42 | }
43 |
44 | const width = this.formGroup.get('width')?.value;
45 | const height = this.formGroup.get('height')?.value;
46 | const confidence = this.formGroup.get('confidence')?.value;
47 |
48 | const result = await SelfieSegmentation.processImage({
49 | path,
50 | width: width,
51 | height: height,
52 | confidence: confidence / 10.0,
53 | });
54 | this.result = result;
55 | }
56 |
57 | public convertPathToWebPath(path: string): SafeUrl {
58 | const fileSrc = Capacitor.convertFileSrc(path);
59 | return this.domSanitizer.bypassSecurityTrustUrl(fileSrc);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/app/app-routing.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { PreloadAllModules, RouterModule, Routes } from '@angular/router';
3 |
4 | const routes: Routes = [
5 | {
6 | path: '',
7 | redirectTo: 'home',
8 | pathMatch: 'full',
9 | },
10 | {
11 | path: 'home',
12 | loadChildren: () =>
13 | import('./modules/home/home.module').then((m) => m.HomePageModule),
14 | },
15 | {
16 | path: 'barcode-scanning',
17 | loadChildren: () =>
18 | import('./modules/barcode-scanning/barcode-scanning.module').then(
19 | (m) => m.BarcodeScanningModule,
20 | ),
21 | },
22 | {
23 | path: 'document-scanner',
24 | loadChildren: () =>
25 | import('./modules/document-scanner/document-scanner.module').then(
26 | (m) => m.DocumentScannerModule,
27 | ),
28 | },
29 | {
30 | path: 'face-detection',
31 | loadChildren: () =>
32 | import('./modules/face-detection/face-detection.module').then(
33 | (m) => m.FaceDetectionModule,
34 | ),
35 | },
36 | {
37 | path: 'face-mesh-detection',
38 | loadChildren: () =>
39 | import('./modules/face-mesh-detection/face-mesh-detection.module').then(
40 | (m) => m.FaceMeshDetectionModule,
41 | ),
42 | },
43 | {
44 | path: 'selfie-segmentation',
45 | loadChildren: () =>
46 | import('./modules/selfie-segmentation/selfie-segmentation.module').then(
47 | (m) => m.SelfieSegmentationModule,
48 | ),
49 | },
50 | {
51 | path: 'subject-segmentation',
52 | loadChildren: () =>
53 | import('./modules/subject-segmentation/subject-segmentation.module').then(
54 | (m) => m.SubjectSegmentationModule,
55 | ),
56 | },
57 | {
58 | path: 'translation',
59 | loadChildren: () =>
60 | import('./modules/translation/translation.module').then(
61 | (m) => m.TranslationModule,
62 | ),
63 | },
64 | {
65 | path: '**',
66 | redirectTo: 'home',
67 | },
68 | ];
69 |
70 | @NgModule({
71 | imports: [
72 | RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules }),
73 | ],
74 | exports: [RouterModule],
75 | })
76 | export class AppRoutingModule {}
77 |
--------------------------------------------------------------------------------
/android/capacitor.settings.gradle:
--------------------------------------------------------------------------------
1 | // DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
2 | include ':capacitor-android'
3 | project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor')
4 |
5 | include ':capacitor-mlkit-barcode-scanning'
6 | project(':capacitor-mlkit-barcode-scanning').projectDir = new File('../node_modules/@capacitor-mlkit/barcode-scanning/android')
7 |
8 | include ':capacitor-mlkit-document-scanner'
9 | project(':capacitor-mlkit-document-scanner').projectDir = new File('../node_modules/@capacitor-mlkit/document-scanner/android')
10 |
11 | include ':capacitor-mlkit-face-detection'
12 | project(':capacitor-mlkit-face-detection').projectDir = new File('../node_modules/@capacitor-mlkit/face-detection/android')
13 |
14 | include ':capacitor-mlkit-face-mesh-detection'
15 | project(':capacitor-mlkit-face-mesh-detection').projectDir = new File('../node_modules/@capacitor-mlkit/face-mesh-detection/android')
16 |
17 | include ':capacitor-mlkit-selfie-segmentation'
18 | project(':capacitor-mlkit-selfie-segmentation').projectDir = new File('../node_modules/@capacitor-mlkit/selfie-segmentation/android')
19 |
20 | include ':capacitor-mlkit-subject-segmentation'
21 | project(':capacitor-mlkit-subject-segmentation').projectDir = new File('../node_modules/@capacitor-mlkit/subject-segmentation/android')
22 |
23 | include ':capacitor-mlkit-translation'
24 | project(':capacitor-mlkit-translation').projectDir = new File('../node_modules/@capacitor-mlkit/translation/android')
25 |
26 | include ':capacitor-app'
27 | project(':capacitor-app').projectDir = new File('../node_modules/@capacitor/app/android')
28 |
29 | include ':capacitor-haptics'
30 | project(':capacitor-haptics').projectDir = new File('../node_modules/@capacitor/haptics/android')
31 |
32 | include ':capacitor-keyboard'
33 | project(':capacitor-keyboard').projectDir = new File('../node_modules/@capacitor/keyboard/android')
34 |
35 | include ':capacitor-status-bar'
36 | project(':capacitor-status-bar').projectDir = new File('../node_modules/@capacitor/status-bar/android')
37 |
38 | include ':capawesome-capacitor-file-picker'
39 | project(':capawesome-capacitor-file-picker').projectDir = new File('../node_modules/@capawesome/capacitor-file-picker/android')
40 |
--------------------------------------------------------------------------------
/src/app/modules/subject-segmentation/subject-segmentation.page.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 | import { UntypedFormControl, UntypedFormGroup } from '@angular/forms';
3 | import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
4 | import {
5 | ProcessImageResult,
6 | SubjectSegmentation,
7 | } from '@capacitor-mlkit/subject-segmentation';
8 | import { Capacitor } from '@capacitor/core';
9 | import { FilePicker } from '@capawesome/capacitor-file-picker';
10 |
11 | @Component({
12 | selector: 'app-subject-segmentation',
13 | templateUrl: './subject-segmentation.page.html',
14 | styleUrls: ['./subject-segmentation.page.scss'],
15 | })
16 | export class SubjectSegmentationPage {
17 | public formGroup = new UntypedFormGroup({
18 | width: new UntypedFormControl(512),
19 | height: new UntypedFormControl(),
20 | confidence: new UntypedFormControl(9),
21 | });
22 | public result: ProcessImageResult | undefined;
23 |
24 | private readonly githubUrl =
25 | 'https://github.com/capawesome-team/capacitor-mlkit';
26 |
27 | constructor(private readonly domSanitizer: DomSanitizer) {}
28 |
29 | public openOnGithub(): void {
30 | window.open(this.githubUrl, '_blank');
31 | }
32 |
33 | public pinFormatter(value: number): string {
34 | return `${value / 10.0}`;
35 | }
36 |
37 | public async processImage(): Promise {
38 | const { files } = await FilePicker.pickImages({ limit: 1 });
39 | const path = files[0]?.path;
40 | if (!path) {
41 | return;
42 | }
43 |
44 | const width = this.formGroup.get('width')?.value;
45 | const height = this.formGroup.get('height')?.value;
46 | const confidence = this.formGroup.get('confidence')?.value;
47 |
48 | const result = await SubjectSegmentation.processImage({
49 | path,
50 | width: width,
51 | height: height,
52 | confidence: confidence / 10.0,
53 | });
54 | this.result = result;
55 | }
56 |
57 | public async installGoogleSubjectSegmentationModule(): Promise {
58 | await SubjectSegmentation.installGoogleSubjectSegmentationModule();
59 | }
60 |
61 | public convertPathToWebPath(path: string): SafeUrl {
62 | const fileSrc = Capacitor.convertFileSrc(path);
63 | return this.domSanitizer.bypassSecurityTrustUrl(fileSrc);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
32 |
35 |
36 |
37 |
38 |
40 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/ios/App/Podfile:
--------------------------------------------------------------------------------
1 | require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers'
2 |
3 | platform :ios, '15.5'
4 | use_frameworks!
5 |
6 | # workaround to avoid Xcode caching of Pods that requires
7 | # Product -> Clean Build Folder after new Cordova plugins installed
8 | # Requires CocoaPods 1.6 or newer
9 | install! 'cocoapods', :disable_input_output_paths => true
10 |
11 | def capacitor_pods
12 | pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
13 | pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
14 | pod 'CapacitorMlkitBarcodeScanning', :path => '../../node_modules/@capacitor-mlkit/barcode-scanning'
15 | pod 'CapacitorMlkitDocumentScanner', :path => '../../node_modules/@capacitor-mlkit/document-scanner'
16 | pod 'CapacitorMlkitFaceDetection', :path => '../../node_modules/@capacitor-mlkit/face-detection'
17 | pod 'CapacitorMlkitFaceMeshDetection', :path => '../../node_modules/@capacitor-mlkit/face-mesh-detection'
18 | pod 'CapacitorMlkitSelfieSegmentation', :path => '../../node_modules/@capacitor-mlkit/selfie-segmentation'
19 | pod 'CapacitorMlkitSubjectSegmentation', :path => '../../node_modules/@capacitor-mlkit/subject-segmentation'
20 | pod 'CapacitorMlkitTranslation', :path => '../../node_modules/@capacitor-mlkit/translation'
21 | pod 'CapacitorApp', :path => '../../node_modules/@capacitor/app'
22 | pod 'CapacitorHaptics', :path => '../../node_modules/@capacitor/haptics'
23 | pod 'CapacitorKeyboard', :path => '../../node_modules/@capacitor/keyboard'
24 | pod 'CapacitorStatusBar', :path => '../../node_modules/@capacitor/status-bar'
25 | pod 'CapawesomeCapacitorFilePicker', :path => '../../node_modules/@capawesome/capacitor-file-picker'
26 | end
27 |
28 | target 'App' do
29 | capacitor_pods
30 | # Add your Pods here
31 | end
32 |
33 |
34 | post_install do |installer|
35 | assertDeploymentTarget(installer)
36 | installer.pods_project.targets.each do |target|
37 | if target.respond_to?(:product_type) and target.product_type == "com.apple.product-type.bundle"
38 | target.build_configurations.each do |config|
39 | config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'
40 | end
41 | end
42 | target.build_configurations.each do |config|
43 | config.build_settings['ONLY_ACTIVE_ARCH'] = 'NO'
44 | config.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'arm64'
45 | end
46 | end
47 | end
48 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # capacitor-mlkit-plugin-demo
2 |
3 | [](https://github.com/robingenz/capacitor-mlkit-plugin-demo/actions)
4 |
5 |
6 |
7 | ⚡️ Simple Ionic Angular app to demonstrate the use of certain Capacitor plugins.
8 |
9 | ## Plugins
10 |
11 | The following plugins are included:
12 |
13 | - [capacitor-mlkit/barcode-scanning](https://capawesome.io/plugins/mlkit/barcode-scanning/)
14 | - [capacitor-mlkit/face-detection](https://capawesome.io/plugins/mlkit/face-detection/)
15 | - [capacitor-mlkit/selfie-segmentation](https://capawesome.io/plugins/mlkit/selfie-segmentation/)
16 | - [capacitor-mlkit/subject-segmentation](https://capawesome.io/plugins/mlkit/subject-segmentation/)
17 | - [capacitor-mlkit/translation](https://capawesome.io/plugins/mlkit/translation/)
18 |
19 | ## Development Setup 💻
20 |
21 | ### Prerequisites
22 |
23 | - Install [Node.js](https://nodejs.org) which includes [Node Package Manager](https://www.npmjs.com/get-npm)
24 | - Android development: Install [Android Studio](https://developer.android.com/studio)
25 | - iOS development: Install [XCode](https://apps.apple.com/de/app/xcode/id497799835?mt=12)
26 |
27 | ### Getting Started
28 |
29 | Clone this repository:
30 |
31 | ```
32 | git clone https://github.com/robingenz/capacitor-mlkit-plugin-demo.git
33 | ```
34 |
35 | Change to the root directory of the project:
36 |
37 | ```
38 | cd capacitor-mlkit-plugin-demo
39 | ```
40 |
41 | Install all dependencies:
42 |
43 | ```
44 | npm i
45 | ```
46 |
47 | Prepare and launch the Android app:
48 |
49 | ```
50 | npx ionic cap sync android
51 | npx ionic cap run android
52 | ```
53 |
54 | Prepare and launch the iOS app:
55 |
56 | ```
57 | npx ionic cap sync ios
58 | npx ionic cap run ios
59 | ```
60 |
61 | This project uses [Ionic](https://ionicframework.com/) as app development platform and the [Ionic CLI](https://ionicframework.com/docs/cli).
62 |
63 |
66 |
67 | ## License
68 |
69 | See [LICENSE](https://github.com/robingenz/capacitor-mlkit-plugin-demo/blob/main/LICENSE).
70 |
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | namespace = "dev.robingenz.capacitorjs.demo.mlkitplugins"
5 | compileSdk = rootProject.ext.compileSdkVersion
6 | defaultConfig {
7 | applicationId "dev.robingenz.capacitorjs.demo.mlkitplugins"
8 | minSdkVersion rootProject.ext.minSdkVersion
9 | targetSdkVersion rootProject.ext.targetSdkVersion
10 | versionCode 1
11 | versionName "1.0"
12 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
13 | aaptOptions {
14 | // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
15 | // Default: https://android.googlesource.com/platform/frameworks/base/+/282e181b58cf72b6ca770dc7ca5f91f135444502/tools/aapt/AaptAssets.cpp#61
16 | ignoreAssetsPattern = '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~'
17 | }
18 | }
19 | buildTypes {
20 | release {
21 | minifyEnabled false
22 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
23 | }
24 | }
25 | buildFeatures {
26 | dataBinding true
27 | }
28 | dataBinding {
29 | enabled = true
30 | }
31 | }
32 |
33 | repositories {
34 | flatDir{
35 | dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs'
36 | }
37 | }
38 |
39 | dependencies {
40 | implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion"
41 | implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion"
42 | implementation fileTree(include: ['*.jar'], dir: 'libs')
43 | implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
44 | implementation project(':capacitor-android')
45 | testImplementation "junit:junit:$junitVersion"
46 | androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
47 | androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
48 | implementation project(':capacitor-cordova-android-plugins')
49 | }
50 |
51 | apply from: 'capacitor.build.gradle'
52 |
53 | try {
54 | def servicesJSON = file('google-services.json')
55 | if (servicesJSON.text) {
56 | apply plugin: 'com.google.gms.google-services'
57 | }
58 | } catch(Exception e) {
59 | logger.warn("google-services.json not found, google-services plugin not applied. Push Notifications won't work")
60 | }
61 |
--------------------------------------------------------------------------------
/src/app/modules/selfie-segmentation/selfie-segmentation.page.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ML Kit Selfie Segmentation
7 |
8 |
9 |
10 |
11 |
12 |
13 | About
14 |
15 |
16 | ⚡️ Capacitor plugin for ML Kit Selfie Segmentation.
17 |
18 |
19 |
20 | GitHub
26 |
27 |
28 |
29 |
30 |
31 | Demo
32 |
33 |
34 |
58 |
59 |
60 | @if (result) {
61 |
62 |
63 |
64 |
65 | Width
66 |
67 |
68 |
69 | Height
70 |
71 |
72 |
73 |
74 | }
75 |
76 |
--------------------------------------------------------------------------------
/src/polyfills.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This file includes polyfills needed by Angular and is loaded before the app.
3 | * You can add your own extra polyfills to this file.
4 | *
5 | * This file is divided into 2 sections:
6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
8 | * file.
9 | *
10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
13 | *
14 | * Learn more in https://angular.io/guide/browser-support
15 | */
16 |
17 | /***************************************************************************************************
18 | * BROWSER POLYFILLS
19 | */
20 |
21 | /**
22 | * By default, zone.js will patch all possible macroTask and DomEvents
23 | * user can disable parts of macroTask/DomEvents patch by setting following flags
24 | * because those flags need to be set before `zone.js` being loaded, and webpack
25 | * will put import in the top of bundle, so user need to create a separate file
26 | * in this directory (for example: zone-flags.ts), and put the following flags
27 | * into that file, and then add the following code before importing zone.js.
28 | * import './zone-flags';
29 | *
30 | * The flags allowed in zone-flags.ts are listed here.
31 | *
32 | * The following flags will work for all browsers.
33 | *
34 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
35 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
36 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
37 | *
38 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
39 | * with the following flag, it will bypass `zone.js` patch for IE/Edge
40 | *
41 | * (window as any).__Zone_enable_cross_context_check = true;
42 | *
43 | */
44 |
45 | import './zone-flags';
46 |
47 | /***************************************************************************************************
48 | * Zone JS is required by default for Angular itself.
49 | */
50 | import 'zone.js'; // Included with Angular CLI.
51 |
52 | /***************************************************************************************************
53 | * APPLICATION IMPORTS
54 | */
55 | import 'barcode-detector/polyfill';
56 |
--------------------------------------------------------------------------------
/src/app/modules/face-mesh-detection/face-mesh-detection.pipe.ts:
--------------------------------------------------------------------------------
1 | import { Pipe, PipeTransform } from '@angular/core';
2 | import { FaceMeshPoint, Contours } from '@capacitor-mlkit/face-mesh-detection';
3 |
4 | const contourType: any = {
5 | faceOval: {
6 | title: 'Face Oval',
7 | description: "The outline of the subject's face.",
8 | },
9 | leftEye: {
10 | title: 'Left Eye',
11 | description: "The outline of the subject's left eye cavity.",
12 | },
13 | leftEyebrowBottom: {
14 | title: 'Left Eyebrow Bottom',
15 | description: "The bottom outline of the subject's left eyebrow.",
16 | },
17 | leftEyebrowTop: {
18 | title: 'Left Eyebrow Top',
19 | description: "The top outline of the subject's left eyebrow.",
20 | },
21 | lowerLipBottom: {
22 | title: 'Lower Lip Bottom',
23 | description: "The bottom outline of the subject's lower lip.",
24 | },
25 | lowerLipTop: {
26 | title: 'Lower Lip Top',
27 | description: "The top outline of the subject's lower lip.",
28 | },
29 | noseBridge: {
30 | title: 'Nose Bridge',
31 | description: "The outline of the subject's nose bridge.",
32 | },
33 | rightEye: {
34 | title: 'Right Eye',
35 | description: "The outline of the subject's right eye cavity.",
36 | },
37 | rightEyebrowBottom: {
38 | title: 'Right Eyebrow Bottom',
39 | description: "The bottom outline of the subject's right eyebrow.",
40 | },
41 | rightEyebrowTop: {
42 | title: 'Right Eyebrow Top',
43 | description: "The top outline of the subject's right eyebrow.",
44 | },
45 | upperLipBottom: {
46 | title: 'Upper Lip Bottom',
47 | description: "The bottom outline of the subject's upper lip.",
48 | },
49 | upperLipTop: {
50 | title: 'Upper Lip Top',
51 | description: "The top outline of the subject's upper lip.",
52 | },
53 | };
54 |
55 | @Pipe({ name: 'keys', pure: false })
56 | export class KeysPipe implements PipeTransform {
57 | transform(value: any): any {
58 | return Object.keys(value);
59 | }
60 | }
61 |
62 | @Pipe({ name: 'contourTitle', pure: false })
63 | export class ContourTitlePipe implements PipeTransform {
64 | transform(contour: any): any {
65 | return contourType[contour].title;
66 | }
67 | }
68 |
69 | @Pipe({ name: 'contourDescription', pure: false })
70 | export class ContourDescriptionPipe implements PipeTransform {
71 | transform(contour: any): any {
72 | return contourType[contour].description;
73 | }
74 | }
75 |
76 | @Pipe({ name: 'contour', pure: false })
77 | export class ContourPipe implements PipeTransform {
78 | transform(contours: Contours, contour: any): FaceMeshPoint[] {
79 | return contours[contour as keyof Contours]!;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/app/modules/translation/translation.page.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { UntypedFormControl, UntypedFormGroup } from '@angular/forms';
3 | import { Language, Translation } from '@capacitor-mlkit/translation';
4 |
5 | @Component({
6 | selector: 'app-translation',
7 | templateUrl: './translation.page.html',
8 | styleUrls: ['./translation.page.scss'],
9 | })
10 | export class TranslationPage implements OnInit {
11 | public readonly language = Language;
12 | public translateFormGroup = new UntypedFormGroup({
13 | text: new UntypedFormControl(''),
14 | sourceLanguage: new UntypedFormControl(Language.English),
15 | targetLanguage: new UntypedFormControl(Language.German),
16 | translatedText: new UntypedFormControl(''),
17 | });
18 | public manageModelsFormGroup = new UntypedFormGroup({
19 | languages: new UntypedFormControl([]),
20 | });
21 | public disableSaveModelsButton = false;
22 |
23 | private readonly githubUrl =
24 | 'https://github.com/capawesome-team/capacitor-mlkit';
25 |
26 | constructor() {}
27 |
28 | public ngOnInit(): void {
29 | this.getDownloadedModels();
30 | }
31 |
32 | public openOnGithub(): void {
33 | window.open(this.githubUrl, '_blank');
34 | }
35 |
36 | public async saveModels(): Promise {
37 | this.disableSaveModelsButton = true;
38 | const languages: Language[] =
39 | this.manageModelsFormGroup.get('languages')?.value;
40 | if (!languages) {
41 | return;
42 | }
43 | for (const availableLanguage of Object.values(Language)) {
44 | if (languages.includes(availableLanguage)) {
45 | await Translation.downloadModel({ language: availableLanguage });
46 | } else {
47 | await Translation.deleteDownloadedModel({
48 | language: availableLanguage,
49 | });
50 | }
51 | }
52 | this.disableSaveModelsButton = false;
53 | }
54 |
55 | public async getDownloadedModels(): Promise {
56 | const { languages } = await Translation.getDownloadedModels();
57 | this.manageModelsFormGroup.patchValue({ languages });
58 | }
59 |
60 | public async translate(): Promise {
61 | const text = this.translateFormGroup.get('text')?.value;
62 | const sourceLanguage = this.translateFormGroup.get('sourceLanguage')?.value;
63 | const targetLanguage = this.translateFormGroup.get('targetLanguage')?.value;
64 | if (!text || !sourceLanguage || !targetLanguage) {
65 | return;
66 | }
67 | const result = await Translation.translate({
68 | text,
69 | sourceLanguage,
70 | targetLanguage,
71 | });
72 | this.translateFormGroup.patchValue({ translatedText: result.text });
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/app/modules/subject-segmentation/subject-segmentation.page.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ML Kit Subject Segmentation
7 |
8 |
9 |
10 |
11 |
12 |
13 | About
14 |
15 |
16 | ⚡️ Capacitor plugin for ML Kit Subject Segmentation.
17 |
18 |
19 |
20 | GitHub
26 |
27 |
28 |
29 |
30 |
31 | Demo
32 |
33 |
34 |
61 |
62 |
63 | @if (result) {
64 |
65 |
66 |
67 |
68 | Width
69 |
70 |
71 |
72 | Height
73 |
74 |
75 |
76 |
77 | }
78 |
79 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "capacitor-mlkit-plugin-demo",
3 | "version": "0.0.1",
4 | "author": "Robin Genz ",
5 | "homepage": "https://github.com/robingenz/capacitor-mlkit-plugin-demo",
6 | "scripts": {
7 | "ng": "ng",
8 | "start": "ng serve",
9 | "build": "ng build --configuration production",
10 | "test": "ng test",
11 | "test:ci": "ng test --watch=false --progress=false --code-coverage --browsers=HeadlessChrome",
12 | "lint": "ng lint && npm run prettier -- --check",
13 | "fmt": "ng lint --fix && npm run prettier -- --write",
14 | "prettier": "prettier \"{src,e2e/src}/**/*.{css,scss,html,ts,js}\""
15 | },
16 | "private": true,
17 | "dependencies": {
18 | "@angular/common": "17.0.8",
19 | "@angular/core": "17.0.8",
20 | "@angular/forms": "17.0.8",
21 | "@angular/platform-browser": "17.0.8",
22 | "@angular/platform-browser-dynamic": "17.0.8",
23 | "@angular/router": "17.0.8",
24 | "@capacitor-mlkit/barcode-scanning": "dev",
25 | "@capacitor-mlkit/document-scanner": "dev",
26 | "@capacitor-mlkit/face-detection": "dev",
27 | "@capacitor-mlkit/face-mesh-detection": "dev",
28 | "@capacitor-mlkit/selfie-segmentation": "dev",
29 | "@capacitor-mlkit/subject-segmentation": "dev",
30 | "@capacitor-mlkit/translation": "dev",
31 | "@capacitor/android": "^8.0.0",
32 | "@capacitor/app": "^8.0.0",
33 | "@capacitor/core": "^8.0.0",
34 | "@capacitor/haptics": "^8.0.0",
35 | "@capacitor/ios": "^8.0.0",
36 | "@capacitor/keyboard": "^8.0.0",
37 | "@capacitor/status-bar": "^8.0.0",
38 | "@capawesome/capacitor-file-picker": "dev",
39 | "@ionic/angular": "6.2.9",
40 | "barcode-detector": "3.0.5",
41 | "rxjs": "7.5.7",
42 | "tslib": "2.4.0",
43 | "zone.js": "0.14.2"
44 | },
45 | "devDependencies": {
46 | "@angular-devkit/build-angular": "17.0.8",
47 | "@angular-eslint/builder": "17.1.1",
48 | "@angular-eslint/eslint-plugin": "17.1.1",
49 | "@angular-eslint/eslint-plugin-template": "17.1.1",
50 | "@angular-eslint/template-parser": "17.1.1",
51 | "@angular/cli": "17.0.8",
52 | "@angular/compiler": "17.0.8",
53 | "@angular/compiler-cli": "17.0.8",
54 | "@angular/language-service": "17.0.8",
55 | "@capacitor/cli": "^8.0.0",
56 | "@ionic/angular-toolkit": "7.0.0",
57 | "@ionic/cli": "6.18.0",
58 | "@types/jasmine": "4.3.0",
59 | "@types/jasminewd2": "2.0.10",
60 | "@types/node": "20.10.5",
61 | "@typescript-eslint/eslint-plugin": "6.16.0",
62 | "@typescript-eslint/parser": "6.16.0",
63 | "eslint": "8.21.0",
64 | "jasmine-core": "4.4.0",
65 | "jasmine-spec-reporter": "7.0.0",
66 | "karma": "6.4.1",
67 | "karma-chrome-launcher": "3.1.1",
68 | "karma-coverage": "2.2.0",
69 | "karma-coverage-istanbul-reporter": "3.0.3",
70 | "karma-jasmine": "5.1.0",
71 | "karma-jasmine-html-reporter": "2.0.0",
72 | "prettier": "3.1.1",
73 | "puppeteer": "18.0.5",
74 | "ts-node": "10.9.1",
75 | "typescript": "5.2.2"
76 | },
77 | "description": "Simple Ionic Angular app to demonstrate the use of certain Capacitor ML Kit plugins."
78 | }
--------------------------------------------------------------------------------
/src/app/modules/translation/translation.page.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ML Kit Translation
7 |
8 |
9 |
10 |
11 |
12 |
13 | About
14 |
15 |
16 | ⚡️ Capacitor plugin for ML Kit Translation.
17 |
18 |
19 |
20 | GitHub
26 |
27 |
28 |
29 |
30 |
31 | Translate
32 |
33 |
34 |
68 | Translate
69 |
70 |
71 |
72 |
73 | Manage Models
74 |
75 |
76 |
88 | Save
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 | @rem SPDX-License-Identifier: Apache-2.0
17 | @rem
18 |
19 | @if "%DEBUG%"=="" @echo off
20 | @rem ##########################################################################
21 | @rem
22 | @rem Gradle startup script for Windows
23 | @rem
24 | @rem ##########################################################################
25 |
26 | @rem Set local scope for the variables with windows NT shell
27 | if "%OS%"=="Windows_NT" setlocal
28 |
29 | set DIRNAME=%~dp0
30 | if "%DIRNAME%"=="" set DIRNAME=.
31 | @rem This is normally unused
32 | set APP_BASE_NAME=%~n0
33 | set APP_HOME=%DIRNAME%
34 |
35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
37 |
38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
40 |
41 | @rem Find java.exe
42 | if defined JAVA_HOME goto findJavaFromJavaHome
43 |
44 | set JAVA_EXE=java.exe
45 | %JAVA_EXE% -version >NUL 2>&1
46 | if %ERRORLEVEL% equ 0 goto execute
47 |
48 | echo. 1>&2
49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
50 | echo. 1>&2
51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
52 | echo location of your Java installation. 1>&2
53 |
54 | goto fail
55 |
56 | :findJavaFromJavaHome
57 | set JAVA_HOME=%JAVA_HOME:"=%
58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
59 |
60 | if exist "%JAVA_EXE%" goto execute
61 |
62 | echo. 1>&2
63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
64 | echo. 1>&2
65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
66 | echo location of your Java installation. 1>&2
67 |
68 | goto fail
69 |
70 | :execute
71 | @rem Setup the command line
72 |
73 | set CLASSPATH=
74 |
75 |
76 | @rem Execute Gradle
77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
78 |
79 | :end
80 | @rem End local scope for the variables with windows NT shell
81 | if %ERRORLEVEL% equ 0 goto mainEnd
82 |
83 | :fail
84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
85 | rem the _cmd.exe /c_ return code!
86 | set EXIT_CODE=%ERRORLEVEL%
87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
89 | exit /b %EXIT_CODE%
90 |
91 | :mainEnd
92 | if "%OS%"=="Windows_NT" endlocal
93 |
94 | :omega
95 |
--------------------------------------------------------------------------------
/src/app/modules/face-detection/face-detection.page.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { UntypedFormControl, UntypedFormGroup } from '@angular/forms';
3 | import {
4 | ClassificationMode,
5 | ContourMode,
6 | ContourType,
7 | Face,
8 | FaceDetection,
9 | LandmarkMode,
10 | LandmarkType,
11 | PerformanceMode,
12 | Point,
13 | } from '@capacitor-mlkit/face-detection';
14 | import { FilePicker } from '@capawesome/capacitor-file-picker';
15 |
16 | @Component({
17 | selector: 'app-face-detection',
18 | templateUrl: './face-detection.page.html',
19 | styleUrls: ['./face-detection.page.scss'],
20 | })
21 | export class FaceDetectionPage implements OnInit {
22 | public readonly performanceMode = PerformanceMode;
23 |
24 | public readonly contourMode = ContourMode;
25 | public readonly landmarkMode = LandmarkMode;
26 |
27 | public readonly classificationMode = ClassificationMode;
28 |
29 | public formGroup = new UntypedFormGroup({
30 | performanceMode: new UntypedFormControl(PerformanceMode.Fast),
31 |
32 | contourMode: new UntypedFormControl(ContourMode.None),
33 | landmarkMode: new UntypedFormControl(LandmarkMode.None),
34 |
35 | classificationMode: new UntypedFormControl(ClassificationMode.None),
36 |
37 | minFaceSize: new UntypedFormControl(1),
38 | enableTracking: new UntypedFormControl(false),
39 | });
40 |
41 | pinFormatter(value: number) {
42 | return `${value / 10.0}`;
43 | }
44 |
45 | public faces: Face[] = [];
46 |
47 | private readonly githubUrl =
48 | 'https://github.com/capawesome-team/capacitor-mlkit';
49 |
50 | constructor() {}
51 |
52 | public ngOnInit(): void {
53 | return;
54 | }
55 |
56 | public openOnGithub(): void {
57 | window.open(this.githubUrl, '_blank');
58 | }
59 |
60 | public async processImage(): Promise {
61 | const { files } = await FilePicker.pickImages({ limit: 1 });
62 | const path = files[0]?.path;
63 | if (!path) {
64 | return;
65 | }
66 |
67 | const performanceMode = this.formGroup.get('performanceMode')?.value;
68 |
69 | const contourMode = this.formGroup.get('contourMode')?.value;
70 | const landmarkMode = this.formGroup.get('landmarkMode')?.value;
71 |
72 | const classificationMode = this.formGroup.get('classificationMode')?.value;
73 |
74 | const minFaceSize = this.formGroup.get('minFaceSize')?.value;
75 | const enableTracking = this.formGroup.get('enableTracking')?.value;
76 |
77 | const { faces } = await FaceDetection.processImage({
78 | path,
79 |
80 | performanceMode: performanceMode,
81 |
82 | contourMode: contourMode,
83 | landmarkMode: landmarkMode,
84 |
85 | classificationMode: classificationMode,
86 |
87 | minFaceSize: minFaceSize / 10.0,
88 | enableTracking: enableTracking,
89 | });
90 | this.faces = faces;
91 | }
92 |
93 | public getLandmarkType(type: LandmarkType) {
94 | return LandmarkType[type];
95 | }
96 | public getContourType(type: ContourType) {
97 | return ContourType[type];
98 | }
99 | public getPoint(point: Point) {
100 | return `(${point.x}, ${point.y})`;
101 | }
102 | public getPoints(points: Point[]) {
103 | const $ = [];
104 | for (const point of points) {
105 | $.push(this.getPoint(point));
106 | }
107 | return $.join(', ');
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/ios/App/App/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Capacitor
3 |
4 | @UIApplicationMain
5 | class AppDelegate: UIResponder, UIApplicationDelegate {
6 |
7 | var window: UIWindow?
8 |
9 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
10 | // Override point for customization after application launch.
11 | return true
12 | }
13 |
14 | func applicationWillResignActive(_ application: UIApplication) {
15 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
16 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
17 | }
18 |
19 | func applicationDidEnterBackground(_ application: UIApplication) {
20 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
21 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
22 | }
23 |
24 | func applicationWillEnterForeground(_ application: UIApplication) {
25 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
26 | }
27 |
28 | func applicationDidBecomeActive(_ application: UIApplication) {
29 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
30 | }
31 |
32 | func applicationWillTerminate(_ application: UIApplication) {
33 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
34 | }
35 |
36 | func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
37 | // Called when the app was launched with a url. Feel free to add additional processing here,
38 | // but if you want the App API to support tracking app url opens, make sure to keep this call
39 | return ApplicationDelegateProxy.shared.application(app, open: url, options: options)
40 | }
41 |
42 | func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
43 | // Called when the app was launched with an activity, including Universal Links.
44 | // Feel free to add additional processing here, but if you want the App API to support
45 | // tracking app url opens, make sure to keep this call
46 | return ApplicationDelegateProxy.shared.application(application, continue: userActivity, restorationHandler: restorationHandler)
47 | }
48 |
49 | func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
50 | NotificationCenter.default.post(name: .capacitorDidRegisterForRemoteNotifications, object: deviceToken)
51 | }
52 |
53 | func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
54 | NotificationCenter.default.post(name: .capacitorDidFailToRegisterForRemoteNotifications, object: error)
55 | }
56 |
57 | func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
58 | NotificationCenter.default.post(name: Notification.Name.init("didReceiveRemoteNotification"), object: completionHandler, userInfo: userInfo)
59 | }
60 |
61 |
62 | }
63 |
64 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | paths-ignore:
8 | - "**.md"
9 | pull_request:
10 | paths-ignore:
11 | - "**.md"
12 | workflow_dispatch:
13 |
14 | env:
15 | NODE_VERSION: 22
16 | JAVA_VERSION: 21
17 |
18 | jobs:
19 | build:
20 | name: Build web assets
21 | runs-on: ubuntu-latest
22 | steps:
23 | - name: Checkout
24 | uses: actions/checkout@v4
25 | - name: Set up Node.js ${{ env.NODE_VERSION }}
26 | uses: actions/setup-node@v4
27 | with:
28 | node-version: ${{ env.NODE_VERSION }}
29 | - name: Install Node.js dependencies
30 | run: npm ci
31 | - name: Build web assets
32 | run: npm run build
33 | - name: Upload artifacts
34 | uses: actions/upload-artifact@v4
35 | with:
36 | name: www
37 | path: www
38 | android:
39 | name: Build Android platform
40 | runs-on: ubuntu-latest
41 | needs: [build]
42 | steps:
43 | - name: Checkout
44 | uses: actions/checkout@v4
45 | - name: Download artifacts
46 | uses: actions/download-artifact@v4
47 | with:
48 | name: www
49 | path: www
50 | - name: Set up Node.js ${{ env.NODE_VERSION }}
51 | uses: actions/setup-node@v4
52 | with:
53 | node-version: ${{ env.NODE_VERSION }}
54 | - name: Set up JDK ${{ env.JAVA_VERSION }}
55 | uses: actions/setup-java@v4
56 | with:
57 | distribution: "zulu"
58 | java-version: ${{ env.JAVA_VERSION }}
59 | - name: Install dependencies
60 | run: npm ci
61 | - name: Copy web assets to native platform
62 | run: npx ionic capacitor copy android --no-build
63 | - name: Update native platform
64 | run: npx ionic capacitor update android
65 | - name: Build with Gradle
66 | working-directory: android
67 | run: ./gradlew build
68 | - name: Upload artifacts
69 | uses: actions/upload-artifact@v4
70 | with:
71 | name: android
72 | path: android/app/build/outputs/apk/debug
73 | ios:
74 | name: Build iOS platform
75 | runs-on: macos-14
76 | needs: [build]
77 | steps:
78 | - name: Checkout
79 | uses: actions/checkout@v4
80 | - name: Download artifacts
81 | uses: actions/download-artifact@v4
82 | with:
83 | name: www
84 | path: www
85 | - name: Set up Node.js ${{ env.NODE_VERSION }}
86 | uses: actions/setup-node@v4
87 | with:
88 | node-version: ${{ env.NODE_VERSION }}
89 | - name: Install Node.js dependencies
90 | run: npm ci
91 | - name: Copy web assets to native platform
92 | run: npx ionic capacitor copy ios --no-build
93 | - name: Update native platform
94 | run: npx ionic capacitor update ios
95 | - name: Build and archive with xcodebuild
96 | working-directory: ios
97 | run: xcodebuild
98 | -workspace App/App.xcworkspace
99 | -scheme App
100 | -archivePath App/build/App.xarchive
101 | clean build archive
102 | CODE_SIGN_IDENTITY=""
103 | CODE_SIGNING_REQUIRED=NO
104 | CODE_SIGNING_ALLOWED="NO"
105 | CODE_SIGN_ENTITLEMENTS=""
106 | lint:
107 | name: Lint
108 | runs-on: ubuntu-latest
109 | steps:
110 | - name: Checkout
111 | uses: actions/checkout@v4
112 | - name: Set up Node.js ${{ env.NODE_VERSION }}
113 | uses: actions/setup-node@v4
114 | with:
115 | node-version: ${{ env.NODE_VERSION }}
116 | - name: Install Node.js dependencies
117 | run: npm ci
118 | - name: Run ESLint and Prettier
119 | run: npm run lint
120 | test:
121 | name: Test
122 | runs-on: ubuntu-latest
123 | if: false
124 | steps:
125 | - name: Checkout
126 | uses: actions/checkout@v4
127 | - name: Set up Node.js ${{ env.NODE_VERSION }}
128 | uses: actions/setup-node@v4
129 | with:
130 | node-version: ${{ env.NODE_VERSION }}
131 | - name: Install dependencies
132 | run: npm ci
133 | - name: Run unit tests
134 | run: npm run test:ci
135 |
--------------------------------------------------------------------------------
/src/app/modules/document-scanner/document-scanner.page.ts:
--------------------------------------------------------------------------------
1 | import { Component, NgZone, OnInit } from '@angular/core';
2 | import { UntypedFormControl, UntypedFormGroup } from '@angular/forms';
3 | import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
4 | import {
5 | DocumentScanner,
6 | ScanOptions,
7 | ScanResult,
8 | GoogleDocumentScannerModuleInstallState,
9 | GoogleDocumentScannerModuleInstallProgressEvent,
10 | } from '@capacitor-mlkit/document-scanner';
11 | import { Capacitor } from '@capacitor/core';
12 |
13 | @Component({
14 | selector: 'app-document-scanner',
15 | templateUrl: './document-scanner.page.html',
16 | styleUrls: ['./document-scanner.page.scss'],
17 | })
18 | export class DocumentScannerPage implements OnInit {
19 | public readonly scannerMode = {
20 | FULL: 'FULL',
21 | BASE: 'BASE',
22 | BASE_WITH_FILTER: 'BASE_WITH_FILTER',
23 | };
24 |
25 | public readonly resultFormats = {
26 | JPEG: 'JPEG',
27 | PDF: 'PDF',
28 | JPEG_PDF: 'JPEG_PDF',
29 | };
30 |
31 | public readonly installState = GoogleDocumentScannerModuleInstallState;
32 |
33 | public formGroup = new UntypedFormGroup({
34 | galleryImportAllowed: new UntypedFormControl(false),
35 | pageLimit: new UntypedFormControl(10),
36 | resultFormats: new UntypedFormControl('JPEG_PDF'),
37 | scannerMode: new UntypedFormControl('FULL'),
38 | googleDocumentScannerModuleInstallState: new UntypedFormControl(0),
39 | googleDocumentScannerModuleInstallProgress: new UntypedFormControl(0),
40 | });
41 |
42 | public scanResult: ScanResult | null = null;
43 | public isModuleAvailable = false;
44 |
45 | private readonly GH_URL =
46 | 'https://github.com/capawesome-team/capacitor-mlkit';
47 |
48 | constructor(
49 | private readonly domSanitizer: DomSanitizer,
50 | private readonly ngZone: NgZone,
51 | ) {}
52 |
53 | public ngOnInit(): void {
54 | this.checkModuleAvailability();
55 | this.setupEventListener();
56 | }
57 |
58 | public async scanDocument(): Promise {
59 | const options: ScanOptions = {
60 | galleryImportAllowed:
61 | this.formGroup.get('galleryImportAllowed')?.value || false,
62 | pageLimit: this.formGroup.get('pageLimit')?.value || 10,
63 | resultFormats: this.formGroup.get('resultFormats')?.value || 'JPEG_PDF',
64 | scannerMode: this.formGroup.get('scannerMode')?.value || 'FULL',
65 | };
66 |
67 | try {
68 | const result = await DocumentScanner.scanDocument(options);
69 | this.scanResult = result;
70 | } catch (error) {
71 | console.error('Error scanning document:', error);
72 | }
73 | }
74 |
75 | public async checkModuleAvailability(): Promise {
76 | try {
77 | const result =
78 | await DocumentScanner.isGoogleDocumentScannerModuleAvailable();
79 | this.isModuleAvailable = result.available;
80 | } catch (error) {
81 | console.error('Error checking module availability:', error);
82 | this.isModuleAvailable = false;
83 | }
84 | }
85 |
86 | public async installGoogleDocumentScannerModule(): Promise {
87 | try {
88 | await DocumentScanner.installGoogleDocumentScannerModule();
89 | } catch (error) {
90 | console.error('Error installing module:', error);
91 | }
92 | }
93 |
94 | public openOnGithub(): void {
95 | window.open(this.GH_URL, '_blank');
96 | }
97 |
98 | public convertPathToWebPath(path: string): SafeUrl {
99 | const fileSrc = Capacitor.convertFileSrc(path);
100 | return this.domSanitizer.bypassSecurityTrustUrl(fileSrc);
101 | }
102 |
103 | private setupEventListener(): void {
104 | DocumentScanner.removeAllListeners().then(() => {
105 | DocumentScanner.addListener(
106 | 'googleDocumentScannerModuleInstallProgress',
107 | (event: GoogleDocumentScannerModuleInstallProgressEvent) => {
108 | this.ngZone.run(() => {
109 | console.log('googleDocumentScannerModuleInstallProgress', event);
110 | const { state, progress } = event;
111 | this.formGroup.patchValue({
112 | googleDocumentScannerModuleInstallState: state,
113 | googleDocumentScannerModuleInstallProgress: progress,
114 | });
115 | });
116 | },
117 | );
118 | });
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/src/app/modules/barcode-scanning/barcode-scanning.page.ts:
--------------------------------------------------------------------------------
1 | import { Component, NgZone, OnInit } from '@angular/core';
2 | import { UntypedFormControl, UntypedFormGroup } from '@angular/forms';
3 | import { DialogService } from '@app/core';
4 | import {
5 | Barcode,
6 | BarcodeFormat,
7 | BarcodeScanner,
8 | LensFacing,
9 | } from '@capacitor-mlkit/barcode-scanning';
10 | import { FilePicker } from '@capawesome/capacitor-file-picker';
11 | import { BarcodeScanningModalComponent } from './barcode-scanning-modal.component';
12 |
13 | @Component({
14 | selector: 'app-barcode-scanning',
15 | templateUrl: './barcode-scanning.page.html',
16 | styleUrls: ['./barcode-scanning.page.scss'],
17 | })
18 | export class BarcodeScanningPage implements OnInit {
19 | public readonly barcodeFormat = BarcodeFormat;
20 | public readonly lensFacing = LensFacing;
21 |
22 | public formGroup = new UntypedFormGroup({
23 | formats: new UntypedFormControl([]),
24 | lensFacing: new UntypedFormControl(LensFacing.Back),
25 | googleBarcodeScannerModuleInstallState: new UntypedFormControl(0),
26 | googleBarcodeScannerModuleInstallProgress: new UntypedFormControl(0),
27 | });
28 | public barcodes: Barcode[] = [];
29 | public isSupported = false;
30 | public isPermissionGranted = false;
31 |
32 | private readonly GH_URL =
33 | 'https://github.com/capawesome-team/capacitor-barcode-scanning';
34 |
35 | constructor(
36 | private readonly dialogService: DialogService,
37 | private readonly ngZone: NgZone,
38 | ) {}
39 |
40 | public ngOnInit(): void {
41 | BarcodeScanner.isSupported().then((result) => {
42 | this.isSupported = result.supported;
43 | });
44 | BarcodeScanner.checkPermissions().then((result) => {
45 | this.isPermissionGranted = result.camera === 'granted';
46 | });
47 | BarcodeScanner.removeAllListeners().then(() => {
48 | BarcodeScanner.addListener(
49 | 'googleBarcodeScannerModuleInstallProgress',
50 | (event) => {
51 | this.ngZone.run(() => {
52 | console.log('googleBarcodeScannerModuleInstallProgress', event);
53 | const { state, progress } = event;
54 | this.formGroup.patchValue({
55 | googleBarcodeScannerModuleInstallState: state,
56 | googleBarcodeScannerModuleInstallProgress: progress,
57 | });
58 | });
59 | },
60 | );
61 | });
62 | }
63 |
64 | public async startScan(): Promise {
65 | const formats = this.formGroup.get('formats')?.value || [];
66 | const lensFacing =
67 | this.formGroup.get('lensFacing')?.value || LensFacing.Back;
68 | const element = await this.dialogService.showModal({
69 | component: BarcodeScanningModalComponent,
70 | // Set `visibility` to `visible` to show the modal (see `src/theme/variables.scss`)
71 | cssClass: 'barcode-scanning-modal',
72 | showBackdrop: false,
73 | componentProps: {
74 | formats: formats,
75 | lensFacing: lensFacing,
76 | },
77 | });
78 | element.onDidDismiss().then((result) => {
79 | const barcode: Barcode | undefined = result.data?.barcode;
80 | if (barcode) {
81 | this.barcodes = [barcode];
82 | }
83 | });
84 | }
85 |
86 | public async readBarcodeFromImage(): Promise {
87 | const { files } = await FilePicker.pickImages({ limit: 1 });
88 | const path = files[0]?.path;
89 | if (!path) {
90 | return;
91 | }
92 | const formats = this.formGroup.get('formats')?.value || [];
93 | const { barcodes } = await BarcodeScanner.readBarcodesFromImage({
94 | path,
95 | formats,
96 | });
97 | this.barcodes = barcodes;
98 | }
99 |
100 | public async scan(): Promise {
101 | const formats = this.formGroup.get('formats')?.value || [];
102 | const { barcodes } = await BarcodeScanner.scan({
103 | formats,
104 | });
105 | this.barcodes = barcodes;
106 | }
107 |
108 | public async openSettings(): Promise {
109 | await BarcodeScanner.openSettings();
110 | }
111 |
112 | public async installGoogleBarcodeScannerModule(): Promise {
113 | await BarcodeScanner.installGoogleBarcodeScannerModule();
114 | }
115 |
116 | public async requestPermissions(): Promise {
117 | await BarcodeScanner.requestPermissions();
118 | }
119 |
120 | public openOnGithub(): void {
121 | window.open(this.GH_URL, '_blank');
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/angular.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 | "version": 1,
4 | "newProjectRoot": "projects",
5 | "projects": {
6 | "app": {
7 | "root": "",
8 | "sourceRoot": "src",
9 | "projectType": "application",
10 | "prefix": "app",
11 | "schematics": {},
12 | "architect": {
13 | "build": {
14 | "builder": "@angular-devkit/build-angular:browser",
15 | "options": {
16 | "outputPath": "www",
17 | "index": "src/index.html",
18 | "main": "src/main.ts",
19 | "polyfills": "src/polyfills.ts",
20 | "tsConfig": "tsconfig.app.json",
21 | "assets": [
22 | {
23 | "glob": "**/*",
24 | "input": "src/assets",
25 | "output": "assets"
26 | },
27 | {
28 | "glob": "**/*.svg",
29 | "input": "node_modules/ionicons/dist/ionicons/svg",
30 | "output": "./svg"
31 | }
32 | ],
33 | "styles": ["src/theme/variables.scss", "src/global.scss"],
34 | "scripts": [],
35 | "aot": false,
36 | "vendorChunk": true,
37 | "extractLicenses": false,
38 | "buildOptimizer": false,
39 | "sourceMap": true,
40 | "optimization": false,
41 | "namedChunks": true
42 | },
43 | "configurations": {
44 | "production": {
45 | "fileReplacements": [
46 | {
47 | "replace": "src/environments/environment.ts",
48 | "with": "src/environments/environment.prod.ts"
49 | }
50 | ],
51 | "optimization": true,
52 | "outputHashing": "all",
53 | "sourceMap": false,
54 | "namedChunks": false,
55 | "aot": true,
56 | "extractLicenses": true,
57 | "vendorChunk": false,
58 | "buildOptimizer": true,
59 | "budgets": [
60 | {
61 | "type": "initial",
62 | "maximumWarning": "2mb",
63 | "maximumError": "5mb"
64 | }
65 | ]
66 | },
67 | "ci": {
68 | "progress": false
69 | }
70 | }
71 | },
72 | "serve": {
73 | "builder": "@angular-devkit/build-angular:dev-server",
74 | "options": {
75 | "buildTarget": "app:build"
76 | },
77 | "configurations": {
78 | "production": {
79 | "buildTarget": "app:build:production"
80 | },
81 | "ci": {}
82 | }
83 | },
84 | "extract-i18n": {
85 | "builder": "@angular-devkit/build-angular:extract-i18n",
86 | "options": {
87 | "buildTarget": "app:build"
88 | }
89 | },
90 | "test": {
91 | "builder": "@angular-devkit/build-angular:karma",
92 | "options": {
93 | "main": "src/test.ts",
94 | "polyfills": "src/polyfills.ts",
95 | "tsConfig": "tsconfig.spec.json",
96 | "karmaConfig": "karma.conf.js",
97 | "styles": [],
98 | "scripts": [],
99 | "assets": [
100 | {
101 | "glob": "favicon.ico",
102 | "input": "src/",
103 | "output": "/"
104 | },
105 | {
106 | "glob": "**/*",
107 | "input": "src/assets",
108 | "output": "/assets"
109 | }
110 | ]
111 | },
112 | "configurations": {
113 | "ci": {
114 | "progress": false,
115 | "watch": false
116 | }
117 | }
118 | },
119 | "lint": {
120 | "builder": "@angular-eslint/builder:lint",
121 | "options": {
122 | "lintFilePatterns": ["src/**/*.ts", "src/**/*.html"]
123 | }
124 | },
125 | "ionic-cordova-build": {
126 | "builder": "@ionic/angular-toolkit:cordova-build",
127 | "options": {
128 | "browserTarget": "app:build"
129 | },
130 | "configurations": {
131 | "production": {
132 | "browserTarget": "app:build:production"
133 | }
134 | }
135 | },
136 | "ionic-cordova-serve": {
137 | "builder": "@ionic/angular-toolkit:cordova-serve",
138 | "options": {
139 | "cordovaBuildTarget": "app:ionic-cordova-build",
140 | "devServerTarget": "app:serve"
141 | },
142 | "configurations": {
143 | "production": {
144 | "cordovaBuildTarget": "app:ionic-cordova-build:production",
145 | "devServerTarget": "app:serve:production"
146 | }
147 | }
148 | }
149 | }
150 | }
151 | },
152 | "cli": {
153 | "schematicCollections": ["@ionic/angular-toolkit"],
154 | "analytics": false
155 | },
156 | "schematics": {
157 | "@ionic/angular-toolkit:component": {
158 | "styleext": "scss"
159 | },
160 | "@ionic/angular-toolkit:page": {
161 | "styleext": "scss"
162 | }
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/src/app/modules/face-mesh-detection/face-mesh-detection.page.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ML Kit Face Mesh Detection
7 |
8 |
9 |
10 |
11 |
12 |
13 | About
14 |
15 |
16 | ⚡️ Capacitor plugin for ML Kit Face Mesh Detection.
17 |
18 |
19 |
20 | GitHub
26 |
27 |
28 |
29 |
30 |
31 | Face Mesh Detection
32 |
33 |
34 |
48 |
49 |
50 | @for (faceMesh of faceMeshs; track faceMesh; let i = $index) {
51 |
52 |
53 | Face Mesh #{{ i+1 }}
54 |
55 |
56 |
57 |
58 | Bounds
59 |
60 |
61 |
62 | Top
63 |
68 |
69 |
70 | Left
71 |
76 |
77 |
78 | Bottom
79 |
84 |
85 |
86 | Right
87 |
92 |
93 |
94 |
95 |
96 | @if (faceMesh.contours) {
97 |
98 |
99 |
100 | Contours
101 |
102 | Represents a list of face mesh points for each specific contour
103 |
104 |
105 |
106 | @for (contourType of faceMesh.contours | keys; track contourType) {
107 |
108 |
109 |
110 | {{ contourType | contourTitle }}
113 |
114 | {{ contourType | contourDescription }}
115 |
116 |
117 | @for (faceMeshPoint of faceMesh.contours | contour:contourType;
118 | track faceMeshPoint) {
119 |
120 |
121 | #{{ faceMeshPoint.index }}
124 |
129 |
130 |
131 | }
132 |
133 |
134 | }
135 |
136 |
137 |
138 | } @if (faceMesh.faceMeshPoints) {
139 |
140 |
141 |
142 | Face Mesh Points
143 |
144 | Represents a 3D point in face mesh
145 |
146 |
147 | @for (faceMeshPoint of faceMesh.faceMeshPoints; track faceMeshPoint) {
148 |
149 |
150 | #{{ faceMeshPoint.index }}
151 |
156 |
157 |
158 | }
159 |
160 |
161 | }
162 |
163 | }
164 |
165 |
--------------------------------------------------------------------------------
/src/app/modules/document-scanner/document-scanner.page.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Document Scanner
7 |
8 |
9 |
10 |
11 |
12 |
13 | About
14 |
15 |
16 | ⚡️ Capacitor plugin for scanning documents using ML Kit Document Scanner.
17 |
18 |
19 |
20 | GitHub
26 |
27 |
28 |
29 |
30 |
31 |
32 | Demo
33 |
34 |
35 |
119 |
120 |
121 |
122 | @if (scanResult) {
123 |
124 |
125 | Scan Result
126 |
127 |
128 | @if (scanResult.scannedImages && scanResult.scannedImages.length > 0) {
129 |
130 | Scanned Images
131 |
136 |
137 | @for (image of scanResult.scannedImages; track image; let i = $index) {
138 |
139 |
140 |
145 |
146 |
147 | Image {{ i + 1 }}
148 | {{ image }}
149 |
150 |
151 | } } @if (scanResult.pdf) {
152 |
153 | PDF URI
154 |
160 |
161 |
162 | PDF Page Count
163 |
168 |
169 | }
170 |
171 |
172 | }
173 |
174 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/src/app/modules/barcode-scanning/barcode-scanning.page.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Barcode Scanning
7 |
8 |
9 |
10 |
11 |
12 |
13 | About
14 |
15 |
16 | ⚡️ Capacitor plugin for scanning barcodes and QR codes.
17 |
18 |
19 |
20 | GitHub
26 |
27 |
28 |
29 |
30 |
31 | Demo
32 |
33 |
34 |
148 |
149 |
150 | @for (barcode of barcodes; track barcode) {
151 |
152 |
153 |
154 | Bytes
155 |
160 |
161 |
162 | Corner Points
163 |
168 |
169 |
170 | Display Value
171 |
176 |
177 |
178 | Format
179 |
180 |
181 |
182 | Raw Value
183 |
184 |
185 |
186 | Value Type
187 |
188 |
189 |
190 |
191 | }
192 |
193 |
--------------------------------------------------------------------------------
/src/app/modules/barcode-scanning/barcode-scanning-modal.component.ts:
--------------------------------------------------------------------------------
1 | import {
2 | AfterViewInit,
3 | Component,
4 | ElementRef,
5 | Input,
6 | NgZone,
7 | OnDestroy,
8 | ViewChild,
9 | } from '@angular/core';
10 | import { DialogService } from '@app/core';
11 | import {
12 | Barcode,
13 | BarcodeFormat,
14 | BarcodeScanner,
15 | LensFacing,
16 | StartScanOptions,
17 | } from '@capacitor-mlkit/barcode-scanning';
18 | import { Capacitor } from '@capacitor/core';
19 | import { InputCustomEvent } from '@ionic/angular';
20 |
21 | @Component({
22 | selector: 'app-barcode-scanning',
23 | template: `
24 |
25 |
26 | Scanning
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | @if (isWeb) {
37 |
38 | }
39 |
40 |
41 |
47 |
48 | @if (isTorchAvailable) {
49 |
50 |
51 |
52 |
53 |
54 | }
55 |
56 | `,
57 | styles: [
58 | `
59 | ion-content {
60 | --background: transparent;
61 | }
62 |
63 | .square {
64 | position: absolute;
65 | left: 50%;
66 | top: 50%;
67 | transform: translate(-50%, -50%);
68 | border-radius: 16px;
69 | width: 200px;
70 | height: 200px;
71 | border: 6px solid white;
72 | box-shadow: 0 0 0 4000px rgba(0, 0, 0, 0.3);
73 | }
74 |
75 | .video {
76 | position: absolute;
77 | left: 0;
78 | top: 0;
79 | width: 100%;
80 | height: 100%;
81 | object-fit: cover;
82 | }
83 |
84 | .zoom-ratio-wrapper {
85 | position: absolute;
86 | left: 50%;
87 | bottom: 16px;
88 | transform: translateX(-50%);
89 | width: 50%;
90 | }
91 | `,
92 | ],
93 | })
94 | export class BarcodeScanningModalComponent implements AfterViewInit, OnDestroy {
95 | @Input()
96 | public formats: BarcodeFormat[] = [];
97 | @Input()
98 | public lensFacing: LensFacing = LensFacing.Back;
99 |
100 | @ViewChild('square')
101 | public squareElement: ElementRef | undefined;
102 |
103 | @ViewChild('video')
104 | public videoElement: ElementRef | undefined;
105 |
106 | public isTorchAvailable = false;
107 | public isWeb = Capacitor.getPlatform() === 'web';
108 | public minZoomRatio: number | undefined;
109 | public maxZoomRatio: number | undefined;
110 |
111 | constructor(
112 | private readonly dialogService: DialogService,
113 | private readonly ngZone: NgZone,
114 | ) {}
115 |
116 | public ngAfterViewInit(): void {
117 | setTimeout(() => {
118 | this.startScan().then(() => {
119 | if (this.isWeb) {
120 | return;
121 | }
122 | BarcodeScanner.isTorchAvailable().then((result) => {
123 | this.isTorchAvailable = result.available;
124 | });
125 | });
126 | }, 500);
127 | }
128 |
129 | public ngOnDestroy(): void {
130 | this.stopScan();
131 | }
132 |
133 | public setZoomRatio(event: InputCustomEvent): void {
134 | if (!event.detail.value) {
135 | return;
136 | }
137 | BarcodeScanner.setZoomRatio({
138 | zoomRatio: parseInt(event.detail.value as any, 10),
139 | });
140 | }
141 |
142 | public async closeModal(barcode?: Barcode): Promise {
143 | this.dialogService.dismissModal({
144 | barcode: barcode,
145 | });
146 | }
147 |
148 | public async toggleTorch(): Promise {
149 | await BarcodeScanner.toggleTorch();
150 | }
151 |
152 | private async startScan(): Promise {
153 | // Hide everything behind the modal (see `src/theme/variables.scss`)
154 | document.querySelector('body')?.classList.add('barcode-scanning-active');
155 |
156 | const options: StartScanOptions = {
157 | formats: this.formats,
158 | lensFacing: this.lensFacing,
159 | videoElement:
160 | Capacitor.getPlatform() === 'web'
161 | ? this.videoElement?.nativeElement
162 | : undefined,
163 | };
164 |
165 | const squareElementBoundingClientRect =
166 | this.squareElement?.nativeElement.getBoundingClientRect();
167 | const scaledRect = squareElementBoundingClientRect
168 | ? {
169 | left: squareElementBoundingClientRect.left * window.devicePixelRatio,
170 | right:
171 | squareElementBoundingClientRect.right * window.devicePixelRatio,
172 | top: squareElementBoundingClientRect.top * window.devicePixelRatio,
173 | bottom:
174 | squareElementBoundingClientRect.bottom * window.devicePixelRatio,
175 | width:
176 | squareElementBoundingClientRect.width * window.devicePixelRatio,
177 | height:
178 | squareElementBoundingClientRect.height * window.devicePixelRatio,
179 | }
180 | : undefined;
181 | const detectionCornerPoints = scaledRect
182 | ? [
183 | [scaledRect.left, scaledRect.top],
184 | [scaledRect.left + scaledRect.width, scaledRect.top],
185 | [
186 | scaledRect.left + scaledRect.width,
187 | scaledRect.top + scaledRect.height,
188 | ],
189 | [scaledRect.left, scaledRect.top + scaledRect.height],
190 | ]
191 | : undefined;
192 | const listener = await BarcodeScanner.addListener(
193 | 'barcodesScanned',
194 | async (event) => {
195 | this.ngZone.run(() => {
196 | const firstBarcode = event.barcodes[0];
197 | if (!firstBarcode) {
198 | return;
199 | }
200 | const cornerPoints = firstBarcode.cornerPoints;
201 | if (
202 | detectionCornerPoints &&
203 | cornerPoints &&
204 | Capacitor.getPlatform() !== 'web'
205 | ) {
206 | if (
207 | detectionCornerPoints[0][0] > cornerPoints[0][0] ||
208 | detectionCornerPoints[0][1] > cornerPoints[0][1] ||
209 | detectionCornerPoints[1][0] < cornerPoints[1][0] ||
210 | detectionCornerPoints[1][1] > cornerPoints[1][1] ||
211 | detectionCornerPoints[2][0] < cornerPoints[2][0] ||
212 | detectionCornerPoints[2][1] < cornerPoints[2][1] ||
213 | detectionCornerPoints[3][0] > cornerPoints[3][0] ||
214 | detectionCornerPoints[3][1] < cornerPoints[3][1]
215 | ) {
216 | return;
217 | }
218 | }
219 | listener.remove();
220 | this.closeModal(firstBarcode);
221 | });
222 | },
223 | );
224 | await BarcodeScanner.startScan(options);
225 | if (Capacitor.getPlatform() !== 'web') {
226 | void BarcodeScanner.getMinZoomRatio().then((result) => {
227 | this.minZoomRatio = result.zoomRatio;
228 | });
229 | void BarcodeScanner.getMaxZoomRatio().then((result) => {
230 | this.maxZoomRatio = result.zoomRatio;
231 | });
232 | }
233 | }
234 |
235 | private async stopScan(): Promise {
236 | // Show everything behind the modal again
237 | document.querySelector('body')?.classList.remove('barcode-scanning-active');
238 |
239 | await BarcodeScanner.stopScan();
240 | }
241 | }
242 |
--------------------------------------------------------------------------------
/src/theme/variables.scss:
--------------------------------------------------------------------------------
1 | // Ionic Variables and Theming. For more info, please see:
2 | // http://ionicframework.com/docs/theming/
3 |
4 | /** Ionic CSS Variables **/
5 | :root {
6 | /** primary **/
7 | --ion-color-primary: #3880ff;
8 | --ion-color-primary-rgb: 56, 128, 255;
9 | --ion-color-primary-contrast: #ffffff;
10 | --ion-color-primary-contrast-rgb: 255, 255, 255;
11 | --ion-color-primary-shade: #3171e0;
12 | --ion-color-primary-tint: #4c8dff;
13 |
14 | /** secondary **/
15 | --ion-color-secondary: #3dc2ff;
16 | --ion-color-secondary-rgb: 61, 194, 255;
17 | --ion-color-secondary-contrast: #ffffff;
18 | --ion-color-secondary-contrast-rgb: 255, 255, 255;
19 | --ion-color-secondary-shade: #36abe0;
20 | --ion-color-secondary-tint: #50c8ff;
21 |
22 | /** tertiary **/
23 | --ion-color-tertiary: #5260ff;
24 | --ion-color-tertiary-rgb: 82, 96, 255;
25 | --ion-color-tertiary-contrast: #ffffff;
26 | --ion-color-tertiary-contrast-rgb: 255, 255, 255;
27 | --ion-color-tertiary-shade: #4854e0;
28 | --ion-color-tertiary-tint: #6370ff;
29 |
30 | /** success **/
31 | --ion-color-success: #2dd36f;
32 | --ion-color-success-rgb: 45, 211, 111;
33 | --ion-color-success-contrast: #ffffff;
34 | --ion-color-success-contrast-rgb: 255, 255, 255;
35 | --ion-color-success-shade: #28ba62;
36 | --ion-color-success-tint: #42d77d;
37 |
38 | /** warning **/
39 | --ion-color-warning: #ffc409;
40 | --ion-color-warning-rgb: 255, 196, 9;
41 | --ion-color-warning-contrast: #000000;
42 | --ion-color-warning-contrast-rgb: 0, 0, 0;
43 | --ion-color-warning-shade: #e0ac08;
44 | --ion-color-warning-tint: #ffca22;
45 |
46 | /** danger **/
47 | --ion-color-danger: #eb445a;
48 | --ion-color-danger-rgb: 235, 68, 90;
49 | --ion-color-danger-contrast: #ffffff;
50 | --ion-color-danger-contrast-rgb: 255, 255, 255;
51 | --ion-color-danger-shade: #cf3c4f;
52 | --ion-color-danger-tint: #ed576b;
53 |
54 | /** dark **/
55 | --ion-color-dark: #222428;
56 | --ion-color-dark-rgb: 34, 36, 40;
57 | --ion-color-dark-contrast: #ffffff;
58 | --ion-color-dark-contrast-rgb: 255, 255, 255;
59 | --ion-color-dark-shade: #1e2023;
60 | --ion-color-dark-tint: #383a3e;
61 |
62 | /** medium **/
63 | --ion-color-medium: #92949c;
64 | --ion-color-medium-rgb: 146, 148, 156;
65 | --ion-color-medium-contrast: #ffffff;
66 | --ion-color-medium-contrast-rgb: 255, 255, 255;
67 | --ion-color-medium-shade: #808289;
68 | --ion-color-medium-tint: #9d9fa6;
69 |
70 | /** light **/
71 | --ion-color-light: #f4f5f8;
72 | --ion-color-light-rgb: 244, 245, 248;
73 | --ion-color-light-contrast: #000000;
74 | --ion-color-light-contrast-rgb: 0, 0, 0;
75 | --ion-color-light-shade: #d7d8da;
76 | --ion-color-light-tint: #f5f6f9;
77 | }
78 |
79 | @media (prefers-color-scheme: dark) {
80 | /*
81 | * Dark Colors
82 | * -------------------------------------------
83 | */
84 |
85 | body {
86 | --ion-color-primary: #428cff;
87 | --ion-color-primary-rgb: 66, 140, 255;
88 | --ion-color-primary-contrast: #ffffff;
89 | --ion-color-primary-contrast-rgb: 255, 255, 255;
90 | --ion-color-primary-shade: #3a7be0;
91 | --ion-color-primary-tint: #5598ff;
92 |
93 | --ion-color-secondary: #50c8ff;
94 | --ion-color-secondary-rgb: 80, 200, 255;
95 | --ion-color-secondary-contrast: #ffffff;
96 | --ion-color-secondary-contrast-rgb: 255, 255, 255;
97 | --ion-color-secondary-shade: #46b0e0;
98 | --ion-color-secondary-tint: #62ceff;
99 |
100 | --ion-color-tertiary: #6a64ff;
101 | --ion-color-tertiary-rgb: 106, 100, 255;
102 | --ion-color-tertiary-contrast: #ffffff;
103 | --ion-color-tertiary-contrast-rgb: 255, 255, 255;
104 | --ion-color-tertiary-shade: #5d58e0;
105 | --ion-color-tertiary-tint: #7974ff;
106 |
107 | --ion-color-success: #2fdf75;
108 | --ion-color-success-rgb: 47, 223, 117;
109 | --ion-color-success-contrast: #000000;
110 | --ion-color-success-contrast-rgb: 0, 0, 0;
111 | --ion-color-success-shade: #29c467;
112 | --ion-color-success-tint: #44e283;
113 |
114 | --ion-color-warning: #ffd534;
115 | --ion-color-warning-rgb: 255, 213, 52;
116 | --ion-color-warning-contrast: #000000;
117 | --ion-color-warning-contrast-rgb: 0, 0, 0;
118 | --ion-color-warning-shade: #e0bb2e;
119 | --ion-color-warning-tint: #ffd948;
120 |
121 | --ion-color-danger: #ff4961;
122 | --ion-color-danger-rgb: 255, 73, 97;
123 | --ion-color-danger-contrast: #ffffff;
124 | --ion-color-danger-contrast-rgb: 255, 255, 255;
125 | --ion-color-danger-shade: #e04055;
126 | --ion-color-danger-tint: #ff5b71;
127 |
128 | --ion-color-dark: #f4f5f8;
129 | --ion-color-dark-rgb: 244, 245, 248;
130 | --ion-color-dark-contrast: #000000;
131 | --ion-color-dark-contrast-rgb: 0, 0, 0;
132 | --ion-color-dark-shade: #d7d8da;
133 | --ion-color-dark-tint: #f5f6f9;
134 |
135 | --ion-color-medium: #989aa2;
136 | --ion-color-medium-rgb: 152, 154, 162;
137 | --ion-color-medium-contrast: #000000;
138 | --ion-color-medium-contrast-rgb: 0, 0, 0;
139 | --ion-color-medium-shade: #86888f;
140 | --ion-color-medium-tint: #a2a4ab;
141 |
142 | --ion-color-light: #222428;
143 | --ion-color-light-rgb: 34, 36, 40;
144 | --ion-color-light-contrast: #ffffff;
145 | --ion-color-light-contrast-rgb: 255, 255, 255;
146 | --ion-color-light-shade: #1e2023;
147 | --ion-color-light-tint: #383a3e;
148 | }
149 |
150 | /*
151 | * iOS Dark Theme
152 | * -------------------------------------------
153 | */
154 |
155 | .ios body {
156 | --ion-background-color: #000000;
157 | --ion-background-color-rgb: 0, 0, 0;
158 |
159 | --ion-text-color: #ffffff;
160 | --ion-text-color-rgb: 255, 255, 255;
161 |
162 | --ion-color-step-50: #0d0d0d;
163 | --ion-color-step-100: #1a1a1a;
164 | --ion-color-step-150: #262626;
165 | --ion-color-step-200: #333333;
166 | --ion-color-step-250: #404040;
167 | --ion-color-step-300: #4d4d4d;
168 | --ion-color-step-350: #595959;
169 | --ion-color-step-400: #666666;
170 | --ion-color-step-450: #737373;
171 | --ion-color-step-500: #808080;
172 | --ion-color-step-550: #8c8c8c;
173 | --ion-color-step-600: #999999;
174 | --ion-color-step-650: #a6a6a6;
175 | --ion-color-step-700: #b3b3b3;
176 | --ion-color-step-750: #bfbfbf;
177 | --ion-color-step-800: #cccccc;
178 | --ion-color-step-850: #d9d9d9;
179 | --ion-color-step-900: #e6e6e6;
180 | --ion-color-step-950: #f2f2f2;
181 |
182 | --ion-item-background: #000000;
183 |
184 | --ion-card-background: #1c1c1d;
185 | }
186 |
187 | .ios ion-modal {
188 | --ion-background-color: var(--ion-color-step-100);
189 | --ion-toolbar-background: var(--ion-color-step-150);
190 | --ion-toolbar-border-color: var(--ion-color-step-250);
191 | }
192 |
193 | /*
194 | * Material Design Dark Theme
195 | * -------------------------------------------
196 | */
197 |
198 | .md body {
199 | --ion-background-color: #121212;
200 | --ion-background-color-rgb: 18, 18, 18;
201 |
202 | --ion-text-color: #ffffff;
203 | --ion-text-color-rgb: 255, 255, 255;
204 |
205 | --ion-border-color: #222222;
206 |
207 | --ion-color-step-50: #1e1e1e;
208 | --ion-color-step-100: #2a2a2a;
209 | --ion-color-step-150: #363636;
210 | --ion-color-step-200: #414141;
211 | --ion-color-step-250: #4d4d4d;
212 | --ion-color-step-300: #595959;
213 | --ion-color-step-350: #656565;
214 | --ion-color-step-400: #717171;
215 | --ion-color-step-450: #7d7d7d;
216 | --ion-color-step-500: #898989;
217 | --ion-color-step-550: #949494;
218 | --ion-color-step-600: #a0a0a0;
219 | --ion-color-step-650: #acacac;
220 | --ion-color-step-700: #b8b8b8;
221 | --ion-color-step-750: #c4c4c4;
222 | --ion-color-step-800: #d0d0d0;
223 | --ion-color-step-850: #dbdbdb;
224 | --ion-color-step-900: #e7e7e7;
225 | --ion-color-step-950: #f3f3f3;
226 |
227 | --ion-item-background: #1e1e1e;
228 |
229 | --ion-toolbar-background: #1f1f1f;
230 |
231 | --ion-tab-bar-background: #1f1f1f;
232 |
233 | --ion-card-background: #1e1e1e;
234 | }
235 | }
236 |
237 | /**
238 | * Barcode Scanning
239 | * -------------------------------------------
240 | */
241 | body.barcode-scanning-active {
242 | visibility: hidden;
243 | --background: transparent;
244 | --ion-background-color: transparent;
245 | }
246 |
247 | .barcode-scanning-modal {
248 | visibility: visible;
249 | }
250 |
251 | @media (prefers-color-scheme: dark) {
252 | .barcode-scanning-modal {
253 | --background: transparent;
254 | --ion-background-color: transparent;
255 | }
256 | }
257 |
--------------------------------------------------------------------------------
/ios/App/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Capacitor (8.0.0):
3 | - CapacitorCordova
4 | - CapacitorApp (8.0.0):
5 | - Capacitor
6 | - CapacitorCordova (8.0.0)
7 | - CapacitorHaptics (8.0.0):
8 | - Capacitor
9 | - CapacitorKeyboard (8.0.0):
10 | - Capacitor
11 | - CapacitorMlkitBarcodeScanning (7.0.0-dev.1765885034):
12 | - Capacitor
13 | - GoogleMLKit/BarcodeScanning (~> 8.0.0)
14 | - CapacitorMlkitDocumentScanner (7.0.0-dev.1765885034):
15 | - Capacitor
16 | - CapacitorMlkitFaceDetection (7.0.0-dev.1765885034):
17 | - Capacitor
18 | - GoogleMLKit/FaceDetection (~> 8.0.0)
19 | - CapacitorMlkitFaceMeshDetection (7.0.0-dev.1765885034):
20 | - Capacitor
21 | - CapacitorMlkitSelfieSegmentation (7.0.0-dev.1765885034):
22 | - Capacitor
23 | - GoogleMLKit/SegmentationSelfie (~> 8.0.0)
24 | - CapacitorMlkitSubjectSegmentation (7.0.0-dev.1765885034):
25 | - Capacitor
26 | - CapacitorMlkitTranslation (7.0.0-dev.1765885034):
27 | - Capacitor
28 | - GoogleMLKit/Translate (~> 8.0.0)
29 | - CapacitorStatusBar (8.0.0):
30 | - Capacitor
31 | - CapawesomeCapacitorFilePicker (7.0.0-dev.1765885034):
32 | - Capacitor
33 | - GoogleDataTransport (10.1.0):
34 | - nanopb (~> 3.30910.0)
35 | - PromisesObjC (~> 2.4)
36 | - GoogleMLKit/BarcodeScanning (8.0.0):
37 | - GoogleMLKit/MLKitCore
38 | - MLKitBarcodeScanning (~> 7.0.0)
39 | - GoogleMLKit/FaceDetection (8.0.0):
40 | - GoogleMLKit/MLKitCore
41 | - MLKitFaceDetection (~> 7.0.0)
42 | - GoogleMLKit/MLKitCore (8.0.0):
43 | - MLKitCommon (~> 13.0.0)
44 | - GoogleMLKit/SegmentationSelfie (8.0.0):
45 | - GoogleMLKit/MLKitCore
46 | - MLKitSegmentationSelfie (~> 1.0.0-beta13)
47 | - GoogleMLKit/Translate (8.0.0):
48 | - GoogleMLKit/MLKitCore
49 | - MLKitTranslate (~> 7.0.0)
50 | - GoogleToolboxForMac/Defines (4.2.1)
51 | - GoogleToolboxForMac/Logger (4.2.1):
52 | - GoogleToolboxForMac/Defines (= 4.2.1)
53 | - "GoogleToolboxForMac/NSData+zlib (4.2.1)":
54 | - GoogleToolboxForMac/Defines (= 4.2.1)
55 | - GoogleToolboxForMac/StringEncoding (4.2.1):
56 | - GoogleToolboxForMac/Defines (= 4.2.1)
57 | - GoogleUtilities/Environment (8.1.0):
58 | - GoogleUtilities/Privacy
59 | - GoogleUtilities/Logger (8.1.0):
60 | - GoogleUtilities/Environment
61 | - GoogleUtilities/Privacy
62 | - GoogleUtilities/Privacy (8.1.0)
63 | - GoogleUtilities/UserDefaults (8.1.0):
64 | - GoogleUtilities/Logger
65 | - GoogleUtilities/Privacy
66 | - GTMSessionFetcher/Core (3.5.0)
67 | - MLImage (1.0.0-beta7)
68 | - MLKitBarcodeScanning (7.0.0):
69 | - MLKitCommon (~> 13.0)
70 | - MLKitVision (~> 9.0)
71 | - MLKitCommon (13.0.0):
72 | - GoogleDataTransport (~> 10.0)
73 | - GoogleToolboxForMac/Logger (< 5.0, >= 4.2.1)
74 | - "GoogleToolboxForMac/NSData+zlib (< 5.0, >= 4.2.1)"
75 | - GoogleUtilities/Logger (~> 8.0)
76 | - GoogleUtilities/UserDefaults (~> 8.0)
77 | - GTMSessionFetcher/Core (< 4.0, >= 3.3.2)
78 | - MLKitFaceDetection (7.0.0):
79 | - MLKitCommon (~> 13.0)
80 | - MLKitVision (~> 9.0)
81 | - MLKitNaturalLanguage (9.0.0):
82 | - GoogleToolboxForMac/Logger (< 5.0, >= 4.2.1)
83 | - "GoogleToolboxForMac/NSData+zlib (< 5.0, >= 4.2.1)"
84 | - GoogleToolboxForMac/StringEncoding (< 5.0, >= 4.2.1)
85 | - GTMSessionFetcher/Core (< 4.0, >= 3.3.2)
86 | - MLKitCommon (~> 13.0)
87 | - MLKitSegmentationCommon (1.0.0-beta13):
88 | - MLKitCommon (~> 13.0)
89 | - MLKitXenoCommon (= 1.0.0-beta15)
90 | - MLKitSegmentationSelfie (1.0.0-beta13):
91 | - MLKitSegmentationCommon (= 1.0.0-beta13)
92 | - MLKitTranslate (7.0.0):
93 | - MLKitNaturalLanguage (~> 9.0)
94 | - SSZipArchive (< 3.0, >= 2.5.5)
95 | - MLKitVision (9.0.0):
96 | - GoogleToolboxForMac/Logger (< 5.0, >= 4.2.1)
97 | - "GoogleToolboxForMac/NSData+zlib (< 5.0, >= 4.2.1)"
98 | - GTMSessionFetcher/Core (< 4.0, >= 3.3.2)
99 | - MLImage (= 1.0.0-beta7)
100 | - MLKitCommon (~> 13.0)
101 | - MLKitXenoCommon (1.0.0-beta15):
102 | - MLKitCommon (~> 13.0)
103 | - MLKitVision (~> 9.0)
104 | - nanopb (3.30910.0):
105 | - nanopb/decode (= 3.30910.0)
106 | - nanopb/encode (= 3.30910.0)
107 | - nanopb/decode (3.30910.0)
108 | - nanopb/encode (3.30910.0)
109 | - PromisesObjC (2.4.0)
110 | - SSZipArchive (2.6.0)
111 |
112 | DEPENDENCIES:
113 | - "Capacitor (from `../../node_modules/@capacitor/ios`)"
114 | - "CapacitorApp (from `../../node_modules/@capacitor/app`)"
115 | - "CapacitorCordova (from `../../node_modules/@capacitor/ios`)"
116 | - "CapacitorHaptics (from `../../node_modules/@capacitor/haptics`)"
117 | - "CapacitorKeyboard (from `../../node_modules/@capacitor/keyboard`)"
118 | - "CapacitorMlkitBarcodeScanning (from `../../node_modules/@capacitor-mlkit/barcode-scanning`)"
119 | - "CapacitorMlkitDocumentScanner (from `../../node_modules/@capacitor-mlkit/document-scanner`)"
120 | - "CapacitorMlkitFaceDetection (from `../../node_modules/@capacitor-mlkit/face-detection`)"
121 | - "CapacitorMlkitFaceMeshDetection (from `../../node_modules/@capacitor-mlkit/face-mesh-detection`)"
122 | - "CapacitorMlkitSelfieSegmentation (from `../../node_modules/@capacitor-mlkit/selfie-segmentation`)"
123 | - "CapacitorMlkitSubjectSegmentation (from `../../node_modules/@capacitor-mlkit/subject-segmentation`)"
124 | - "CapacitorMlkitTranslation (from `../../node_modules/@capacitor-mlkit/translation`)"
125 | - "CapacitorStatusBar (from `../../node_modules/@capacitor/status-bar`)"
126 | - "CapawesomeCapacitorFilePicker (from `../../node_modules/@capawesome/capacitor-file-picker`)"
127 |
128 | SPEC REPOS:
129 | trunk:
130 | - GoogleDataTransport
131 | - GoogleMLKit
132 | - GoogleToolboxForMac
133 | - GoogleUtilities
134 | - GTMSessionFetcher
135 | - MLImage
136 | - MLKitBarcodeScanning
137 | - MLKitCommon
138 | - MLKitFaceDetection
139 | - MLKitNaturalLanguage
140 | - MLKitSegmentationCommon
141 | - MLKitSegmentationSelfie
142 | - MLKitTranslate
143 | - MLKitVision
144 | - MLKitXenoCommon
145 | - nanopb
146 | - PromisesObjC
147 | - SSZipArchive
148 |
149 | EXTERNAL SOURCES:
150 | Capacitor:
151 | :path: "../../node_modules/@capacitor/ios"
152 | CapacitorApp:
153 | :path: "../../node_modules/@capacitor/app"
154 | CapacitorCordova:
155 | :path: "../../node_modules/@capacitor/ios"
156 | CapacitorHaptics:
157 | :path: "../../node_modules/@capacitor/haptics"
158 | CapacitorKeyboard:
159 | :path: "../../node_modules/@capacitor/keyboard"
160 | CapacitorMlkitBarcodeScanning:
161 | :path: "../../node_modules/@capacitor-mlkit/barcode-scanning"
162 | CapacitorMlkitDocumentScanner:
163 | :path: "../../node_modules/@capacitor-mlkit/document-scanner"
164 | CapacitorMlkitFaceDetection:
165 | :path: "../../node_modules/@capacitor-mlkit/face-detection"
166 | CapacitorMlkitFaceMeshDetection:
167 | :path: "../../node_modules/@capacitor-mlkit/face-mesh-detection"
168 | CapacitorMlkitSelfieSegmentation:
169 | :path: "../../node_modules/@capacitor-mlkit/selfie-segmentation"
170 | CapacitorMlkitSubjectSegmentation:
171 | :path: "../../node_modules/@capacitor-mlkit/subject-segmentation"
172 | CapacitorMlkitTranslation:
173 | :path: "../../node_modules/@capacitor-mlkit/translation"
174 | CapacitorStatusBar:
175 | :path: "../../node_modules/@capacitor/status-bar"
176 | CapawesomeCapacitorFilePicker:
177 | :path: "../../node_modules/@capawesome/capacitor-file-picker"
178 |
179 | SPEC CHECKSUMS:
180 | Capacitor: 341ff7cf652ec695d1a8ebf604db448ac7b6d635
181 | CapacitorApp: 3963a84197280757b84f126afd1520a85ae3b092
182 | CapacitorCordova: 5dc3912d25ef770a3fe0f431bb65c9fbfa2e92f9
183 | CapacitorHaptics: 2079d9fa04c5a71e18663b4722323c304c58245c
184 | CapacitorKeyboard: d7868c079a4d5277a3deca27a10a488fcbbb8b69
185 | CapacitorMlkitBarcodeScanning: 12e784e21f4f10308c8b4253c94cbae33d4525b7
186 | CapacitorMlkitDocumentScanner: d26393765ccc33e140051e9195b1fa31c12e1320
187 | CapacitorMlkitFaceDetection: bacdcaff997704a2335f1cde45638f78f3a6f653
188 | CapacitorMlkitFaceMeshDetection: ef14aae4e6123bbd65d5135580b50ae311f106f8
189 | CapacitorMlkitSelfieSegmentation: 18f8fb52c338ff5c371417592d85f6ab486194d1
190 | CapacitorMlkitSubjectSegmentation: 8b7f8f9b97cd306065fde354db661aa718a767aa
191 | CapacitorMlkitTranslation: e59eec445f93227dd84d855577ddd890d0dfa79d
192 | CapacitorStatusBar: 312e2e67928dfe9514c4a8916a1fd610552f5f35
193 | CapawesomeCapacitorFilePicker: 37ffe33ab8e5340fba712b145a551a7fe910eeb9
194 | GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
195 | GoogleMLKit: ddd51d7dff36ff28defa69afedd9cdce684fd857
196 | GoogleToolboxForMac: d1a2cbf009c453f4d6ded37c105e2f67a32206d8
197 | GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
198 | GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6
199 | MLImage: 2ab9c968e75f57911c16f4c9d9e8a8e9604a86a1
200 | MLKitBarcodeScanning: 72c6437f13a900833b400136be53a8a5d86f42fa
201 | MLKitCommon: 26b779f072a182c1603d4c88a101c350cac837b1
202 | MLKitFaceDetection: d50aff1a44aa9a4e95f7e208298a3ce40b68f9f8
203 | MLKitNaturalLanguage: 4c5580068109aaea85809981b8c4cb4675b2100f
204 | MLKitSegmentationCommon: 2b745e791948849011bfd34dd19be83a4895b14b
205 | MLKitSegmentationSelfie: 72895c53eaf634b6efd8236a329e552bdf239383
206 | MLKitTranslate: ab71c9e4a67cc79756d4dae013e47edfca3b57cb
207 | MLKitVision: fa8dea9012ac59497c79ddbe9ebf32051047ac4c
208 | MLKitXenoCommon: d6f30a3235d21f5d7e85ec3b6015d3b21ff38ba1
209 | nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
210 | PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
211 | SSZipArchive: 8a6ee5677c8e304bebc109e39cf0da91ccef22ea
212 |
213 | PODFILE CHECKSUM: 30a4d6274d2d8e1ccc726f53562530c495098d54
214 |
215 | COCOAPODS: 1.16.2
216 |
--------------------------------------------------------------------------------