├── .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 | 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 | 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 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 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 | [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/robingenz/capacitor-mlkit-plugin-demo/ci.yml?branch=main)](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 |
35 | 36 | Width 37 | 38 | 39 | 40 | Height 41 | 42 | 43 | 44 | Confidence 45 | 55 | 56 | Process Image 57 |
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 |
35 | 36 | Width 37 | 38 | 39 | 40 | Height 41 | 42 | 43 | 44 | Confidence 45 | 55 | 56 | Process Image 57 | Install Google Subject Segmentation Module 60 |
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 |
35 | 36 | Text 37 | 38 | 39 | 40 | Source Language 41 | 42 | @for (item of language | keyvalue; track item) { 43 | {{ item.key }} 46 | } 47 | 48 | 49 | 50 | Target Language 51 | 52 | @for (item of language | keyvalue; track item) { 53 | {{ item.key }} 56 | } 57 | 58 | 59 | 60 | Translation 61 | 66 | 67 |
68 | Translate 69 |
70 |
71 | 72 | 73 | Manage Models 74 | 75 | 76 |
77 | 78 | Language 79 | 80 | @for (item of language | keyvalue; track item) { 81 | {{ item.key }} 84 | } 85 | 86 | 87 |
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 |
35 | 36 | Use Case 37 | 38 | Bounding Box Only 41 | Face Mesh 44 | 45 | 46 | Process Image 47 |
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 |
36 | 37 | Gallery Import Allowed 38 | 42 | 43 | 44 | Page Limit 45 | 51 | 52 | 53 | Result Formats 54 | 55 | JPEG 58 | PDF 61 | JPEG + PDF 64 | 65 | 66 | 67 | Scanner Mode 68 | 69 | BASE 72 | BASE_WITH_FILTER 75 | FULL 78 | 79 | 80 | 81 | Module Available 82 | 87 | 88 | 89 | Install State 90 | 95 | 96 | 97 | Install Progress 98 | 103 | 104 | 105 | 106 | Scan Document 107 | 108 | 109 | Check Module Availability 110 | 111 | 116 | Install Google Document Scanner Module 117 | 118 |
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 | Scanned document {{ i + 1 }} 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 |
35 | 36 | Formats 37 | 42 | Aztec 45 | Codabar 48 | Code39 51 | Code93 54 | Code128 57 | DataMatrix 60 | Ean8 63 | Ean13 66 | Itf 69 | Pdf417 72 | QrCode 75 | UpcA 78 | UpcE 81 | 82 | 83 | 84 | Lens Facing 85 | 86 | Front 89 | Back 92 | 93 | 94 | 95 | Google Barcode Scanner Module Install State 98 | 103 | 104 | 105 | Google Barcode Scanner Module Install Progress 108 | 113 | 114 | Start Scan 120 | Read Barcode From Image 126 | Scan 129 | Open Settings 135 | Install Google Barcode Scanner Module 141 | Request Permissions 147 |
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 | --------------------------------------------------------------------------------