diff --git a/CHANGELOD.md b/CHANGELOD.md new file mode 100644 index 00000000..4abf0c9c --- /dev/null +++ b/CHANGELOD.md @@ -0,0 +1,11 @@ +## [2.0.0](https://github.com/spoonconsulting/cordova-plugin-telerik-imagepicker/compare/1.0.2...2.0.0) (2021-05-05) + + +### Breaking Changes + +* **android:** Android 11 does not support WRITE_EXTERNAL_STORAGE permission and Playstore will reject any app's manifest containting this permission. + +The plugin's new package name is: com.spoon.imagepicker + + +## [1.0.2](https://github.com/spoonconsulting/cordova-plugin-telerik-imagepicker/releases/tag/1.0.2) \ No newline at end of file diff --git a/README.md b/README.md index 9612d299..1f686a28 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ window.imagePicker.getPictures( ### Note for Android Use -When outputType is FILE_URI the plugin returns images that are stored in a temporary directory. These images will often not be deleted automatically though. The files should be moved or deleted after you get their filepaths in javascript. If Base64 Strings are being returned, there is nothing to clean up. +The 'maximumImagesCount' option is currently the only option supported for Android ## Android 6 (M) Permissions On Android 6 you need to request permission to read external storage at runtime when targeting API level 23+. @@ -120,18 +120,6 @@ For iOS this plugin uses the ELCImagePickerController, with slight modifications https://github.com/B-Sides/ELCImagePickerController -#### MultiImageChooser - -For Android this plugin uses MultiImageChooser, with modifications. MultiImageChooser uses the BSD 2-Clause License which can be found in the file BSD_LICENSE. Some code inside MultImageChooser is licensed under the Apache license which can be found in the file APACHE_LICENSE. - -https://github.com/derosa/MultiImageChooser - -#### FakeR - -Code(FakeR) was also taken from the phonegap BarCodeScanner plugin. This code uses the MIT license. - -https://github.com/wildabeast/BarcodeScanner - ## License The MIT License diff --git a/demo/.browserslistrc b/demo/.browserslistrc new file mode 100644 index 00000000..427441dc --- /dev/null +++ b/demo/.browserslistrc @@ -0,0 +1,17 @@ +# This file is used by the build system to adjust CSS and JS output to support the specified browsers below. +# For additional information regarding the format and rule options, please see: +# https://github.com/browserslist/browserslist#queries + +# For the full list of supported browsers by the Angular framework, please see: +# https://angular.io/guide/browser-support + +# You can see what browsers were selected by your queries by running: +# npx browserslist + +last 1 Chrome version +last 1 Firefox version +last 2 Edge major versions +last 2 Safari major versions +last 2 iOS major versions +Firefox ESR +not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line. diff --git a/demo/.eslintrc.json b/demo/.eslintrc.json new file mode 100644 index 00000000..58fd208e --- /dev/null +++ b/demo/.eslintrc.json @@ -0,0 +1,47 @@ +{ + "root": true, + "ignorePatterns": ["projects/**/*"], + "overrides": [ + { + "files": ["*.ts"], + "parserOptions": { + "project": ["tsconfig.json", "e2e/tsconfig.json"], + "createDefaultProgram": true + }, + "extends": [ + "plugin:@angular-eslint/ng-cli-compat", + "plugin:@angular-eslint/ng-cli-compat--formatting-add-on", + "plugin:@angular-eslint/template/process-inline-templates" + ], + "rules": { + "@angular-eslint/component-class-suffix": [ + "error", + { + "suffixes": ["Page", "Component"] + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "app", + "style": "kebab-case" + } + ], + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "app", + "style": "camelCase" + } + ] + } + }, + { + "files": ["*.html"], + "extends": ["plugin:@angular-eslint/template/recommended"], + "rules": {} + } + ] +} diff --git a/demo/.gitignore b/demo/.gitignore new file mode 100644 index 00000000..416fc4c1 --- /dev/null +++ b/demo/.gitignore @@ -0,0 +1,31 @@ +# Specifies intentionally untracked files to ignore when using Git +# http://git-scm.com/docs/gitignore + +*~ +*.sw[mnpcod] +.tmp +*.tmp +*.tmp.* +*.sublime-project +*.sublime-workspace +.DS_Store +Thumbs.db +UserInterfaceState.xcuserstate +$RECYCLE.BIN/ + +*.log +log.txt +npm-debug.log* + +/.idea +/.ionic +/.sass-cache +/.sourcemaps +/.versions +/.vscode +/coverage +/dist +/node_modules +/platforms +/plugins +/www diff --git a/demo/angular.json b/demo/angular.json new file mode 100644 index 00000000..4fe14e74 --- /dev/null +++ b/demo/angular.json @@ -0,0 +1,177 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "defaultProject": "app", + "newProjectRoot": "projects", + "projects": { + "app": { + "root": "", + "sourceRoot": "src", + "projectType": "application", + "prefix": "app", + "schematics": {}, + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:browser", + "options": { + "outputPath": "www", + "index": "src/index.html", + "main": "src/main.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "tsconfig.app.json", + "assets": [ + { + "glob": "**/*", + "input": "src/assets", + "output": "assets" + }, + { + "glob": "**/*.svg", + "input": "node_modules/ionicons/dist/ionicons/svg", + "output": "./svg" + } + ], + "styles": ["src/theme/variables.scss", "src/global.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "fileReplacements": [ + { + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.prod.ts" + } + ], + "optimization": true, + "outputHashing": "all", + "sourceMap": false, + "namedChunks": false, + "aot": true, + "extractLicenses": true, + "vendorChunk": false, + "buildOptimizer": true, + "budgets": [ + { + "type": "initial", + "maximumWarning": "2mb", + "maximumError": "5mb" + } + ] + }, + "ci": { + "progress": false + } + } + }, + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "options": { + "browserTarget": "app:build" + }, + "configurations": { + "production": { + "browserTarget": "app:build:production" + }, + "ci": { + "progress": false + } + } + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "app:build" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "src/test.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "tsconfig.spec.json", + "karmaConfig": "karma.conf.js", + "styles": [], + "scripts": [], + "assets": [ + { + "glob": "favicon.ico", + "input": "src/", + "output": "/" + }, + { + "glob": "**/*", + "input": "src/assets", + "output": "/assets" + } + ] + }, + "configurations": { + "ci": { + "progress": false, + "watch": false + } + } + }, + "lint": { + "builder": "@angular-eslint/builder:lint", + "options": { + "lintFilePatterns": [ + "src/**/*.ts", + "src/**/*.html" + ] + } + }, + "e2e": { + "builder": "@angular-devkit/build-angular:protractor", + "options": { + "protractorConfig": "e2e/protractor.conf.js", + "devServerTarget": "app:serve" + }, + "configurations": { + "production": { + "devServerTarget": "app:serve:production" + }, + "ci": { + "devServerTarget": "app:serve:ci" + } + } + }, + "ionic-cordova-build": { + "builder": "@ionic/angular-toolkit:cordova-build", + "options": { + "browserTarget": "app:build" + }, + "configurations": { + "production": { + "browserTarget": "app:build:production" + } + } + }, + "ionic-cordova-serve": { + "builder": "@ionic/angular-toolkit:cordova-serve", + "options": { + "cordovaBuildTarget": "app:ionic-cordova-build", + "devServerTarget": "app:serve" + }, + "configurations": { + "production": { + "cordovaBuildTarget": "app:ionic-cordova-build:production", + "devServerTarget": "app:serve:production" + } + } + } + } + } + }, + "cli": { + "defaultCollection": "@ionic/angular-toolkit" + }, + "schematics": { + "@ionic/angular-toolkit:component": { + "styleext": "scss" + }, + "@ionic/angular-toolkit:page": { + "styleext": "scss" + } + } +} diff --git a/demo/config.xml b/demo/config.xml new file mode 100644 index 00000000..106bebd8 --- /dev/null +++ b/demo/config.xml @@ -0,0 +1,96 @@ + + + ImagePicker + Demo app for image picker cordova + Spoon Consulting Ltd + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demo/e2e/protractor.conf.js b/demo/e2e/protractor.conf.js new file mode 100644 index 00000000..22bd9d95 --- /dev/null +++ b/demo/e2e/protractor.conf.js @@ -0,0 +1,37 @@ +// @ts-check +// Protractor configuration file, see link for more information +// https://github.com/angular/protractor/blob/master/lib/config.ts + +const { SpecReporter, StacktraceOption } = require('jasmine-spec-reporter'); + +/** + * @type { import("protractor").Config } + */ +exports.config = { + allScriptsTimeout: 11000, + specs: [ + './src/**/*.e2e-spec.ts' + ], + capabilities: { + browserName: 'chrome' + }, + directConnect: true, + SELENIUM_PROMISE_MANAGER: false, + baseUrl: 'http://localhost:4200/', + framework: 'jasmine', + jasmineNodeOpts: { + showColors: true, + defaultTimeoutInterval: 30000, + print: function() {} + }, + onPrepare() { + require('ts-node').register({ + project: require('path').join(__dirname, './tsconfig.json') + }); + jasmine.getEnv().addReporter(new SpecReporter({ + spec: { + displayStacktrace: StacktraceOption.PRETTY + } + })); + } +}; diff --git a/demo/e2e/src/app.e2e-spec.ts b/demo/e2e/src/app.e2e-spec.ts new file mode 100644 index 00000000..33efa08d --- /dev/null +++ b/demo/e2e/src/app.e2e-spec.ts @@ -0,0 +1,14 @@ +import { AppPage } from './app.po'; + +describe('new App', () => { + let page: AppPage; + + beforeEach(() => { + page = new AppPage(); + }); + + it('should be blank', () => { + page.navigateTo(); + expect(page.getParagraphText()).toContain('Start with Ionic UI Components'); + }); +}); diff --git a/demo/e2e/src/app.po.ts b/demo/e2e/src/app.po.ts new file mode 100644 index 00000000..c121fd9b --- /dev/null +++ b/demo/e2e/src/app.po.ts @@ -0,0 +1,11 @@ +import { browser, by, element } from 'protractor'; + +export class AppPage { + navigateTo() { + return browser.get('/'); + } + + getParagraphText() { + return element(by.deepCss('app-root ion-content')).getText(); + } +} diff --git a/demo/e2e/tsconfig.json b/demo/e2e/tsconfig.json new file mode 100644 index 00000000..a82df00e --- /dev/null +++ b/demo/e2e/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/e2e", + "module": "commonjs", + "target": "es2018", + "types": [ + "jasmine", + "node" + ] + } +} diff --git a/demo/index.html b/demo/index.html deleted file mode 100644 index 39d1f2c6..00000000 --- a/demo/index.html +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - ImagePicker demo - - -
-

ImagePicker demo

- - -
- - - - -
-
- - - \ No newline at end of file diff --git a/demo/ionic.config.json b/demo/ionic.config.json new file mode 100644 index 00000000..94c17110 --- /dev/null +++ b/demo/ionic.config.json @@ -0,0 +1,7 @@ +{ + "name": "ImagePicker demo", + "integrations": { + "cordova": {} + }, + "type": "angular" +} diff --git a/demo/karma.conf.js b/demo/karma.conf.js new file mode 100644 index 00000000..49eb12fa --- /dev/null +++ b/demo/karma.conf.js @@ -0,0 +1,44 @@ +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + jasmine: { + // you can add configuration options for Jasmine here + // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html + // for example, you can disable the random execution with `random: false` + // or set a specific seed with `seed: 4321` + }, + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + jasmineHtmlReporter: { + suppressAll: true // removes the duplicated traces + }, + coverageReporter: { + dir: require('path').join(__dirname, './coverage/ngv'), + subdir: '.', + reporters: [ + { type: 'html' }, + { type: 'text-summary' } + ] + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false, + restartOnFileChange: true + }); +}; diff --git a/demo/package.json b/demo/package.json new file mode 100644 index 00000000..145bf575 --- /dev/null +++ b/demo/package.json @@ -0,0 +1,90 @@ +{ + "name": "ImagePicker demo", + "version": "0.0.1", + "author": "Spoon Consulting Ltd", + "homepage": "http://spoonconsulting.com/", + "scripts": { + "ng": "ng", + "start": "ng serve", + "build": "ng build", + "test": "ng test", + "lint": "ng lint", + "e2e": "ng e2e" + }, + "private": true, + "dependencies": { + "@angular/common": "~11.2.0", + "@angular/core": "~11.2.0", + "@angular/forms": "~11.2.0", + "@angular/platform-browser": "~11.2.0", + "@angular/platform-browser-dynamic": "~11.2.0", + "@angular/router": "~11.2.0", + "@ionic-native/core": "^5.32.1", + "@ionic-native/ionic-webview": "^5.22.0-beta-1", + "@ionic/angular": "^5.5.2", + "@spoonconsulting/cordova-plugin-telerik-imagepicker": "^2.0.0", + "cordova-android": "9.1.0", + "rxjs": "~6.6.0", + "tslib": "^2.0.0", + "zone.js": "~0.10.2" + }, + "devDependencies": { + "@angular-devkit/build-angular": "~0.1102.4", + "@angular-eslint/builder": "2.0.2", + "@angular-eslint/eslint-plugin": "2.0.2", + "@angular-eslint/eslint-plugin-template": "2.0.2", + "@angular-eslint/template-parser": "2.0.2", + "@angular/cli": "~11.2.4", + "@angular/compiler": "~11.2.0", + "@angular/compiler-cli": "~11.2.0", + "@angular/language-service": "~11.2.0", + "@ionic/angular-toolkit": "^3.1.1", + "@types/jasmine": "~3.6.0", + "@types/jasminewd2": "~2.0.3", + "@types/node": "^12.11.1", + "@typescript-eslint/eslint-plugin": "4.16.1", + "@typescript-eslint/parser": "4.16.1", + "cordova-plugin-device": "^2.0.2", + "cordova-plugin-ionic-keyboard": "^2.2.0", + "cordova-plugin-ionic-webview": "^4.2.1", + "cordova-plugin-splashscreen": "^5.0.2", + "cordova-plugin-statusbar": "^2.4.2", + "cordova-plugin-whitelist": "^1.3.3", + "eslint": "^7.6.0", + "eslint-plugin-import": "2.22.1", + "eslint-plugin-jsdoc": "30.7.6", + "eslint-plugin-prefer-arrow": "1.2.2", + "jasmine-core": "~3.6.0", + "jasmine-spec-reporter": "~5.0.0", + "karma": "~5.2.0", + "karma-chrome-launcher": "~3.1.0", + "karma-coverage": "~2.0.3", + "karma-coverage-istanbul-reporter": "~3.0.2", + "karma-jasmine": "~4.0.0", + "karma-jasmine-html-reporter": "^1.5.0", + "protractor": "~7.0.0", + "ts-node": "~8.3.0", + "typescript": "~4.0.2", + "cordova-plugin-androidx": "^1.0.2", + "cordova-plugin-androidx-adapter": "^1.1.0" + }, + "description": "Demo app for image picker cordova", + "cordova": { + "plugins": { + "@spoonconsulting/cordova-plugin-telerik-imagepicker": { + "PHOTO_LIBRARY_USAGE_DESCRIPTION": "ImagePicker demo require access to photo library to choose from existing photos." + }, + "cordova-plugin-whitelist": {}, + "cordova-plugin-statusbar": {}, + "cordova-plugin-device": {}, + "cordova-plugin-splashscreen": {}, + "cordova-plugin-ionic-webview": {}, + "cordova-plugin-ionic-keyboard": {}, + "cordova-plugin-androidx": {}, + "cordova-plugin-androidx-adapter": {} + }, + "platforms": [ + "android" + ] + } +} diff --git a/demo/resources/README.md b/demo/resources/README.md new file mode 100644 index 00000000..a5e0a138 --- /dev/null +++ b/demo/resources/README.md @@ -0,0 +1,12 @@ +How to build and launch the app ? + +- Install the dependencies `npm i` +- Add platform `ionic cordova platform add ` +- Run `ionic cordova run ` + +Platform: ios/android + +If you encountered a problem or have an error, proceed as follow: + +- Remove platforms & plugins using `rm ./platforms` and `rm ./plugins` +- Run `ionic cordova run ` diff --git a/demo/resources/android/icon/drawable-hdpi-icon.png b/demo/resources/android/icon/drawable-hdpi-icon.png new file mode 100644 index 00000000..3f84fc1b Binary files /dev/null and b/demo/resources/android/icon/drawable-hdpi-icon.png differ diff --git a/demo/resources/android/icon/drawable-ldpi-icon.png b/demo/resources/android/icon/drawable-ldpi-icon.png new file mode 100644 index 00000000..3de9b4f7 Binary files /dev/null and b/demo/resources/android/icon/drawable-ldpi-icon.png differ diff --git a/demo/resources/android/icon/drawable-mdpi-icon.png b/demo/resources/android/icon/drawable-mdpi-icon.png new file mode 100644 index 00000000..4b455d31 Binary files /dev/null and b/demo/resources/android/icon/drawable-mdpi-icon.png differ diff --git a/demo/resources/android/icon/drawable-xhdpi-icon.png b/demo/resources/android/icon/drawable-xhdpi-icon.png new file mode 100644 index 00000000..fe47ccce Binary files /dev/null and b/demo/resources/android/icon/drawable-xhdpi-icon.png differ diff --git a/demo/resources/android/icon/drawable-xxhdpi-icon.png b/demo/resources/android/icon/drawable-xxhdpi-icon.png new file mode 100644 index 00000000..391b4af1 Binary files /dev/null and b/demo/resources/android/icon/drawable-xxhdpi-icon.png differ diff --git a/demo/resources/android/icon/drawable-xxxhdpi-icon.png b/demo/resources/android/icon/drawable-xxxhdpi-icon.png new file mode 100644 index 00000000..09e50b7b Binary files /dev/null and b/demo/resources/android/icon/drawable-xxxhdpi-icon.png differ diff --git a/demo/resources/android/splash/drawable-land-hdpi-screen.png b/demo/resources/android/splash/drawable-land-hdpi-screen.png new file mode 100644 index 00000000..74abe28e Binary files /dev/null and b/demo/resources/android/splash/drawable-land-hdpi-screen.png differ diff --git a/demo/resources/android/splash/drawable-land-ldpi-screen.png b/demo/resources/android/splash/drawable-land-ldpi-screen.png new file mode 100644 index 00000000..b224ba8c Binary files /dev/null and b/demo/resources/android/splash/drawable-land-ldpi-screen.png differ diff --git a/demo/resources/android/splash/drawable-land-mdpi-screen.png b/demo/resources/android/splash/drawable-land-mdpi-screen.png new file mode 100644 index 00000000..f18770eb Binary files /dev/null and b/demo/resources/android/splash/drawable-land-mdpi-screen.png differ diff --git a/demo/resources/android/splash/drawable-land-xhdpi-screen.png b/demo/resources/android/splash/drawable-land-xhdpi-screen.png new file mode 100644 index 00000000..76eab0d7 Binary files /dev/null and b/demo/resources/android/splash/drawable-land-xhdpi-screen.png differ diff --git a/demo/resources/android/splash/drawable-land-xxhdpi-screen.png b/demo/resources/android/splash/drawable-land-xxhdpi-screen.png new file mode 100644 index 00000000..b15925df Binary files /dev/null and b/demo/resources/android/splash/drawable-land-xxhdpi-screen.png differ diff --git a/demo/resources/android/splash/drawable-land-xxxhdpi-screen.png b/demo/resources/android/splash/drawable-land-xxxhdpi-screen.png new file mode 100644 index 00000000..4b22b8b5 Binary files /dev/null and b/demo/resources/android/splash/drawable-land-xxxhdpi-screen.png differ diff --git a/demo/resources/android/splash/drawable-port-hdpi-screen.png b/demo/resources/android/splash/drawable-port-hdpi-screen.png new file mode 100644 index 00000000..c0c981b9 Binary files /dev/null and b/demo/resources/android/splash/drawable-port-hdpi-screen.png differ diff --git a/demo/resources/android/splash/drawable-port-ldpi-screen.png b/demo/resources/android/splash/drawable-port-ldpi-screen.png new file mode 100644 index 00000000..dfba9321 Binary files /dev/null and b/demo/resources/android/splash/drawable-port-ldpi-screen.png differ diff --git a/demo/resources/android/splash/drawable-port-mdpi-screen.png b/demo/resources/android/splash/drawable-port-mdpi-screen.png new file mode 100644 index 00000000..e5129fd0 Binary files /dev/null and b/demo/resources/android/splash/drawable-port-mdpi-screen.png differ diff --git a/demo/resources/android/splash/drawable-port-xhdpi-screen.png b/demo/resources/android/splash/drawable-port-xhdpi-screen.png new file mode 100644 index 00000000..14ec839e Binary files /dev/null and b/demo/resources/android/splash/drawable-port-xhdpi-screen.png differ diff --git a/demo/resources/android/splash/drawable-port-xxhdpi-screen.png b/demo/resources/android/splash/drawable-port-xxhdpi-screen.png new file mode 100644 index 00000000..4df256fb Binary files /dev/null and b/demo/resources/android/splash/drawable-port-xxhdpi-screen.png differ diff --git a/demo/resources/android/splash/drawable-port-xxxhdpi-screen.png b/demo/resources/android/splash/drawable-port-xxxhdpi-screen.png new file mode 100644 index 00000000..53f97f9d Binary files /dev/null and b/demo/resources/android/splash/drawable-port-xxxhdpi-screen.png differ diff --git a/demo/resources/android/xml/network_security_config.xml b/demo/resources/android/xml/network_security_config.xml new file mode 100644 index 00000000..de61259a --- /dev/null +++ b/demo/resources/android/xml/network_security_config.xml @@ -0,0 +1,6 @@ + + + + localhost + + diff --git a/demo/resources/icon.png b/demo/resources/icon.png new file mode 100644 index 00000000..bee77667 Binary files /dev/null and b/demo/resources/icon.png differ diff --git a/demo/resources/ios/icon/icon-1024.png b/demo/resources/ios/icon/icon-1024.png new file mode 100644 index 00000000..be633f45 Binary files /dev/null and b/demo/resources/ios/icon/icon-1024.png differ diff --git a/demo/resources/ios/icon/icon-20.png b/demo/resources/ios/icon/icon-20.png new file mode 100644 index 00000000..08993e09 Binary files /dev/null and b/demo/resources/ios/icon/icon-20.png differ diff --git a/demo/resources/ios/icon/icon-20@2x.png b/demo/resources/ios/icon/icon-20@2x.png new file mode 100644 index 00000000..acbecd2c Binary files /dev/null and b/demo/resources/ios/icon/icon-20@2x.png differ diff --git a/demo/resources/ios/icon/icon-20@3x.png b/demo/resources/ios/icon/icon-20@3x.png new file mode 100644 index 00000000..00de715c Binary files /dev/null and b/demo/resources/ios/icon/icon-20@3x.png differ diff --git a/demo/resources/ios/icon/icon-24@2x.png b/demo/resources/ios/icon/icon-24@2x.png new file mode 100644 index 00000000..4b455d31 Binary files /dev/null and b/demo/resources/ios/icon/icon-24@2x.png differ diff --git a/demo/resources/ios/icon/icon-27.5@2x.png b/demo/resources/ios/icon/icon-27.5@2x.png new file mode 100644 index 00000000..c623f279 Binary files /dev/null and b/demo/resources/ios/icon/icon-27.5@2x.png differ diff --git a/demo/resources/ios/icon/icon-29.png b/demo/resources/ios/icon/icon-29.png new file mode 100644 index 00000000..8a55da53 Binary files /dev/null and b/demo/resources/ios/icon/icon-29.png differ diff --git a/demo/resources/ios/icon/icon-29@2x.png b/demo/resources/ios/icon/icon-29@2x.png new file mode 100644 index 00000000..185277b1 Binary files /dev/null and b/demo/resources/ios/icon/icon-29@2x.png differ diff --git a/demo/resources/ios/icon/icon-29@3x.png b/demo/resources/ios/icon/icon-29@3x.png new file mode 100644 index 00000000..3393f844 Binary files /dev/null and b/demo/resources/ios/icon/icon-29@3x.png differ diff --git a/demo/resources/ios/icon/icon-40.png b/demo/resources/ios/icon/icon-40.png new file mode 100644 index 00000000..acbecd2c Binary files /dev/null and b/demo/resources/ios/icon/icon-40.png differ diff --git a/demo/resources/ios/icon/icon-40@2x.png b/demo/resources/ios/icon/icon-40@2x.png new file mode 100644 index 00000000..61d82a73 Binary files /dev/null and b/demo/resources/ios/icon/icon-40@2x.png differ diff --git a/demo/resources/ios/icon/icon-40@3x.png b/demo/resources/ios/icon/icon-40@3x.png new file mode 100644 index 00000000..cc349ded Binary files /dev/null and b/demo/resources/ios/icon/icon-40@3x.png differ diff --git a/demo/resources/ios/icon/icon-44@2x.png b/demo/resources/ios/icon/icon-44@2x.png new file mode 100644 index 00000000..00a2ff3d Binary files /dev/null and b/demo/resources/ios/icon/icon-44@2x.png differ diff --git a/demo/resources/ios/icon/icon-50.png b/demo/resources/ios/icon/icon-50.png new file mode 100644 index 00000000..9e9a5c1f Binary files /dev/null and b/demo/resources/ios/icon/icon-50.png differ diff --git a/demo/resources/ios/icon/icon-50@2x.png b/demo/resources/ios/icon/icon-50@2x.png new file mode 100644 index 00000000..fe547b12 Binary files /dev/null and b/demo/resources/ios/icon/icon-50@2x.png differ diff --git a/demo/resources/ios/icon/icon-60.png b/demo/resources/ios/icon/icon-60.png new file mode 100644 index 00000000..00de715c Binary files /dev/null and b/demo/resources/ios/icon/icon-60.png differ diff --git a/demo/resources/ios/icon/icon-60@2x.png b/demo/resources/ios/icon/icon-60@2x.png new file mode 100644 index 00000000..cc349ded Binary files /dev/null and b/demo/resources/ios/icon/icon-60@2x.png differ diff --git a/demo/resources/ios/icon/icon-60@3x.png b/demo/resources/ios/icon/icon-60@3x.png new file mode 100644 index 00000000..38988281 Binary files /dev/null and b/demo/resources/ios/icon/icon-60@3x.png differ diff --git a/demo/resources/ios/icon/icon-72.png b/demo/resources/ios/icon/icon-72.png new file mode 100644 index 00000000..3f84fc1b Binary files /dev/null and b/demo/resources/ios/icon/icon-72.png differ diff --git a/demo/resources/ios/icon/icon-72@2x.png b/demo/resources/ios/icon/icon-72@2x.png new file mode 100644 index 00000000..391b4af1 Binary files /dev/null and b/demo/resources/ios/icon/icon-72@2x.png differ diff --git a/demo/resources/ios/icon/icon-76.png b/demo/resources/ios/icon/icon-76.png new file mode 100644 index 00000000..971034a6 Binary files /dev/null and b/demo/resources/ios/icon/icon-76.png differ diff --git a/demo/resources/ios/icon/icon-76@2x.png b/demo/resources/ios/icon/icon-76@2x.png new file mode 100644 index 00000000..b538930a Binary files /dev/null and b/demo/resources/ios/icon/icon-76@2x.png differ diff --git a/demo/resources/ios/icon/icon-83.5@2x.png b/demo/resources/ios/icon/icon-83.5@2x.png new file mode 100644 index 00000000..5f8dbb2f Binary files /dev/null and b/demo/resources/ios/icon/icon-83.5@2x.png differ diff --git a/demo/resources/ios/icon/icon-86@2x.png b/demo/resources/ios/icon/icon-86@2x.png new file mode 100644 index 00000000..9798fc2d Binary files /dev/null and b/demo/resources/ios/icon/icon-86@2x.png differ diff --git a/demo/resources/ios/icon/icon-98@2x.png b/demo/resources/ios/icon/icon-98@2x.png new file mode 100644 index 00000000..5ebd9db6 Binary files /dev/null and b/demo/resources/ios/icon/icon-98@2x.png differ diff --git a/demo/resources/ios/icon/icon-small.png b/demo/resources/ios/icon/icon-small.png new file mode 100644 index 00000000..8a55da53 Binary files /dev/null and b/demo/resources/ios/icon/icon-small.png differ diff --git a/demo/resources/ios/icon/icon-small@2x.png b/demo/resources/ios/icon/icon-small@2x.png new file mode 100644 index 00000000..185277b1 Binary files /dev/null and b/demo/resources/ios/icon/icon-small@2x.png differ diff --git a/demo/resources/ios/icon/icon-small@3x.png b/demo/resources/ios/icon/icon-small@3x.png new file mode 100644 index 00000000..3393f844 Binary files /dev/null and b/demo/resources/ios/icon/icon-small@3x.png differ diff --git a/demo/resources/ios/icon/icon.png b/demo/resources/ios/icon/icon.png new file mode 100644 index 00000000..a90d46c8 Binary files /dev/null and b/demo/resources/ios/icon/icon.png differ diff --git a/demo/resources/ios/icon/icon@2x.png b/demo/resources/ios/icon/icon@2x.png new file mode 100644 index 00000000..946c6cef Binary files /dev/null and b/demo/resources/ios/icon/icon@2x.png differ diff --git a/demo/resources/ios/splash/Default-2436h.png b/demo/resources/ios/splash/Default-2436h.png new file mode 100644 index 00000000..bdbeb9da Binary files /dev/null and b/demo/resources/ios/splash/Default-2436h.png differ diff --git a/demo/resources/ios/splash/Default-568h@2x~iphone.png b/demo/resources/ios/splash/Default-568h@2x~iphone.png new file mode 100644 index 00000000..5e9edf63 Binary files /dev/null and b/demo/resources/ios/splash/Default-568h@2x~iphone.png differ diff --git a/demo/resources/ios/splash/Default-667h.png b/demo/resources/ios/splash/Default-667h.png new file mode 100644 index 00000000..2843fb37 Binary files /dev/null and b/demo/resources/ios/splash/Default-667h.png differ diff --git a/demo/resources/ios/splash/Default-736h.png b/demo/resources/ios/splash/Default-736h.png new file mode 100644 index 00000000..21f2d423 Binary files /dev/null and b/demo/resources/ios/splash/Default-736h.png differ diff --git a/demo/resources/ios/splash/Default-Landscape-2436h.png b/demo/resources/ios/splash/Default-Landscape-2436h.png new file mode 100644 index 00000000..763ae78d Binary files /dev/null and b/demo/resources/ios/splash/Default-Landscape-2436h.png differ diff --git a/demo/resources/ios/splash/Default-Landscape-736h.png b/demo/resources/ios/splash/Default-Landscape-736h.png new file mode 100644 index 00000000..9c069f7c Binary files /dev/null and b/demo/resources/ios/splash/Default-Landscape-736h.png differ diff --git a/demo/resources/ios/splash/Default-Landscape@2x~ipad.png b/demo/resources/ios/splash/Default-Landscape@2x~ipad.png new file mode 100644 index 00000000..35407a90 Binary files /dev/null and b/demo/resources/ios/splash/Default-Landscape@2x~ipad.png differ diff --git a/demo/resources/ios/splash/Default-Landscape@~ipadpro.png b/demo/resources/ios/splash/Default-Landscape@~ipadpro.png new file mode 100644 index 00000000..75de9e0e Binary files /dev/null and b/demo/resources/ios/splash/Default-Landscape@~ipadpro.png differ diff --git a/demo/resources/ios/splash/Default-Landscape~ipad.png b/demo/resources/ios/splash/Default-Landscape~ipad.png new file mode 100644 index 00000000..b74bbf69 Binary files /dev/null and b/demo/resources/ios/splash/Default-Landscape~ipad.png differ diff --git a/demo/resources/ios/splash/Default-Portrait@2x~ipad.png b/demo/resources/ios/splash/Default-Portrait@2x~ipad.png new file mode 100644 index 00000000..d0c33f78 Binary files /dev/null and b/demo/resources/ios/splash/Default-Portrait@2x~ipad.png differ diff --git a/demo/resources/ios/splash/Default-Portrait@~ipadpro.png b/demo/resources/ios/splash/Default-Portrait@~ipadpro.png new file mode 100644 index 00000000..363dd1c8 Binary files /dev/null and b/demo/resources/ios/splash/Default-Portrait@~ipadpro.png differ diff --git a/demo/resources/ios/splash/Default-Portrait~ipad.png b/demo/resources/ios/splash/Default-Portrait~ipad.png new file mode 100644 index 00000000..aad1debb Binary files /dev/null and b/demo/resources/ios/splash/Default-Portrait~ipad.png differ diff --git a/demo/resources/ios/splash/Default@2x~iphone.png b/demo/resources/ios/splash/Default@2x~iphone.png new file mode 100644 index 00000000..f0f16ef9 Binary files /dev/null and b/demo/resources/ios/splash/Default@2x~iphone.png differ diff --git a/demo/resources/ios/splash/Default@2x~universal~anyany.png b/demo/resources/ios/splash/Default@2x~universal~anyany.png new file mode 100644 index 00000000..c8fcc8f1 Binary files /dev/null and b/demo/resources/ios/splash/Default@2x~universal~anyany.png differ diff --git a/demo/resources/ios/splash/Default~iphone.png b/demo/resources/ios/splash/Default~iphone.png new file mode 100644 index 00000000..e5129fd0 Binary files /dev/null and b/demo/resources/ios/splash/Default~iphone.png differ diff --git a/demo/resources/splash.png b/demo/resources/splash.png new file mode 100644 index 00000000..960cb82a Binary files /dev/null and b/demo/resources/splash.png differ diff --git a/demo/src/app/app-routing.module.ts b/demo/src/app/app-routing.module.ts new file mode 100644 index 00000000..e7b0d5af --- /dev/null +++ b/demo/src/app/app-routing.module.ts @@ -0,0 +1,22 @@ +import { NgModule } from '@angular/core'; +import { PreloadAllModules, RouterModule, Routes } from '@angular/router'; + +const routes: Routes = [ + { + path: 'home', + loadChildren: () => import('./home/home.module').then( m => m.HomePageModule) + }, + { + path: '', + redirectTo: 'home', + pathMatch: 'full' + }, +]; + +@NgModule({ + imports: [ + RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules }) + ], + exports: [RouterModule] +}) +export class AppRoutingModule { } diff --git a/demo/src/app/app.component.html b/demo/src/app/app.component.html new file mode 100644 index 00000000..13b96776 --- /dev/null +++ b/demo/src/app/app.component.html @@ -0,0 +1,3 @@ + + + diff --git a/src/android/androidtarget.gradle b/demo/src/app/app.component.scss similarity index 100% rename from src/android/androidtarget.gradle rename to demo/src/app/app.component.scss diff --git a/demo/src/app/app.component.ts b/demo/src/app/app.component.ts new file mode 100644 index 00000000..913de3df --- /dev/null +++ b/demo/src/app/app.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-root', + templateUrl: 'app.component.html', + styleUrls: ['app.component.scss'], +}) +export class AppComponent { + constructor() {} +} diff --git a/demo/src/app/app.module.ts b/demo/src/app/app.module.ts new file mode 100644 index 00000000..be790cfa --- /dev/null +++ b/demo/src/app/app.module.ts @@ -0,0 +1,21 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { RouteReuseStrategy } from '@angular/router'; + +import { IonicModule, IonicRouteStrategy } from '@ionic/angular'; +import { WebView } from '@ionic-native/ionic-webview/ngx'; + +import { AppComponent } from './app.component'; +import { AppRoutingModule } from './app-routing.module'; + +@NgModule({ + declarations: [AppComponent], + entryComponents: [], + imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule], + providers: [ + { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }, + WebView, + ], + bootstrap: [AppComponent], +}) +export class AppModule {} diff --git a/demo/src/app/home/home-routing.module.ts b/demo/src/app/home/home-routing.module.ts new file mode 100644 index 00000000..29c3f600 --- /dev/null +++ b/demo/src/app/home/home-routing.module.ts @@ -0,0 +1,16 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { HomePage } from './home.page'; + +const routes: Routes = [ + { + path: '', + component: HomePage, + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class HomePageRoutingModule {} diff --git a/demo/src/app/home/home.module.ts b/demo/src/app/home/home.module.ts new file mode 100644 index 00000000..585676b7 --- /dev/null +++ b/demo/src/app/home/home.module.ts @@ -0,0 +1,14 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { IonicModule } from '@ionic/angular'; +import { FormsModule } from '@angular/forms'; +import { HomePage } from './home.page'; + +import { HomePageRoutingModule } from './home-routing.module'; +import { SafePipe } from '../utils/SafePipe'; + +@NgModule({ + imports: [CommonModule, FormsModule, IonicModule, HomePageRoutingModule], + declarations: [HomePage, SafePipe], +}) +export class HomePageModule {} diff --git a/demo/src/app/home/home.page.html b/demo/src/app/home/home.page.html new file mode 100644 index 00000000..3f5da507 --- /dev/null +++ b/demo/src/app/home/home.page.html @@ -0,0 +1,32 @@ + + + Demo + + + + + + + Demo + + + +
+ + + + +
+
+ +
+ +
+
+
+
+
+
diff --git a/demo/src/app/home/home.page.scss b/demo/src/app/home/home.page.scss new file mode 100644 index 00000000..591b454e --- /dev/null +++ b/demo/src/app/home/home.page.scss @@ -0,0 +1,23 @@ +.container { + padding: 8px; +} + +.img-container { + display: block; + text-align: center; + border-width: 1px; + border-style: dashed; + + img { + object-fit: contain; + } +} + +.close-btn { + text-align: right; + padding-right: 2px; +} + +ion-icon { + color: red; +} diff --git a/demo/src/app/home/home.page.ts b/demo/src/app/home/home.page.ts new file mode 100644 index 00000000..6ad1941b --- /dev/null +++ b/demo/src/app/home/home.page.ts @@ -0,0 +1,58 @@ +import { Component, NgZone } from '@angular/core'; +import { WebView } from '@ionic-native/ionic-webview/ngx'; + +declare var imagePicker: any; + +@Component({ + selector: 'app-home', + templateUrl: 'home.page.html', + styleUrls: ['home.page.scss'], +}) +export class HomePage { + images: Array = []; + options: any; + + constructor(private zone: NgZone, private webview: WebView) { + this.hasReadPermission(); + } + + openGallery() { + this.options = { + outputType: 1, + }; + + imagePicker.getPictures( + (results) => { + this.images = []; + + this.zone.run(() => { + for (var i = 0; i < results.length; i++) { + let file = 'file://' + results[i]; + let path = this.webview.convertFileSrc(file); + this.images.push(path); + } + }); + }, + (error) => { + console.log('Error: ' + error); + }, + this.options + ); + } + + hasReadPermission() { + imagePicker.hasReadPermission(function (result) { + if (!result) { + this.requestReadPermission(); + } + }); + } + + requestReadPermission() { + imagePicker.requestReadPermission(); + } + + removeImage(image: string) { + this.images = this.images.filter((img) => img !== image); + } +} diff --git a/demo/src/app/utils/SafePipe.ts b/demo/src/app/utils/SafePipe.ts new file mode 100644 index 00000000..e9d13426 --- /dev/null +++ b/demo/src/app/utils/SafePipe.ts @@ -0,0 +1,10 @@ +import { Pipe, PipeTransform } from '@angular/core'; +import { DomSanitizer } from '@angular/platform-browser'; + +@Pipe({ name: 'safe' }) +export class SafePipe implements PipeTransform { + constructor(private sanitizer: DomSanitizer) {} + transform(url) { + return this.sanitizer.bypassSecurityTrustUrl(url); + } +} diff --git a/demo/src/assets/icon/favicon.png b/demo/src/assets/icon/favicon.png new file mode 100644 index 00000000..51888a7b Binary files /dev/null and b/demo/src/assets/icon/favicon.png differ diff --git a/demo/src/assets/shapes.svg b/demo/src/assets/shapes.svg new file mode 100644 index 00000000..d370b4dc --- /dev/null +++ b/demo/src/assets/shapes.svg @@ -0,0 +1 @@ + diff --git a/demo/src/environments/environment.prod.ts b/demo/src/environments/environment.prod.ts new file mode 100644 index 00000000..3612073b --- /dev/null +++ b/demo/src/environments/environment.prod.ts @@ -0,0 +1,3 @@ +export const environment = { + production: true +}; diff --git a/demo/src/environments/environment.ts b/demo/src/environments/environment.ts new file mode 100644 index 00000000..7b4f817a --- /dev/null +++ b/demo/src/environments/environment.ts @@ -0,0 +1,16 @@ +// This file can be replaced during build by using the `fileReplacements` array. +// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. +// The list of file replacements can be found in `angular.json`. + +export const environment = { + production: false +}; + +/* + * For easier debugging in development mode, you can import the following file + * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. + * + * This import should be commented out in production mode because it will have a negative impact + * on performance if an error is thrown. + */ +// import 'zone.js/dist/zone-error'; // Included with Angular CLI. diff --git a/demo/src/global.scss b/demo/src/global.scss new file mode 100644 index 00000000..d854de84 --- /dev/null +++ b/demo/src/global.scss @@ -0,0 +1,26 @@ +/* + * App Global CSS + * ---------------------------------------------------------------------------- + * Put style rules here that you want to apply globally. These styles are for + * the entire app and not just one component. Additionally, this file can be + * used as an entry point to import other CSS/Sass files to be included in the + * output CSS. + * For more information on global stylesheets, visit the documentation: + * https://ionicframework.com/docs/layout/global-stylesheets + */ + +/* Core CSS required for Ionic components to work properly */ +@import "~@ionic/angular/css/core.css"; + +/* Basic CSS for apps built with Ionic */ +@import "~@ionic/angular/css/normalize.css"; +@import "~@ionic/angular/css/structure.css"; +@import "~@ionic/angular/css/typography.css"; +@import '~@ionic/angular/css/display.css'; + +/* Optional CSS utils that can be commented out */ +@import "~@ionic/angular/css/padding.css"; +@import "~@ionic/angular/css/float-elements.css"; +@import "~@ionic/angular/css/text-alignment.css"; +@import "~@ionic/angular/css/text-transformation.css"; +@import "~@ionic/angular/css/flex-utils.css"; diff --git a/demo/src/index.html b/demo/src/index.html new file mode 100644 index 00000000..3b0aae1d --- /dev/null +++ b/demo/src/index.html @@ -0,0 +1,26 @@ + + + + + + Ionic App + + + + + + + + + + + + + + + + + + + + diff --git a/demo/src/main.ts b/demo/src/main.ts new file mode 100644 index 00000000..91ec6da5 --- /dev/null +++ b/demo/src/main.ts @@ -0,0 +1,12 @@ +import { enableProdMode } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; +import { environment } from './environments/environment'; + +if (environment.production) { + enableProdMode(); +} + +platformBrowserDynamic().bootstrapModule(AppModule) + .catch(err => console.log(err)); diff --git a/demo/src/polyfills.ts b/demo/src/polyfills.ts new file mode 100644 index 00000000..ba409f9d --- /dev/null +++ b/demo/src/polyfills.ts @@ -0,0 +1,65 @@ +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), + * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. + * + * Learn more in https://angular.io/guide/browser-support + */ + +/*************************************************************************************************** + * BROWSER POLYFILLS + */ + +/** IE11 requires the following for NgClass support on SVG elements */ +// import 'classlist.js'; // Run `npm install --save classlist.js`. + +/** + * Web Animations `@angular/platform-browser/animations` + * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. + * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). + */ +// import 'web-animations-js'; // Run `npm install --save web-animations-js`. + +/** + * By default, zone.js will patch all possible macroTask and DomEvents + * user can disable parts of macroTask/DomEvents patch by setting following flags + * because those flags need to be set before `zone.js` being loaded, and webpack + * will put import in the top of bundle, so user need to create a separate file + * in this directory (for example: zone-flags.ts), and put the following flags + * into that file, and then add the following code before importing zone.js. + * import './zone-flags'; + * + * The flags allowed in zone-flags.ts are listed here. + * + * The following flags will work for all browsers. + * + * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame + * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick + * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames + * + * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js + * with the following flag, it will bypass `zone.js` patch for IE/Edge + * + * (window as any).__Zone_enable_cross_context_check = true; + * + */ + +import './zone-flags'; + +/*************************************************************************************************** + * Zone JS is required by default for Angular itself. + */ +import 'zone.js/dist/zone'; // Included with Angular CLI. + + +/*************************************************************************************************** + * APPLICATION IMPORTS + */ diff --git a/demo/src/test.ts b/demo/src/test.ts new file mode 100644 index 00000000..50193eb0 --- /dev/null +++ b/demo/src/test.ts @@ -0,0 +1,25 @@ +// This file is required by karma.conf.js and loads recursively all the .spec and framework files + +import 'zone.js/dist/zone-testing'; +import { getTestBed } from '@angular/core/testing'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting +} from '@angular/platform-browser-dynamic/testing'; + +declare const require: { + context(path: string, deep?: boolean, filter?: RegExp): { + keys(): string[]; + (id: string): T; + }; +}; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment( + BrowserDynamicTestingModule, + platformBrowserDynamicTesting() +); +// Then we find all the tests. +const context = require.context('./', true, /\.spec\.ts$/); +// And load the modules. +context.keys().map(context); diff --git a/demo/src/theme/variables.scss b/demo/src/theme/variables.scss new file mode 100644 index 00000000..eae59259 --- /dev/null +++ b/demo/src/theme/variables.scss @@ -0,0 +1,236 @@ +// Ionic Variables and Theming. For more info, please see: +// http://ionicframework.com/docs/theming/ + +/** Ionic CSS Variables **/ +:root { + /** primary **/ + --ion-color-primary: #3880ff; + --ion-color-primary-rgb: 56, 128, 255; + --ion-color-primary-contrast: #ffffff; + --ion-color-primary-contrast-rgb: 255, 255, 255; + --ion-color-primary-shade: #3171e0; + --ion-color-primary-tint: #4c8dff; + + /** secondary **/ + --ion-color-secondary: #3dc2ff; + --ion-color-secondary-rgb: 61, 194, 255; + --ion-color-secondary-contrast: #ffffff; + --ion-color-secondary-contrast-rgb: 255, 255, 255; + --ion-color-secondary-shade: #36abe0; + --ion-color-secondary-tint: #50c8ff; + + /** tertiary **/ + --ion-color-tertiary: #5260ff; + --ion-color-tertiary-rgb: 82, 96, 255; + --ion-color-tertiary-contrast: #ffffff; + --ion-color-tertiary-contrast-rgb: 255, 255, 255; + --ion-color-tertiary-shade: #4854e0; + --ion-color-tertiary-tint: #6370ff; + + /** success **/ + --ion-color-success: #2dd36f; + --ion-color-success-rgb: 45, 211, 111; + --ion-color-success-contrast: #ffffff; + --ion-color-success-contrast-rgb: 255, 255, 255; + --ion-color-success-shade: #28ba62; + --ion-color-success-tint: #42d77d; + + /** warning **/ + --ion-color-warning: #ffc409; + --ion-color-warning-rgb: 255, 196, 9; + --ion-color-warning-contrast: #000000; + --ion-color-warning-contrast-rgb: 0, 0, 0; + --ion-color-warning-shade: #e0ac08; + --ion-color-warning-tint: #ffca22; + + /** danger **/ + --ion-color-danger: #eb445a; + --ion-color-danger-rgb: 235, 68, 90; + --ion-color-danger-contrast: #ffffff; + --ion-color-danger-contrast-rgb: 255, 255, 255; + --ion-color-danger-shade: #cf3c4f; + --ion-color-danger-tint: #ed576b; + + /** dark **/ + --ion-color-dark: #222428; + --ion-color-dark-rgb: 34, 36, 40; + --ion-color-dark-contrast: #ffffff; + --ion-color-dark-contrast-rgb: 255, 255, 255; + --ion-color-dark-shade: #1e2023; + --ion-color-dark-tint: #383a3e; + + /** medium **/ + --ion-color-medium: #92949c; + --ion-color-medium-rgb: 146, 148, 156; + --ion-color-medium-contrast: #ffffff; + --ion-color-medium-contrast-rgb: 255, 255, 255; + --ion-color-medium-shade: #808289; + --ion-color-medium-tint: #9d9fa6; + + /** light **/ + --ion-color-light: #f4f5f8; + --ion-color-light-rgb: 244, 245, 248; + --ion-color-light-contrast: #000000; + --ion-color-light-contrast-rgb: 0, 0, 0; + --ion-color-light-shade: #d7d8da; + --ion-color-light-tint: #f5f6f9; +} + +@media (prefers-color-scheme: dark) { + /* + * Dark Colors + * ------------------------------------------- + */ + + body { + --ion-color-primary: #428cff; + --ion-color-primary-rgb: 66,140,255; + --ion-color-primary-contrast: #ffffff; + --ion-color-primary-contrast-rgb: 255,255,255; + --ion-color-primary-shade: #3a7be0; + --ion-color-primary-tint: #5598ff; + + --ion-color-secondary: #50c8ff; + --ion-color-secondary-rgb: 80,200,255; + --ion-color-secondary-contrast: #ffffff; + --ion-color-secondary-contrast-rgb: 255,255,255; + --ion-color-secondary-shade: #46b0e0; + --ion-color-secondary-tint: #62ceff; + + --ion-color-tertiary: #6a64ff; + --ion-color-tertiary-rgb: 106,100,255; + --ion-color-tertiary-contrast: #ffffff; + --ion-color-tertiary-contrast-rgb: 255,255,255; + --ion-color-tertiary-shade: #5d58e0; + --ion-color-tertiary-tint: #7974ff; + + --ion-color-success: #2fdf75; + --ion-color-success-rgb: 47,223,117; + --ion-color-success-contrast: #000000; + --ion-color-success-contrast-rgb: 0,0,0; + --ion-color-success-shade: #29c467; + --ion-color-success-tint: #44e283; + + --ion-color-warning: #ffd534; + --ion-color-warning-rgb: 255,213,52; + --ion-color-warning-contrast: #000000; + --ion-color-warning-contrast-rgb: 0,0,0; + --ion-color-warning-shade: #e0bb2e; + --ion-color-warning-tint: #ffd948; + + --ion-color-danger: #ff4961; + --ion-color-danger-rgb: 255,73,97; + --ion-color-danger-contrast: #ffffff; + --ion-color-danger-contrast-rgb: 255,255,255; + --ion-color-danger-shade: #e04055; + --ion-color-danger-tint: #ff5b71; + + --ion-color-dark: #f4f5f8; + --ion-color-dark-rgb: 244,245,248; + --ion-color-dark-contrast: #000000; + --ion-color-dark-contrast-rgb: 0,0,0; + --ion-color-dark-shade: #d7d8da; + --ion-color-dark-tint: #f5f6f9; + + --ion-color-medium: #989aa2; + --ion-color-medium-rgb: 152,154,162; + --ion-color-medium-contrast: #000000; + --ion-color-medium-contrast-rgb: 0,0,0; + --ion-color-medium-shade: #86888f; + --ion-color-medium-tint: #a2a4ab; + + --ion-color-light: #222428; + --ion-color-light-rgb: 34,36,40; + --ion-color-light-contrast: #ffffff; + --ion-color-light-contrast-rgb: 255,255,255; + --ion-color-light-shade: #1e2023; + --ion-color-light-tint: #383a3e; + } + + /* + * iOS Dark Theme + * ------------------------------------------- + */ + + .ios body { + --ion-background-color: #000000; + --ion-background-color-rgb: 0,0,0; + + --ion-text-color: #ffffff; + --ion-text-color-rgb: 255,255,255; + + --ion-color-step-50: #0d0d0d; + --ion-color-step-100: #1a1a1a; + --ion-color-step-150: #262626; + --ion-color-step-200: #333333; + --ion-color-step-250: #404040; + --ion-color-step-300: #4d4d4d; + --ion-color-step-350: #595959; + --ion-color-step-400: #666666; + --ion-color-step-450: #737373; + --ion-color-step-500: #808080; + --ion-color-step-550: #8c8c8c; + --ion-color-step-600: #999999; + --ion-color-step-650: #a6a6a6; + --ion-color-step-700: #b3b3b3; + --ion-color-step-750: #bfbfbf; + --ion-color-step-800: #cccccc; + --ion-color-step-850: #d9d9d9; + --ion-color-step-900: #e6e6e6; + --ion-color-step-950: #f2f2f2; + + --ion-item-background: #000000; + + --ion-card-background: #1c1c1d; + } + + .ios ion-modal { + --ion-background-color: var(--ion-color-step-100); + --ion-toolbar-background: var(--ion-color-step-150); + --ion-toolbar-border-color: var(--ion-color-step-250); + } + + + /* + * Material Design Dark Theme + * ------------------------------------------- + */ + + .md body { + --ion-background-color: #121212; + --ion-background-color-rgb: 18,18,18; + + --ion-text-color: #ffffff; + --ion-text-color-rgb: 255,255,255; + + --ion-border-color: #222222; + + --ion-color-step-50: #1e1e1e; + --ion-color-step-100: #2a2a2a; + --ion-color-step-150: #363636; + --ion-color-step-200: #414141; + --ion-color-step-250: #4d4d4d; + --ion-color-step-300: #595959; + --ion-color-step-350: #656565; + --ion-color-step-400: #717171; + --ion-color-step-450: #7d7d7d; + --ion-color-step-500: #898989; + --ion-color-step-550: #949494; + --ion-color-step-600: #a0a0a0; + --ion-color-step-650: #acacac; + --ion-color-step-700: #b8b8b8; + --ion-color-step-750: #c4c4c4; + --ion-color-step-800: #d0d0d0; + --ion-color-step-850: #dbdbdb; + --ion-color-step-900: #e7e7e7; + --ion-color-step-950: #f3f3f3; + + --ion-item-background: #1e1e1e; + + --ion-toolbar-background: #1f1f1f; + + --ion-tab-bar-background: #1f1f1f; + + --ion-card-background: #1e1e1e; + } +} diff --git a/demo/src/zone-flags.ts b/demo/src/zone-flags.ts new file mode 100644 index 00000000..c84245fd --- /dev/null +++ b/demo/src/zone-flags.ts @@ -0,0 +1,6 @@ +/** + * Prevents Angular change detection from + * running with certain Web Component callbacks + */ +// eslint-disable-next-line no-underscore-dangle +(window as any).__Zone_disable_customElements = true; diff --git a/demo/tsconfig.app.json b/demo/tsconfig.app.json new file mode 100644 index 00000000..82d91dc4 --- /dev/null +++ b/demo/tsconfig.app.json @@ -0,0 +1,15 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/app", + "types": [] + }, + "files": [ + "src/main.ts", + "src/polyfills.ts" + ], + "include": [ + "src/**/*.d.ts" + ] +} diff --git a/demo/tsconfig.json b/demo/tsconfig.json new file mode 100644 index 00000000..5acda4a7 --- /dev/null +++ b/demo/tsconfig.json @@ -0,0 +1,23 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "compileOnSave": false, + "compilerOptions": { + "baseUrl": "./", + "outDir": "./dist/out-tsc", + "sourceMap": true, + "declaration": false, + "downlevelIteration": true, + "experimentalDecorators": true, + "moduleResolution": "node", + "importHelpers": true, + "target": "es2015", + "module": "es2020", + "lib": ["es2018", "dom"] + }, + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/demo/tsconfig.spec.json b/demo/tsconfig.spec.json new file mode 100644 index 00000000..092345b0 --- /dev/null +++ b/demo/tsconfig.spec.json @@ -0,0 +1,18 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/spec", + "types": [ + "jasmine" + ] + }, + "files": [ + "src/test.ts", + "src/polyfills.ts" + ], + "include": [ + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} diff --git a/package.json b/package.json index 962b31a3..438417c5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "version": "2.3.2", - "name": "cordova-plugin-telerik-imagepicker", + "name": "@spoonconsulting/cordova-plugin-telerik-imagepicker", + "version": "2.0.0", "cordova_name": "ImagePicker", "description": "This plugin allows selection of multiple images from the camera roll / gallery in a phonegap app", "license": "MIT", @@ -10,20 +10,22 @@ "android", "ios" ], + "author": "Telerik-Verified-Plugins & spoonconsulting", + "repository": { + "type": "git", + "url": "git+https://github.com/spoonconsulting/cordova-plugin-telerik-imagepicker.git" + }, "cordova": { - "id": "cordova-plugin-telerik-imagepicker", + "id": "@spoonconsulting/cordova-plugin-telerik-imagepicker", "platforms": [ "ios", "android", "wp8" ] }, - "repository": { - "type": "git", - "url": "git+https://github.com/Telerik-Verified-Plugins/ImagePicker.git" - }, "engines": { "name": "cordova", "version": ">=3.5.0" - } + }, + "homepage": "https://github.com/spoonconsulting/cordova-plugin-telerik-imagepicker" } diff --git a/plugin.xml b/plugin.xml index 4c4251d5..c538ea3d 100644 --- a/plugin.xml +++ b/plugin.xml @@ -1,8 +1,8 @@ + id="@spoonconsulting/cordova-plugin-telerik-imagepicker" + version="2.0.0"> ImagePicker @@ -17,7 +17,7 @@ - + @@ -87,6 +87,7 @@ +
@@ -94,58 +95,12 @@ - + - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/src/android/ImagePicker.java b/src/android/ImagePicker.java new file mode 100644 index 00000000..7280a4a6 --- /dev/null +++ b/src/android/ImagePicker.java @@ -0,0 +1,204 @@ +package com.spoon.imagepicker; + +import org.apache.cordova.CallbackContext; +import org.apache.cordova.CordovaPlugin; +import org.apache.cordova.PluginResult; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import android.Manifest; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.ClipData; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.database.Cursor; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.provider.MediaStore; +import android.provider.OpenableColumns; +import android.util.Log; +import android.widget.Toast; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.util.ArrayList; + +import androidx.core.content.ContextCompat; + +public class ImagePicker extends CordovaPlugin { + private static final String ACTION_GET_PICTURES = "getPictures"; + private static final String ACTION_HAS_READ_PERMISSION = "hasReadPermission"; + private static final String ACTION_REQUEST_READ_PERMISSION = "requestReadPermission"; + + private static final int PERMISSION_REQUEST_CODE = 100; + private static final int SELECT_PICTURE = 200; + + private static final String CROSS_USER_PROFILE_ACCESS_DENIED = "Cannot access file. (-1)"; + + private CallbackContext callbackContext; + private int maxImageCount; + + public boolean execute(String action, final JSONArray args, final CallbackContext callbackContext) throws JSONException { + this.callbackContext = callbackContext; + if (ACTION_HAS_READ_PERMISSION.equals(action)) { + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, hasReadPermission())); + return true; + + } else if (ACTION_REQUEST_READ_PERMISSION.equals(action)) { + requestReadPermission(); + return true; + + } else if (ACTION_GET_PICTURES.equals(action)) { + + final JSONObject params = args.getJSONObject(0); + this.maxImageCount = params.has("maximumImagesCount") ? params.getInt("maximumImagesCount") : 20; + + Intent imagePickerIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT, MediaStore.Images.Media.EXTERNAL_CONTENT_URI); + imagePickerIntent.setType("image/*"); + imagePickerIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); + + cordova.startActivityForResult(this, imagePickerIntent, SELECT_PICTURE); + this.showMaxLimitWarning(); + return true; + } + return false; + } + + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (resultCode == Activity.RESULT_OK && data != null) { + ArrayList fileURIs = new ArrayList(); + if (requestCode == SELECT_PICTURE) { + if (data.getData() != null) { + Uri uri = data.getData(); + String path = this.copyFileToInternalStorage(uri, ""); + if (path.equals("-1")) { + callbackContext.error(CROSS_USER_PROFILE_ACCESS_DENIED); + return; + } + fileURIs.add(path); + } else { + ClipData clip = data.getClipData(); + for (int i=0; i this.maxImageCount - 1) { break; } + } + } + } + JSONArray res = new JSONArray(fileURIs); + callbackContext.success(res); + + } else if (resultCode == Activity.RESULT_CANCELED && data != null) { + String error = data.getStringExtra("ERRORMESSAGE"); + callbackContext.error(error); + + } else if (resultCode == Activity.RESULT_CANCELED) { + JSONArray res = new JSONArray(); + callbackContext.success(res); + + } else { + callbackContext.error("No images selected"); + } + } + + /** + * Choosing a picture launches another Activity, so we need to implement the + * save/restore APIs to handle the case where the CordovaActivity is killed by the OS + * before we get the launched Activity's result. + * + * @see http://cordova.apache.org/docs/en/dev/guide/platforms/android/plugin.html#launching-other-activities + */ + public void onRestoreStateForActivityResult(Bundle state, CallbackContext callbackContext) { + this.callbackContext = callbackContext; + } + + + @Override + public void onRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) throws JSONException { + + // For now we just have one permission, so things can be kept simple... + if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + callbackContext.success(1); + } else { + callbackContext.success(0); + } + } + + @SuppressLint("InlinedApi") + private boolean hasReadPermission() { + return Build.VERSION.SDK_INT < 23 || + PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(this.cordova.getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE); + } + + @SuppressLint("InlinedApi") + private void requestReadPermission() { + if (!hasReadPermission()) { + cordova.requestPermissions(this, PERMISSION_REQUEST_CODE, new String[] {Manifest.permission.READ_EXTERNAL_STORAGE}); + return; + } + callbackContext.success(1); + } + + private String copyFileToInternalStorage(Uri uri, String newDirName) { + Uri returnUri = uri; + Cursor returnCursor = null; + try { + returnCursor = cordova.getActivity().getContentResolver().query( + returnUri, + new String[] { OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE }, + null, + null, + null + ); + } catch (SecurityException se) { + String toastMsg = "For the moment cross sharing of media between work profile and personal profile is not supported."; + (Toast.makeText(cordova.getContext(), toastMsg, Toast.LENGTH_LONG)).show(); + Log.d("error", se.getMessage()); + return "-1"; + } + + int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); + returnCursor.moveToFirst(); + String name = returnCursor.getString(nameIndex); + + File output; + if (!newDirName.equals("")) { + File dir = new File(cordova.getContext().getFilesDir() + "/" + newDirName); + if (!dir.exists()) { dir.mkdir(); } + output = new File(cordova.getContext().getFilesDir() + "/" + newDirName + "/" + name); + } else { + output = new File(cordova.getContext().getFilesDir() + "/" + name); + } + try { + InputStream inputStream = cordova.getActivity().getContentResolver().openInputStream(uri); + FileOutputStream outputStream = new FileOutputStream(output); + int read = 0; + int bufferSize = 1024; + final byte[] buffers = new byte[bufferSize]; + while ((read = inputStream.read(buffers)) != -1) { + outputStream.write(buffers, 0, read); + } + inputStream.close(); + outputStream.close(); + + } catch (Exception e) { + Log.e("copyToInternalStorage ", e.getMessage()); + } + + return output.getPath(); + } + + private void showMaxLimitWarning() { + String toastMsg = "Only the first " + this.maxImageCount + " images selected will be taken."; + (Toast.makeText(cordova.getContext(), toastMsg, Toast.LENGTH_LONG)).show(); + } +} diff --git a/src/android/Library/res/anim/image_pop_in.xml b/src/android/Library/res/anim/image_pop_in.xml deleted file mode 100644 index 3b1f7e9d..00000000 --- a/src/android/Library/res/anim/image_pop_in.xml +++ /dev/null @@ -1,11 +0,0 @@ - - diff --git a/src/android/Library/res/drawable-hdpi/icon.png b/src/android/Library/res/drawable-hdpi/icon.png deleted file mode 100644 index 8074c4c5..00000000 Binary files a/src/android/Library/res/drawable-hdpi/icon.png and /dev/null differ diff --git a/src/android/Library/res/drawable-hdpi/image_bg.9.png b/src/android/Library/res/drawable-hdpi/image_bg.9.png deleted file mode 100644 index 9835be61..00000000 Binary files a/src/android/Library/res/drawable-hdpi/image_bg.9.png and /dev/null differ diff --git a/src/android/Library/res/drawable-hdpi/loading_icon.png b/src/android/Library/res/drawable-hdpi/loading_icon.png deleted file mode 100644 index 3490f83d..00000000 Binary files a/src/android/Library/res/drawable-hdpi/loading_icon.png and /dev/null differ diff --git a/src/android/Library/res/drawable-ldpi/icon.png b/src/android/Library/res/drawable-ldpi/icon.png deleted file mode 100644 index 1095584e..00000000 Binary files a/src/android/Library/res/drawable-ldpi/icon.png and /dev/null differ diff --git a/src/android/Library/res/drawable-mdpi/ic_action_discard_dark.png b/src/android/Library/res/drawable-mdpi/ic_action_discard_dark.png deleted file mode 100644 index b65f4c66..00000000 Binary files a/src/android/Library/res/drawable-mdpi/ic_action_discard_dark.png and /dev/null differ diff --git a/src/android/Library/res/drawable-mdpi/ic_action_discard_light.png b/src/android/Library/res/drawable-mdpi/ic_action_discard_light.png deleted file mode 100644 index d74c9d5f..00000000 Binary files a/src/android/Library/res/drawable-mdpi/ic_action_discard_light.png and /dev/null differ diff --git a/src/android/Library/res/drawable-mdpi/ic_action_done_dark.png b/src/android/Library/res/drawable-mdpi/ic_action_done_dark.png deleted file mode 100644 index b8fb4f84..00000000 Binary files a/src/android/Library/res/drawable-mdpi/ic_action_done_dark.png and /dev/null differ diff --git a/src/android/Library/res/drawable-mdpi/ic_action_done_light.png b/src/android/Library/res/drawable-mdpi/ic_action_done_light.png deleted file mode 100644 index e5d82fdf..00000000 Binary files a/src/android/Library/res/drawable-mdpi/ic_action_done_light.png and /dev/null differ diff --git a/src/android/Library/res/drawable-mdpi/ic_launcher.png b/src/android/Library/res/drawable-mdpi/ic_launcher.png deleted file mode 100644 index 9dc7f218..00000000 Binary files a/src/android/Library/res/drawable-mdpi/ic_launcher.png and /dev/null differ diff --git a/src/android/Library/res/drawable-mdpi/icon.png b/src/android/Library/res/drawable-mdpi/icon.png deleted file mode 100644 index a07c69fa..00000000 Binary files a/src/android/Library/res/drawable-mdpi/icon.png and /dev/null differ diff --git a/src/android/Library/res/drawable-xhdpi/ic_action_discard_dark.png b/src/android/Library/res/drawable-xhdpi/ic_action_discard_dark.png deleted file mode 100644 index 4bfac666..00000000 Binary files a/src/android/Library/res/drawable-xhdpi/ic_action_discard_dark.png and /dev/null differ diff --git a/src/android/Library/res/drawable-xhdpi/ic_action_discard_light.png b/src/android/Library/res/drawable-xhdpi/ic_action_discard_light.png deleted file mode 100644 index 24256f15..00000000 Binary files a/src/android/Library/res/drawable-xhdpi/ic_action_discard_light.png and /dev/null differ diff --git a/src/android/Library/res/drawable-xhdpi/ic_action_done_dark.png b/src/android/Library/res/drawable-xhdpi/ic_action_done_dark.png deleted file mode 100644 index f70a494f..00000000 Binary files a/src/android/Library/res/drawable-xhdpi/ic_action_done_dark.png and /dev/null differ diff --git a/src/android/Library/res/drawable-xhdpi/ic_action_done_light.png b/src/android/Library/res/drawable-xhdpi/ic_action_done_light.png deleted file mode 100644 index 71094a09..00000000 Binary files a/src/android/Library/res/drawable-xhdpi/ic_action_done_light.png and /dev/null differ diff --git a/src/android/Library/res/drawable-xhdpi/ic_launcher.png b/src/android/Library/res/drawable-xhdpi/ic_launcher.png deleted file mode 100644 index 75578f40..00000000 Binary files a/src/android/Library/res/drawable-xhdpi/ic_launcher.png and /dev/null differ diff --git a/src/android/Library/res/drawable/grid_background.xml b/src/android/Library/res/drawable/grid_background.xml deleted file mode 100644 index d57bb389..00000000 --- a/src/android/Library/res/drawable/grid_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - \ No newline at end of file diff --git a/src/android/Library/res/layout/actionbar_custom_view_done_discard.xml b/src/android/Library/res/layout/actionbar_custom_view_done_discard.xml deleted file mode 100644 index 0b61fb97..00000000 --- a/src/android/Library/res/layout/actionbar_custom_view_done_discard.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - diff --git a/src/android/Library/res/layout/actionbar_discard_button.xml b/src/android/Library/res/layout/actionbar_discard_button.xml deleted file mode 100644 index 3d77b03f..00000000 --- a/src/android/Library/res/layout/actionbar_discard_button.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - diff --git a/src/android/Library/res/layout/actionbar_done_button.xml b/src/android/Library/res/layout/actionbar_done_button.xml deleted file mode 100644 index 33387c2c..00000000 --- a/src/android/Library/res/layout/actionbar_done_button.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - diff --git a/src/android/Library/res/layout/multiselectorgrid.xml b/src/android/Library/res/layout/multiselectorgrid.xml deleted file mode 100644 index 01f8e2d6..00000000 --- a/src/android/Library/res/layout/multiselectorgrid.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/src/android/Library/res/values-de/multiimagechooser_strings_de.xml b/src/android/Library/res/values-de/multiimagechooser_strings_de.xml deleted file mode 100644 index ea2825f9..00000000 --- a/src/android/Library/res/values-de/multiimagechooser_strings_de.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - MultiImageChooser - Freie Version - Nur noch %d Bilder können ausgewählt werden - Beim Öffnen der Bilder-Datenbank ist ein Fehler augetreten. Bitte melden Sie dieses Problem. - Vorschaubilder werden geladen, bitte haben Sie etwas Geduld - Bilder werden verarbeitet - Dies kann einen Moment dauern - diff --git a/src/android/Library/res/values-es/multiimagechooser_strings_es.xml b/src/android/Library/res/values-es/multiimagechooser_strings_es.xml deleted file mode 100644 index 5a131cf9..00000000 --- a/src/android/Library/res/values-es/multiimagechooser_strings_es.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - MultiImageChooser - Solicitando miniaturas. Por favor, espere… - Versión gratuita - Imágenes restantes: %d - Error al abrir la base de datos de imágenes. - Procesando imágenes - Esto puede tomar un momento - Cancelar - OK - \ No newline at end of file diff --git a/src/android/Library/res/values-fr/multiimagechooser_strings_fr.xml b/src/android/Library/res/values-fr/multiimagechooser_strings_fr.xml deleted file mode 100644 index 964f1900..00000000 --- a/src/android/Library/res/values-fr/multiimagechooser_strings_fr.xml +++ /dev/null @@ -1,6 +0,0 @@ - - "MultiImageChooser" - "La version gratuite - gauche Images:%d" - "Il y avait une erreur d'ouvrir la base de données images. S'il vous plaît signaler le problème." - "Demande de vignettes, s'il vous plaît soyez patient" - \ No newline at end of file diff --git a/src/android/Library/res/values-hu/multiimagechooser_strings_hu.xml b/src/android/Library/res/values-hu/multiimagechooser_strings_hu.xml deleted file mode 100644 index 1c60b5a0..00000000 --- a/src/android/Library/res/values-hu/multiimagechooser_strings_hu.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - MultiImageChooser - Ingyenes verzió - hátralévő képek: %d - Képadatbázis megnyitási hiba történt. Kérjük, jelentse a problémát. - Miniatűrök lekérése, kérjük legyen türelemmel - \ No newline at end of file diff --git a/src/android/Library/res/values-ja/multiimagechooser_strings_ja.xml b/src/android/Library/res/values-ja/multiimagechooser_strings_ja.xml deleted file mode 100644 index 92f084a0..00000000 --- a/src/android/Library/res/values-ja/multiimagechooser_strings_ja.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - MultiImageChooser - 無料版 - 残りの画像: %d - 画像データベースを開く際にエラーがありました。問題を報告してください。 - サムネイルをリクエスト中です。お待ちください。 - diff --git a/src/android/Library/res/values-ko/multiimagechooser_strings_ko.xml b/src/android/Library/res/values-ko/multiimagechooser_strings_ko.xml deleted file mode 100644 index 4454379c..00000000 --- a/src/android/Library/res/values-ko/multiimagechooser_strings_ko.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - MultiImageChooser - 무료 버전 - 남은 이미지: %d - 이미지 데이터베이스를 여는 데 오류가 발생했습니다. 문제를 보고하세요. - 썸네일 요청 중. 기다려주세요 - diff --git a/src/android/Library/res/values-pl/multiimagechooser_strings_pl.xml b/src/android/Library/res/values-pl/multiimagechooser_strings_pl.xml deleted file mode 100644 index 860c08e8..00000000 --- a/src/android/Library/res/values-pl/multiimagechooser_strings_pl.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - MultiImageChooser - Darmowa wersja - Zdjęć zostało: %d - Wystąpił problem przy próbie otwarcia bazy zdjęć. Proszę, zgłoś problem. - Pobieram miniaturki, proszę o cierpliwość - Przetwarzam zdjęcia - To może chwilę zająć - Anuluj - OK - diff --git a/src/android/Library/res/values-sv/multiimagechooser_strings_sv.xml b/src/android/Library/res/values-sv/multiimagechooser_strings_sv.xml deleted file mode 100644 index 2f73c0fc..00000000 --- a/src/android/Library/res/values-sv/multiimagechooser_strings_sv.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - MultiImageChooser - Gratisversion - Bilder kvar: %d - Det gick inte att öppna bilddatabasen. Var vänlig rapportera detta problem. - Hämtar tumnaglar, var god vänta - Behandlar bilder - Det här kan ta en stund - diff --git a/src/android/Library/res/values/multiimagechooser_strings_en.xml b/src/android/Library/res/values/multiimagechooser_strings_en.xml deleted file mode 100644 index 286803a2..00000000 --- a/src/android/Library/res/values/multiimagechooser_strings_en.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - MultiImageChooser - Free version - Images left: %d - There was an error opening the images database. Please report the problem. - Requesting thumbnails, please be patient - Processing images - This may take a moment - Cancel - OK - diff --git a/src/android/Library/res/values/themes.xml b/src/android/Library/res/values/themes.xml deleted file mode 100644 index 2ec73cf1..00000000 --- a/src/android/Library/res/values/themes.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/src/android/Library/src/ImageFetcher.java b/src/android/Library/src/ImageFetcher.java deleted file mode 100644 index 170380b1..00000000 --- a/src/android/Library/src/ImageFetcher.java +++ /dev/null @@ -1,381 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.synconset; - -import java.lang.ref.SoftReference; -import java.lang.ref.WeakReference; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.RejectedExecutionException; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Color; -import android.graphics.drawable.ColorDrawable; -import android.graphics.drawable.Drawable; -import android.graphics.Matrix; -import android.os.AsyncTask; -import android.os.Build; -import android.os.Handler; -import android.provider.MediaStore; -import android.util.Log; -import android.view.View; -import android.view.animation.Animation; -import android.view.animation.AnimationUtils; -import android.widget.ImageView; - -/** - * This helper class download images from the Internet and binds those with the - * provided ImageView. - * - *

- * It requires the INTERNET permission, which should be added to your - * application's manifest file. - *

- * - * A local cache of downloaded images is maintained internally to improve - * performance. - */ -public class ImageFetcher { - - private int colWidth; - private long origId; - private ExecutorService executor; - - public ImageFetcher() { - executor = Executors.newCachedThreadPool(); - } - - public void fetch(Integer id, ImageView imageView, int colWidth, int rotate) { - resetPurgeTimer(); - this.colWidth = colWidth; - this.origId = id; - Bitmap bitmap = getBitmapFromCache(id); - - if (bitmap == null) { - forceDownload(id, imageView, rotate); - } else { - cancelPotentialDownload(id, imageView); - imageView.setImageBitmap(bitmap); - } - } - - /** - * Same as download but the image is always downloaded and the cache is not - * used. Kept private at the moment as its interest is not clear. - */ - private void forceDownload(Integer position, ImageView imageView, int rotate) { - if (position == null) { - imageView.setImageDrawable(null); - return; - } - - if (cancelPotentialDownload(position, imageView)) { - BitmapFetcherTask task = new BitmapFetcherTask(imageView.getContext(), imageView, rotate); - DownloadedDrawable downloadedDrawable = new DownloadedDrawable(imageView.getContext(), task, origId); - imageView.setImageDrawable(downloadedDrawable); - imageView.setMinimumHeight(colWidth); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - task.executeOnExecutor(executor, position); - } else { - try { - task.execute(position); - } catch (RejectedExecutionException e) { - // Oh :( - } - } - - } - } - - /** - * Returns true if the current download has been canceled or if there was no - * download in progress on this image view. Returns false if the download in - * progress deals with the same url. The download is not stopped in that - * case. - */ - private static boolean cancelPotentialDownload(Integer position, ImageView imageView) { - BitmapFetcherTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView); - long origId = getOrigId(imageView); - - if (bitmapDownloaderTask != null) { - Integer bitmapPosition = bitmapDownloaderTask.position; - if ((bitmapPosition == null) || (!bitmapPosition.equals(position))) { - // Log.d("DAVID", "Canceling..."); - MediaStore.Images.Thumbnails.cancelThumbnailRequest(imageView.getContext().getContentResolver(), - origId, 12345); - bitmapDownloaderTask.cancel(true); - } else { - return false; - } - } - return true; - } - - /** - * @param imageView - * Any imageView - * @return Retrieve the currently active download task (if any) associated - * with this imageView. null if there is no such task. - */ - private static BitmapFetcherTask getBitmapDownloaderTask(ImageView imageView) { - if (imageView != null) { - Drawable drawable = imageView.getDrawable(); - if (drawable instanceof DownloadedDrawable) { - DownloadedDrawable downloadedDrawable = (DownloadedDrawable) drawable; - return downloadedDrawable.getBitmapDownloaderTask(); - } - } - return null; - } - - private static long getOrigId(ImageView imageView) { - if (imageView != null) { - Drawable drawable = imageView.getDrawable(); - if (drawable instanceof DownloadedDrawable) { - DownloadedDrawable downloadedDrawable = (DownloadedDrawable) drawable; - return downloadedDrawable.getOrigId(); - } - } - return -1; - } - - /** - * The actual AsyncTask that will asynchronously download the image. - */ - class BitmapFetcherTask extends AsyncTask { - private Integer position; - private final WeakReference imageViewReference; - private final Context mContext; - private final int rotate; - - public BitmapFetcherTask(Context context, ImageView imageView, int rotate) { - imageViewReference = new WeakReference(imageView); - mContext = context; - this.rotate = rotate; - } - - /** - * Actual download method. - */ - @Override - protected Bitmap doInBackground(Integer... params) { - try { - position = params[0]; - if (isCancelled()) { - return null; - } - Bitmap thumb = MediaStore.Images.Thumbnails.getThumbnail(mContext.getContentResolver(), position, 12345, - MediaStore.Images.Thumbnails.MINI_KIND, null); - if (isCancelled()) { - return null; - } - if (thumb == null) { - return null; - } else { - if (isCancelled()) { - return null; - } else { - if (rotate != 0) { - Matrix matrix = new Matrix(); - matrix.setRotate(rotate); - thumb = Bitmap.createBitmap(thumb, 0, 0, thumb.getWidth(), thumb.getHeight(), matrix, true); - } - return thumb; - } - } - }catch(OutOfMemoryError error) { - clearCache(); - return null; - } - - } - - private void setInvisible() { - // Log.d("COLLAGE", "Setting something invisible..."); - if (imageViewReference != null) { - final ImageView imageView = imageViewReference.get(); - BitmapFetcherTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView); - if (this == bitmapDownloaderTask) { - imageView.setVisibility(View.GONE); - imageView.setClickable(false); - imageView.setEnabled(false); - } - } - } - - /** - * Once the image is downloaded, associates it to the imageView - */ - @Override - protected void onPostExecute(Bitmap bitmap) { - if (isCancelled()) { - bitmap = null; - } - addBitmapToCache(position, bitmap); - if (imageViewReference != null) { - ImageView imageView = imageViewReference.get(); - BitmapFetcherTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView); - if (this == bitmapDownloaderTask) { - imageView.setImageBitmap(bitmap); - Animation anim = AnimationUtils.loadAnimation(imageView.getContext(), android.R.anim.fade_in); - imageView.setAnimation(anim); - anim.start(); - } - } else { - setInvisible(); - } - } - } - - /** - * A fake Drawable that will be attached to the imageView while the download - * is in progress. - * - *

- * Contains a reference to the actual download task, so that a download task - * can be stopped if a new binding is required, and makes sure that only the - * last started download process can bind its result, independently of the - * download finish order. - *

- */ - static class DownloadedDrawable extends ColorDrawable { - private final WeakReference bitmapDownloaderTaskReference; - private long origId; - - public DownloadedDrawable(Context mContext, BitmapFetcherTask bitmapDownloaderTask, long origId) { - super(Color.TRANSPARENT); - bitmapDownloaderTaskReference = new WeakReference(bitmapDownloaderTask); - this.origId = origId; - } - - public long getOrigId() { - return origId; - } - - public BitmapFetcherTask getBitmapDownloaderTask() { - return bitmapDownloaderTaskReference.get(); - } - } - - /* - * Cache-related fields and methods. - * - * We use a hard and a soft cache. A soft reference cache is too aggressively cleared by the - * Garbage Collector. - */ - - private static final int HARD_CACHE_CAPACITY = 100; - private static final int DELAY_BEFORE_PURGE = 10 * 1000; // in milliseconds - - // Hard cache, with a fixed maximum capacity and a life duration - private final HashMap sHardBitmapCache = new LinkedHashMap( - HARD_CACHE_CAPACITY / 2, 0.75f, true) { - @Override - protected boolean removeEldestEntry(HashMap.Entry eldest) { - if (size() > HARD_CACHE_CAPACITY) { - // Entries push-out of hard reference cache are transferred to - // soft reference cache - sSoftBitmapCache.put(eldest.getKey(), new SoftReference(eldest.getValue())); - return true; - } else - return false; - } - }; - - // Soft cache for bitmaps kicked out of hard cache - private final static ConcurrentHashMap> sSoftBitmapCache = new ConcurrentHashMap>( - HARD_CACHE_CAPACITY / 2); - - private final Handler purgeHandler = new Handler(); - - private final Runnable purger = new Runnable() { - public void run() { - clearCache(); - } - }; - - /** - * Adds this bitmap to the cache. - * - * @param bitmap - * The newly downloaded bitmap. - */ - private void addBitmapToCache(Integer position, Bitmap bitmap) { - if (bitmap != null) { - synchronized (sHardBitmapCache) { - sHardBitmapCache.put(position, bitmap); - } - } - } - - /** - * @param position - * The URL of the image that will be retrieved from the cache. - * @return The cached bitmap or null if it was not found. - */ - private Bitmap getBitmapFromCache(Integer position) { - // First try the hard reference cache - synchronized (sHardBitmapCache) { - final Bitmap bitmap = sHardBitmapCache.get(position); - if (bitmap != null) { - // Log.d("CACHE ****** ", "Hard hit!"); - // Bitmap found in hard cache - // Move element to first position, so that it is removed last - return bitmap; - } - } - - // Then try the soft reference cache - SoftReference bitmapReference = sSoftBitmapCache.get(position); - if (bitmapReference != null) { - final Bitmap bitmap = bitmapReference.get(); - if (bitmap != null) { - // Bitmap found in soft cache - // Log.d("CACHE ****** ", "Soft hit!"); - return bitmap; - } else { - // Soft reference has been Garbage Collected - sSoftBitmapCache.remove(position); - } - } - - return null; - } - - /** - * Clears the image cache used internally to improve performance. Note that - * for memory efficiency reasons, the cache will automatically be cleared - * after a certain inactivity delay. - */ - public void clearCache() { - sHardBitmapCache.clear(); - sSoftBitmapCache.clear(); - } - - /** - * Allow a new delay before the automatic cache clear is done. - */ - private void resetPurgeTimer() { - // purgeHandler.removeCallbacks(purger); - // purgeHandler.postDelayed(purger, DELAY_BEFORE_PURGE); - } -} diff --git a/src/android/Library/src/MultiImageChooserActivity.java b/src/android/Library/src/MultiImageChooserActivity.java deleted file mode 100644 index 1e48bf07..00000000 --- a/src/android/Library/src/MultiImageChooserActivity.java +++ /dev/null @@ -1,773 +0,0 @@ -/* - * Copyright (c) 2012, David Erosa - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDIN G NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE - * - * Code modified by Andrew Stephan for Sync OnSet - * - */ - -package com.synconset; - -import java.net.URI; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import com.synconset.FakeR; -import android.app.AlertDialog; -import android.app.LoaderManager; -import android.app.ProgressDialog; -import android.content.Context; -import android.content.CursorLoader; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.Loader; -import android.content.pm.ActivityInfo; -import android.database.Cursor; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Color; -import android.graphics.Matrix; -import android.net.Uri; -import android.os.AsyncTask; -import android.os.Bundle; -import android.provider.MediaStore; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AppCompatActivity; -import android.util.Base64; -import android.util.SparseBooleanArray; -import android.view.Display; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AbsListView; -import android.widget.AbsListView.OnScrollListener; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.BaseAdapter; -import android.widget.GridView; -import android.widget.ImageView; - -public class MultiImageChooserActivity extends AppCompatActivity implements - OnItemClickListener, - LoaderManager.LoaderCallbacks { - - private static final String TAG = "ImagePicker"; - - public static final int NOLIMIT = -1; - public static final String MAX_IMAGES_KEY = "MAX_IMAGES"; - public static final String WIDTH_KEY = "WIDTH"; - public static final String HEIGHT_KEY = "HEIGHT"; - public static final String QUALITY_KEY = "QUALITY"; - public static final String OUTPUT_TYPE_KEY = "OUTPUT_TYPE"; - - private ImageAdapter ia; - - private Cursor imagecursor, actualimagecursor; - private int image_column_index, image_column_orientation, actual_image_column_index, orientation_column_index; - private int colWidth; - - private static final int CURSORLOADER_THUMBS = 0; - private static final int CURSORLOADER_REAL = 1; - - private Map fileNames = new HashMap(); - - private SparseBooleanArray checkStatus = new SparseBooleanArray(); - - private int maxImages; - private int maxImageCount; - - private int desiredWidth; - private int desiredHeight; - private int quality; - private OutputType outputType; - - private final ImageFetcher fetcher = new ImageFetcher(); - - private int selectedColor = 0xff32b2e1; - private boolean shouldRequestThumb = true; - - private FakeR fakeR; - private View abDoneView; - private View abDiscardView; - - private ProgressDialog progress; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - fakeR = new FakeR(this); - setContentView(fakeR.getId("layout", "multiselectorgrid")); - fileNames.clear(); - - maxImages = getIntent().getIntExtra(MAX_IMAGES_KEY, NOLIMIT); - desiredWidth = getIntent().getIntExtra(WIDTH_KEY, 0); - desiredHeight = getIntent().getIntExtra(HEIGHT_KEY, 0); - quality = getIntent().getIntExtra(QUALITY_KEY, 0); - maxImageCount = maxImages; - outputType = OutputType.fromValue(getIntent().getIntExtra(OUTPUT_TYPE_KEY, 0)); - - Display display = getWindowManager().getDefaultDisplay(); - int width = display.getWidth(); - - colWidth = width / 4; - - GridView gridView = (GridView) findViewById(fakeR.getId("id", "gridview")); - gridView.setOnItemClickListener(this); - gridView.setOnScrollListener(new OnScrollListener() { - private int lastFirstItem = 0; - private long timestamp = System.currentTimeMillis(); - - @Override - public void onScrollStateChanged(AbsListView view, int scrollState) { - if (scrollState == SCROLL_STATE_IDLE) { - shouldRequestThumb = true; - ia.notifyDataSetChanged(); - } - } - - @Override - public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { - float dt = System.currentTimeMillis() - timestamp; - if (firstVisibleItem != lastFirstItem) { - double speed = 1 / dt * 1000; - lastFirstItem = firstVisibleItem; - timestamp = System.currentTimeMillis(); - - // Limit if we go faster than a page a second - shouldRequestThumb = speed < visibleItemCount; - } - } - }); - - ia = new ImageAdapter(); - gridView.setAdapter(ia); - - LoaderManager.enableDebugLogging(false); - getLoaderManager().initLoader(CURSORLOADER_THUMBS, null, this); - getLoaderManager().initLoader(CURSORLOADER_REAL, null, this); - setupHeader(); - updateAcceptButton(); - progress = new ProgressDialog(this); - progress.setTitle(getString(fakeR.getId("string", "multi_image_picker_processing_images_title"))); - progress.setMessage(getString(fakeR.getId("string", "multi_image_picker_processing_images_message"))); - } - - @Override - public void onItemClick(AdapterView arg0, View view, int position, long id) { - String name = getImageName(position); - int rotation = getImageRotation(position); - - if (name == null) { - return; - } - - boolean isChecked = !isChecked(position); - - if (maxImages == 0 && isChecked) { - isChecked = false; - new AlertDialog.Builder(this) - .setTitle("Maximum " + maxImageCount + " Photos") - .setMessage("You can only select " + maxImageCount + " photos at a time.") - .setPositiveButton("OK", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.cancel(); - } - }) - .create() - .show(); - - } else if (isChecked) { - fileNames.put(name, rotation); - - if (maxImageCount == 1) { - selectClicked(); - - } else { - maxImages--; - ImageView imageView = (ImageView) view; - - if (android.os.Build.VERSION.SDK_INT >= 16) { - imageView.setImageAlpha(128); - } else { - imageView.setAlpha(128); - } - - view.setBackgroundColor(selectedColor); - } - } else { - fileNames.remove(name); - maxImages++; - ImageView imageView = (ImageView) view; - - if (android.os.Build.VERSION.SDK_INT >= 16) { - imageView.setImageAlpha(255); - } else { - imageView.setAlpha(255); - } - - view.setBackgroundColor(Color.TRANSPARENT); - } - - checkStatus.put(position, isChecked); - updateAcceptButton(); - } - - @Override - public Loader onCreateLoader(int cursorID, Bundle arg1) { - ArrayList img = new ArrayList(); - switch (cursorID) { - case CURSORLOADER_THUMBS: - img.add(MediaStore.Images.Media._ID); - img.add(MediaStore.Images.Media.ORIENTATION); - break; - - case CURSORLOADER_REAL: - img.add(MediaStore.Images.Thumbnails.DATA); - img.add(MediaStore.Images.Media.ORIENTATION); - break; - } - - return new CursorLoader( - this, - MediaStore.Images.Media.EXTERNAL_CONTENT_URI, - img.toArray(new String[img.size()]), - null, - null, - "DATE_MODIFIED DESC" - ); - } - - @Override - public void onLoadFinished(Loader loader, Cursor cursor) { - if (cursor == null) { - // NULL cursor. This usually means there's no image database yet.... - return; - } - - switch (loader.getId()) { - case CURSORLOADER_THUMBS: - imagecursor = cursor; - image_column_index = imagecursor.getColumnIndex(MediaStore.Images.Media._ID); - image_column_orientation = imagecursor.getColumnIndex(MediaStore.Images.Media.ORIENTATION); - ia.notifyDataSetChanged(); - break; - - case CURSORLOADER_REAL: - actualimagecursor = cursor; - actual_image_column_index = actualimagecursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); - orientation_column_index = actualimagecursor.getColumnIndexOrThrow(MediaStore.Images.Media.ORIENTATION); - break; - } - } - - @Override - public void onLoaderReset(Loader loader) { - switch (loader.getId()) { - case CURSORLOADER_THUMBS: - imagecursor = null; - break; - - case CURSORLOADER_REAL: - actualimagecursor = null; - break; - } - } - - public void cancelClicked() { - setResult(RESULT_CANCELED); - finish(); - } - - public void selectClicked() { - abDiscardView.setEnabled(false); - abDoneView.setEnabled(false); - progress.show(); - - if (fileNames.isEmpty()) { - setResult(RESULT_CANCELED); - progress.dismiss(); - finish(); - } else { - setRequestedOrientation(getResources().getConfiguration().orientation); //prevent orientation changes during processing - new ResizeImagesTask().execute(fileNames.entrySet()); - } - } - - - /********************* - * Helper Methods - ********************/ - private void updateAcceptButton() { - if (abDoneView != null) { - abDoneView.setEnabled(fileNames.size() != 0); - } - } - - private void setupHeader() { - // From Roman Nkk's code - // https://plus.google.com/113735310430199015092/posts/R49wVvcDoEW - // Inflate a "Done/Discard" custom action bar view - /* - * Copyright 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE); - View customActionBarView = inflater.inflate( - fakeR.getId("layout", "actionbar_custom_view_done_discard"), - null - ); - - abDoneView = customActionBarView.findViewById(fakeR.getId("id", "actionbar_done")); - abDoneView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - // "Done" - selectClicked(); - } - }); - - abDiscardView = customActionBarView.findViewById(fakeR.getId("id", "actionbar_discard")); - abDiscardView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - cancelClicked(); - } - }); - - // Show the custom action bar view and hide the normal Home icon and title. - ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.setDisplayOptions( - ActionBar.DISPLAY_SHOW_CUSTOM, - ActionBar.DISPLAY_SHOW_CUSTOM - | ActionBar.DISPLAY_SHOW_HOME - | ActionBar.DISPLAY_SHOW_TITLE - ); - actionBar.setCustomView(customActionBarView, new ActionBar.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT - )); - } - } - - private String getImageName(int position) { - actualimagecursor.moveToPosition(position); - String name = null; - - try { - name = actualimagecursor.getString(actual_image_column_index); - } catch (Exception e) { - // Do something? - } - - return name; - } - - private int getImageRotation(int position) { - actualimagecursor.moveToPosition(position); - int rotation = 0; - - try { - rotation = actualimagecursor.getInt(orientation_column_index); - } catch (Exception e) { - // Do something? - } - - return rotation; - } - - public boolean isChecked(int position) { - return checkStatus.get(position); - } - - - /********************* - * Nested Classes - ********************/ - private class SquareImageView extends ImageView { - public SquareImageView(Context context) { - super(context); - } - - @Override - public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, widthMeasureSpec); - } - } - - - private class ImageAdapter extends BaseAdapter { - - public int getCount() { - if (imagecursor != null) { - return imagecursor.getCount(); - } else { - return 0; - } - } - - public Object getItem(int position) { - return position; - } - - public long getItemId(int position) { - return position; - } - - // create a new ImageView for each item referenced by the Adapter - public View getView(int position, View convertView, ViewGroup parent) { - - if (convertView == null) { - ImageView temp = new SquareImageView(MultiImageChooserActivity.this); - temp.setScaleType(ImageView.ScaleType.CENTER_CROP); - convertView = temp; - } - - ImageView imageView = (ImageView) convertView; - imageView.setImageBitmap(null); - - if (!imagecursor.moveToPosition(position)) { - return imageView; - } - - if (image_column_index == -1) { - return imageView; - } - - final int id = imagecursor.getInt(image_column_index); - final int rotate = imagecursor.getInt(image_column_orientation); - - if (isChecked(position)) { - if (android.os.Build.VERSION.SDK_INT >= 16) { - imageView.setImageAlpha(128); - } else { - imageView.setAlpha(128); - } - - imageView.setBackgroundColor(selectedColor); - - } else { - if (android.os.Build.VERSION.SDK_INT >= 16) { - imageView.setImageAlpha(255); - } else { - imageView.setAlpha(255); - } - imageView.setBackgroundColor(Color.TRANSPARENT); - } - - if (shouldRequestThumb) { - fetcher.fetch(id, imageView, colWidth, rotate); - } - - return imageView; - } - } - - private class ResizeImagesTask extends AsyncTask>, Void, ArrayList> { - private Exception asyncTaskError = null; - - @Override - protected ArrayList doInBackground(Set>... fileSets) { - Set> fileNames = fileSets[0]; - ArrayList al = new ArrayList(); - try { - Iterator> i = fileNames.iterator(); - Bitmap bmp; - while (i.hasNext()) { - Entry imageInfo = i.next(); - File file = new File(imageInfo.getKey()); - int rotate = imageInfo.getValue(); - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inSampleSize = 1; - options.inJustDecodeBounds = true; - BitmapFactory.decodeFile(file.getAbsolutePath(), options); - int width = options.outWidth; - int height = options.outHeight; - float scale = calculateScale(width, height); - - if (scale < 1) { - int finalWidth = (int)(width * scale); - int finalHeight = (int)(height * scale); - int inSampleSize = calculateInSampleSize(options, finalWidth, finalHeight); - options = new BitmapFactory.Options(); - options.inSampleSize = inSampleSize; - - try { - bmp = this.tryToGetBitmap(file, options, rotate, true); - } catch (OutOfMemoryError e) { - options.inSampleSize = calculateNextSampleSize(options.inSampleSize); - try { - bmp = this.tryToGetBitmap(file, options, rotate, false); - } catch (OutOfMemoryError e2) { - throw new IOException("Unable to load image into memory."); - } - } - } else { - try { - bmp = this.tryToGetBitmap(file, null, rotate, false); - } catch(OutOfMemoryError e) { - options = new BitmapFactory.Options(); - options.inSampleSize = 2; - - try { - bmp = this.tryToGetBitmap(file, options, rotate, false); - } catch(OutOfMemoryError e2) { - options = new BitmapFactory.Options(); - options.inSampleSize = 4; - - try { - bmp = this.tryToGetBitmap(file, options, rotate, false); - } catch (OutOfMemoryError e3) { - throw new IOException("Unable to load image into memory."); - } - } - } - } - - if (outputType == OutputType.FILE_URI) { - file = storeImage(bmp, file.getName()); - al.add(Uri.fromFile(file).toString()); - - } else if (outputType == OutputType.BASE64_STRING) { - al.add(getBase64OfImage(bmp)); - } - } - return al; - } catch (IOException e) { - try { - asyncTaskError = e; - for (int i = 0; i < al.size(); i++) { - URI uri = new URI(al.get(i)); - File file = new File(uri); - file.delete(); - } - } catch (Exception ignore) { - } - - return new ArrayList(); - } - } - - @Override - protected void onPostExecute(ArrayList al) { - Intent data = new Intent(); - - if (asyncTaskError != null) { - Bundle res = new Bundle(); - res.putString("ERRORMESSAGE", asyncTaskError.getMessage()); - data.putExtras(res); - setResult(RESULT_CANCELED, data); - - } else if (al.size() > 0) { - Bundle res = new Bundle(); - res.putStringArrayList("MULTIPLEFILENAMES", al); - - if (imagecursor != null) { - res.putInt("TOTALFILES", imagecursor.getCount()); - } - - int sync = ResultIPC.get().setLargeData(res); - data.putExtra("bigdata:synccode", sync); - setResult(RESULT_OK, data); - - } else { - setResult(RESULT_CANCELED, data); - } - - progress.dismiss(); - finish(); - } - - private Bitmap tryToGetBitmap(File file, - BitmapFactory.Options options, - int rotate, - boolean shouldScale) throws IOException, OutOfMemoryError { - Bitmap bmp; - if (options == null) { - bmp = BitmapFactory.decodeFile(file.getAbsolutePath()); - } else { - bmp = BitmapFactory.decodeFile(file.getAbsolutePath(), options); - } - - if (bmp == null) { - throw new IOException("The image file could not be opened."); - } - - if (options != null && shouldScale) { - float scale = calculateScale(options.outWidth, options.outHeight); - bmp = this.getResizedBitmap(bmp, scale); - } - - if (rotate != 0) { - Matrix matrix = new Matrix(); - matrix.setRotate(rotate); - bmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true); - } - - return bmp; - } - - /* - * The following functions are originally from - * https://github.com/raananw/PhoneGap-Image-Resizer - * - * They have been modified by Andrew Stephan for Sync OnSet - * - * The software is open source, MIT Licensed. - * Copyright (C) 2012, webXells GmbH All Rights Reserved. - */ - private File storeImage(Bitmap bmp, String fileName) throws IOException { - int index = fileName.lastIndexOf('.'); - String name = fileName.substring(0, index); - String ext = fileName.substring(index); - File file = File.createTempFile("tmp_" + name, ext); - OutputStream outStream = new FileOutputStream(file); - - if (ext.compareToIgnoreCase(".png") == 0) { - bmp.compress(Bitmap.CompressFormat.PNG, quality, outStream); - } else { - bmp.compress(Bitmap.CompressFormat.JPEG, quality, outStream); - } - - outStream.flush(); - outStream.close(); - return file; - } - - private Bitmap getResizedBitmap(Bitmap bm, float factor) { - int width = bm.getWidth(); - int height = bm.getHeight(); - // create a matrix for the manipulation - Matrix matrix = new Matrix(); - // resize the bit map - matrix.postScale(factor, factor); - // recreate the new Bitmap - return Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false); - } - - private String getBase64OfImage(Bitmap bm) { - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - bm.compress(Bitmap.CompressFormat.JPEG, quality, byteArrayOutputStream); - byte[] byteArray = byteArrayOutputStream.toByteArray(); - return Base64.encodeToString(byteArray, Base64.NO_WRAP); - } - } - - private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { - // Raw height and width of image - final int height = options.outHeight; - final int width = options.outWidth; - int inSampleSize = 1; - - if (height > reqHeight || width > reqWidth) { - final int halfHeight = height / 2; - final int halfWidth = width / 2; - - // Calculate the largest inSampleSize value that is a power of 2 and keeps both - // height and width larger than the requested height and width. - while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) { - inSampleSize *= 2; - } - } - - return inSampleSize; - } - - private int calculateNextSampleSize(int sampleSize) { - double logBaseTwo = (int)(Math.log(sampleSize) / Math.log(2)); - return (int)Math.pow(logBaseTwo + 1, 2); - } - - private float calculateScale(int width, int height) { - float widthScale = 1.0f; - float heightScale = 1.0f; - float scale = 1.0f; - if (desiredWidth > 0 || desiredHeight > 0) { - if (desiredHeight == 0 && desiredWidth < width) { - scale = (float)desiredWidth/width; - - } else if (desiredWidth == 0 && desiredHeight < height) { - scale = (float)desiredHeight/height; - - } else { - if (desiredWidth > 0 && desiredWidth < width) { - widthScale = (float)desiredWidth/width; - } - - if (desiredHeight > 0 && desiredHeight < height) { - heightScale = (float)desiredHeight/height; - } - - if (widthScale < heightScale) { - scale = widthScale; - } else { - scale = heightScale; - } - } - } - - return scale; - } - - enum OutputType { - - FILE_URI(0), BASE64_STRING(1); - - int value; - - OutputType(int value) { - this.value = value; - } - - public static OutputType fromValue(int value) { - for (OutputType type : OutputType.values()) { - if (type.value == value) { - return type; - } - } - throw new IllegalArgumentException("Invalid enum value specified"); - } - } -} diff --git a/src/android/com/synconset/ImagePicker/FakeR.java b/src/android/com/synconset/ImagePicker/FakeR.java deleted file mode 100644 index 465b64f5..00000000 --- a/src/android/com/synconset/ImagePicker/FakeR.java +++ /dev/null @@ -1,48 +0,0 @@ -/* -The MIT License - -Copyright (c) 2010 Matt Kane - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Code taken from: https://github.com/wildabeast/BarcodeScanner -*/ -package com.synconset; - -import android.app.Activity; -import android.content.Context; - -/** - * R replacement for PhoneGap Build. - * - * ([^.\w])R\.(\w+)\.(\w+) - * $1fakeR("$2", "$3") - * - * @author Maciej Nux Jaros - */ -public class FakeR { - private Context context; - private String packageName; - - public FakeR(Activity activity) { - context = activity.getApplicationContext(); - packageName = context.getPackageName(); - } - - public FakeR(Context context) { - this.context = context; - packageName = context.getPackageName(); - } - - public int getId(String group, String key) { - return context.getResources().getIdentifier(key, group, packageName); - } - - public static int getId(Context context, String group, String key) { - return context.getResources().getIdentifier(key, group, context.getPackageName()); - } -} diff --git a/src/android/com/synconset/ImagePicker/ImagePicker.java b/src/android/com/synconset/ImagePicker/ImagePicker.java deleted file mode 100644 index b534736a..00000000 --- a/src/android/com/synconset/ImagePicker/ImagePicker.java +++ /dev/null @@ -1,173 +0,0 @@ -/** - * An Image Picker Plugin for Cordova/PhoneGap. - */ -package com.synconset; - -import org.apache.cordova.CallbackContext; -import org.apache.cordova.CordovaPlugin; - -import org.apache.cordova.PluginResult; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.ArrayList; - -import android.Manifest; -import android.annotation.SuppressLint; -import android.app.Activity; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.os.Build; -import android.os.Bundle; -import android.support.v4.app.ActivityCompat; -import android.support.v4.content.ContextCompat; - -public class ImagePicker extends CordovaPlugin { - - private static final String ACTION_GET_PICTURES = "getPictures"; - private static final String ACTION_HAS_READ_PERMISSION = "hasReadPermission"; - private static final String ACTION_REQUEST_READ_PERMISSION = "requestReadPermission"; - - private static final int PERMISSION_REQUEST_CODE = 100; - - private CallbackContext callbackContext; - - public boolean execute(String action, final JSONArray args, final CallbackContext callbackContext) throws JSONException { - this.callbackContext = callbackContext; - - if (ACTION_HAS_READ_PERMISSION.equals(action)) { - callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, hasReadPermission())); - return true; - - } else if (ACTION_REQUEST_READ_PERMISSION.equals(action)) { - requestReadPermission(); - return true; - - } else if (ACTION_GET_PICTURES.equals(action)) { - final JSONObject params = args.getJSONObject(0); - final Intent imagePickerIntent = new Intent(cordova.getActivity(), MultiImageChooserActivity.class); - int max = 20; - int desiredWidth = 0; - int desiredHeight = 0; - int quality = 100; - int outputType = 0; - if (params.has("maximumImagesCount")) { - max = params.getInt("maximumImagesCount"); - } - if (params.has("width")) { - desiredWidth = params.getInt("width"); - } - if (params.has("height")) { - desiredHeight = params.getInt("height"); - } - if (params.has("quality")) { - quality = params.getInt("quality"); - } - if (params.has("outputType")) { - outputType = params.getInt("outputType"); - } - - imagePickerIntent.putExtra("MAX_IMAGES", max); - imagePickerIntent.putExtra("WIDTH", desiredWidth); - imagePickerIntent.putExtra("HEIGHT", desiredHeight); - imagePickerIntent.putExtra("QUALITY", quality); - imagePickerIntent.putExtra("OUTPUT_TYPE", outputType); - - // some day, when everybody uses a cordova version supporting 'hasPermission', enable this: - /* - if (cordova != null) { - if (cordova.hasPermission(Manifest.permission.READ_EXTERNAL_STORAGE)) { - cordova.startActivityForResult(this, imagePickerIntent, 0); - } else { - cordova.requestPermission( - this, - PERMISSION_REQUEST_CODE, - Manifest.permission.READ_EXTERNAL_STORAGE - ); - } - } - */ - // .. until then use: - if (hasReadPermission()) { - cordova.startActivityForResult(this, imagePickerIntent, 0); - } else { - requestReadPermission(); - // The downside is the user needs to re-invoke this picker method. - // The best thing to do for the dev is check 'hasReadPermission' manually and - // run 'requestReadPermission' or 'getPictures' based on the outcome. - } - return true; - } - return false; - } - - @SuppressLint("InlinedApi") - private boolean hasReadPermission() { - return Build.VERSION.SDK_INT < 23 || - PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(this.cordova.getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE); - } - - @SuppressLint("InlinedApi") - private void requestReadPermission() { - if (!hasReadPermission()) { - ActivityCompat.requestPermissions( - this.cordova.getActivity(), - new String[] {Manifest.permission.READ_EXTERNAL_STORAGE}, - PERMISSION_REQUEST_CODE); - } - // This method executes async and we seem to have no known way to receive the result - // (that's why these methods were later added to Cordova), so simply returning ok now. - callbackContext.success(); - } - - public void onActivityResult(int requestCode, int resultCode, Intent data) { - if (resultCode == Activity.RESULT_OK && data != null) { - int sync = data.getIntExtra("bigdata:synccode", -1); - final Bundle bigData = ResultIPC.get().getLargeData(sync); - - ArrayList fileNames = bigData.getStringArrayList("MULTIPLEFILENAMES"); - - JSONArray res = new JSONArray(fileNames); - callbackContext.success(res); - - } else if (resultCode == Activity.RESULT_CANCELED && data != null) { - String error = data.getStringExtra("ERRORMESSAGE"); - callbackContext.error(error); - - } else if (resultCode == Activity.RESULT_CANCELED) { - JSONArray res = new JSONArray(); - callbackContext.success(res); - - } else { - callbackContext.error("No images selected"); - } - } - - /** - * Choosing a picture launches another Activity, so we need to implement the - * save/restore APIs to handle the case where the CordovaActivity is killed by the OS - * before we get the launched Activity's result. - * - * @see http://cordova.apache.org/docs/en/dev/guide/platforms/android/plugin.html#launching-other-activities - */ - public void onRestoreStateForActivityResult(Bundle state, CallbackContext callbackContext) { - this.callbackContext = callbackContext; - } - -/* - @Override - public void onRequestPermissionResult(int requestCode, - String[] permissions, - int[] grantResults) throws JSONException { - - // For now we just have one permission, so things can be kept simple... - if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - cordova.startActivityForResult(this, imagePickerIntent, 0); - } else { - // Tell the JS layer that something went wrong... - callbackContext.error("Permission denied"); - } - } -*/ -} diff --git a/src/android/com/synconset/ImagePicker/ResultIPC.java b/src/android/com/synconset/ImagePicker/ResultIPC.java deleted file mode 100644 index 714dd2e6..00000000 --- a/src/android/com/synconset/ImagePicker/ResultIPC.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.synconset; - -import android.os.Bundle; - -public class ResultIPC { - - private static ResultIPC instance; - - public synchronized static ResultIPC get() { - if (instance == null) { - instance = new ResultIPC (); - } - return instance; - } - - private int sync = 0; - - private Bundle largeData; - public int setLargeData(Bundle largeData) { - this.largeData = largeData; - return ++sync; - } - - public Bundle getLargeData(int request) { - return (request == sync) ? largeData : null; - } -} \ No newline at end of file diff --git a/src/android/ignorelinterrors.gradle b/src/android/ignorelinterrors.gradle deleted file mode 100644 index c1d8e4bc..00000000 --- a/src/android/ignorelinterrors.gradle +++ /dev/null @@ -1,5 +0,0 @@ -android { - lintOptions { - checkReleaseBuilds false - } -} \ No newline at end of file diff --git a/src/ios/GMImagePicker/GMGridViewController.m b/src/ios/GMImagePicker/GMGridViewController.m index 6636eb72..a2e30208 100755 --- a/src/ios/GMImagePicker/GMGridViewController.m +++ b/src/ios/GMImagePicker/GMGridViewController.m @@ -11,7 +11,7 @@ #import "GMAlbumsViewController.h" #import "GMGridViewCell.h" #import "GMPHAsset.h" - +#import //#import "PSYBlockTimer.h" #import "GMFetchItem.h" @@ -472,9 +472,14 @@ - (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtInde }]; - - - [ self.imageManager requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeDefault options:ph_options resultHandler:^(UIImage *result, NSDictionary *info) { + [[PHImageManager defaultManager] requestImageDataForAsset:asset + options:ph_options + resultHandler: + ^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) { + //CIImage* ciImage = [CIImage imageWithData:imageData]; + //NSLog(@"Metadata : %@", ciImage.properties); + + // [ self.imageManager requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeDefault options:ph_options resultHandler:^(UIImage *result, NSDictionary *info) { //dispatch_async(dispatch_get_main_queue(), ^{ @@ -487,35 +492,58 @@ - (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtInde fetch_item.be_progressed = false; fetch_item.be_finished = true; + + NSString *fileName =[asset valueForKey:@"filename"]; + NSString *fileExtension = [fileName pathExtension]; + if ([fileExtension containsString:@"heic"]) { + CIImage *ciImage = [CIImage imageWithData:imageData]; + NSData* data = [[[CIContext alloc] init] JPEGRepresentationOfImage:ciImage colorSpace:CGColorSpaceCreateDeviceRGB() options:@{}]; + imageData = data; + fileExtension = @"jpg"; + } + //asset.image_fullsize = result; + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); + NSString *libPath = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"NoCloud"]; NSString * filePath; do { - filePath = [NSString stringWithFormat:@"%@/%@%03d.%@", docsPath, CDV_PHOTO_PREFIX, docCount++, @"jpg"]; + + filePath = [NSString stringWithFormat:@"%@/%@.%@", libPath, [[NSUUID UUID] UUIDString], [fileExtension lowercaseString]]; } while ([fileMgr fileExistsAtPath:filePath]); fetch_item.be_saving_img = true; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [imageData writeToFile:filePath atomically:YES]; // @BVL: Added orientation-fix to correctly display the returned result // if ( ![ UIImageJPEGRepresentation(result, 1.0f ) writeToFile:filePath atomically:YES ] ) { // return; // } - + /* NSLog(@"original orientation: %ld",(UIImageOrientation)result.imageOrientation); UIImage *imageToDisplay = result.fixOrientation; // UIImage+fixOrientation extension NSLog(@"corrected orientation: %ld",(UIImageOrientation)imageToDisplay.imageOrientation); - - // setting compression to a low value (high compression) impact performance, but not actual img quality - if ( ![ UIImageJPEGRepresentation(imageToDisplay, 0.2f ) writeToFile:filePath atomically:YES ] ) { - return; + + if (info[@"PHImageFileURLKey"]){ + NSError* err; + [[NSFileManager defaultManager] copyItemAtPath:info[@"PHImageFileURLKey"] toPath:filePath error:&err]; + if (err){ + return NSLog(@"%@", err); + } + }else{ + // setting compression to a low value (high compression) impact performance, but not actual img quality + if ( ![ UIImageJPEGRepresentation(imageToDisplay, 0.2f ) writeToFile:filePath atomically:YES ] ) { + return; + } } + */ fetch_item.image_fullsize = filePath; fetch_item.be_saving_img = false; diff --git a/src/ios/SOSPicker.m b/src/ios/SOSPicker.m index 0e2e00e7..b41e9d81 100644 --- a/src/ios/SOSPicker.m +++ b/src/ios/SOSPicker.m @@ -32,35 +32,23 @@ - (void) hasReadPermission:(CDVInvokedUrlCommand *)command { } - (void) requestReadPermission:(CDVInvokedUrlCommand *)command { - // [PHPhotoLibrary requestAuthorization:] - // this method works only when it is a first time, see - // https://developer.apple.com/library/ios/documentation/Photos/Reference/PHPhotoLibrary_Class/ - - PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus]; - if (status == PHAuthorizationStatusAuthorized) { - NSLog(@"Access has been granted."); - - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; - } else if (status == PHAuthorizationStatusDenied) { - NSString* message = @"Access has been denied. Change your setting > this app > Photo enable"; - NSLog(@"%@", message); - - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:message]; - [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; - } else if (status == PHAuthorizationStatusNotDetermined) { - // Access has not been determined. requestAuthorization: is available - [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {}]; - - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; - } else if (status == PHAuthorizationStatusRestricted) { - NSString* message = @"Access has been restricted. Change your setting > Privacy > Photo enable"; - NSLog(@"%@", message); - - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:message]; - [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; + [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus authStatus) { + NSString* status = [self getCameraRollAuthorizationStatusAsString:authStatus]; + [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:status] callbackId:command.callbackId]; + }]; +} + +- (NSString*) getCameraRollAuthorizationStatusAsString: (PHAuthorizationStatus)authStatus +{ + NSString* status; + if(authStatus == PHAuthorizationStatusDenied || authStatus == PHAuthorizationStatusRestricted){ + status = @"denied"; + }else if(authStatus == PHAuthorizationStatusNotDetermined ){ + status = @"not_determined"; + }else if(authStatus == PHAuthorizationStatusAuthorized){ + status = @"authorized"; } + return status; } - (void) getPictures:(CDVInvokedUrlCommand *)command { @@ -137,7 +125,7 @@ - (UIImage*)imageByScalingNotCroppingForSize:(UIImage*)anImage toSize:(CGSize)fr scaledSize = CGSizeMake(floor(width * scaleFactor), floor(height * scaleFactor)); } - UIGraphicsBeginImageContext(scaledSize); // this will resize + UIGraphicsBeginImageContextWithOptions(scaledSize, YES, 1.0); // this will resize [sourceImage drawInRect:CGRectMake(0, 0, scaledSize.width, scaledSize.height)]; @@ -182,10 +170,10 @@ - (void)assetsPickerController:(GMImagePickerController *)picker didFinishPickin NSMutableArray * result_all = [[NSMutableArray alloc] init]; CGSize targetSize = CGSizeMake(self.width, self.height); NSFileManager* fileMgr = [[NSFileManager alloc] init]; - NSString* docsPath = [NSTemporaryDirectory()stringByStandardizingPath]; - + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); + NSString *libPath = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"NoCloud"]; + NSError* err = nil; - int i = 1; NSString* filePath; CDVPluginResult* result = nil; @@ -196,7 +184,7 @@ - (void)assetsPickerController:(GMImagePickerController *)picker didFinishPickin } do { - filePath = [NSString stringWithFormat:@"%@/%@%03d.%@", docsPath, CDV_PHOTO_PREFIX, i++, @"jpg"]; + filePath = [NSString stringWithFormat:@"%@/%@.%@", libPath, [[NSUUID UUID] UUIDString], @"jpg"]; } while ([fileMgr fileExistsAtPath:filePath]); NSData* data = nil; @@ -209,6 +197,7 @@ - (void)assetsPickerController:(GMImagePickerController *)picker didFinishPickin if (self.quality == 100) { // no scaling, no downsampling, this is the fastest option [result_all addObject:item.image_fullsize]; + } else { // resample first UIImage* image = [UIImage imageNamed:item.image_fullsize];