diff --git a/README.md b/README.md index 7260741..a411e75 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,32 @@ Scientists, (app) developers, project partners, people who are lookikng for lo ## Documentation More in depth documentation is available on ZENODO: https://zenodo.org/record/7615472#.Y-JidC8w2gQ +## Installation and setup +### Prerequisites +- Node.js +- Ionic / capactior + +- Git +- Xcode (for iOS) +- Android Studio (for Android) + +A Parse server (for example the one provided by Pocket Science, DIY or Back4App) is required for the app to work. +A Firebase account for login and push notifications is required. + +### Installation + +Rename the provided .app. constant example to app.copnstnt and fill in the required fields. + + +1. Clone the repository +2. Install the dependencies + npm install +3. Run the app + + + + + ## Generic Provided functionalities in R 1.0: User login (Apple/Google/Email) diff --git a/src/app/app.constant.example.ts b/src/app/app.constant.example.ts new file mode 100644 index 0000000..6b896ac --- /dev/null +++ b/src/app/app.constant.example.ts @@ -0,0 +1,36 @@ +export const ENV = { + production: false, + parseAppId: 'PARSE APP HERE', + parseServerUrl: 'PARSE URL HERE', + parseJSKey: 'parseJSKey here', + fileKey: 'parsefileKey here', + plantnetKey: 'plantnetKey here' + } + + +// 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 = { + firebase: { + projectId: 'mobisapp-prod', + appId: 'firebase app id', + storageBucket: 'xx-prod.appspot.com', + //locationId: 'europe-west', + apiKey: 'xxx-no', + authDomain: 'xxxm', + messagingSenderId: 'xxx', + }, + + production: true +}; + +/* + * 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/src/app/mobisplugins/plantnet/classify/classify.page.ts b/src/app/mobisplugins/plantnet/classify/classify.page.ts index ea17a33..3a961a3 100644 --- a/src/app/mobisplugins/plantnet/classify/classify.page.ts +++ b/src/app/mobisplugins/plantnet/classify/classify.page.ts @@ -1,5 +1,13 @@ import { Component, OnInit } from '@angular/core'; import {ENV} from '../../../app.constant'; +import { TranslateService } from '@ngx-translate/core'; +import { AuthService } from '../../../services/auth.service'; +import { Auth, user } from '@angular/fire/auth'; +import { Storage } from '@ionic/storage-angular'; +import { Router } from '@angular/router'; +import { Geolocation } from '@capacitor/geolocation'; + +import { Http } from '@capacitor-community/http'; @Component({ selector: 'app-classify', @@ -11,46 +19,159 @@ export class ClassifyPage implements OnInit { API_URL = 'https://my-api.plantnet.org/v2/identify/' + this.PROJECT + '?api-key='; API_PRIVATE_KEY = ENV.plantnetKey; // secret API_SIMSEARCH_OPTION = '&include-related-images=true'; // optional: get most similar images - API_LANG = '&lang=fr'; // default: en + API_LANG = '&lang=en'; // default: en - IMAGE_1 = '../data/image_1.jpeg'; - ORGAN_1 = 'flower'; - IMAGE_2 = '../data/image_2.jpeg'; - ORGAN_2 = 'leaf'; - - constructor() { } + uploadSuccess = false; // Add this line + image = ''; + user = null; + language = ''; + latitude: number; + longitude: number; + altitude: number; + constructor( + +private storage: Storage, +private authService: AuthService, +private afAuth: Auth, +private translateService: TranslateService, +private router: Router + + ) { user(this.afAuth).subscribe((response) => { + //fill the user to verify if someone is logged in + this.user = response; + console.log(this.user.uid); + }); } ngOnInit() { + + // get location + this.getLocation(); + + + // get image from local storage + this.storage.get('image').then((image) => { + console.log(image); + this.image = image; + + }); + + + +// add rose.jpg from assets directory for testing + const imageUri = 'assets/rose.jpg'; + + + const imageType = 'image/jpeg'; + const imageName = 'rose.jpg'; + + fetch(imageUri) + .then(response => response.blob()) + .then(blob => { + const formData = new FormData(); + formData.append('images', new File([blob], imageName, { type: imageType })); + formData.append('organs', 'auto'); + + const url = 'https://my-api.plantnet.org/v2/identify/all'; + const headers = { + 'accept': 'application/json', + 'Content-Type': 'multipart/form-data' + }; + const params = { + 'include-related-images': 'false', + 'no-reject': 'false', + 'lang': 'en', + 'api-key': '2b10bmIKkNNcBL6D4jwq3il4rO' + }; + + Http.request({ + method: 'POST', + url: url, + headers: headers, + params: params, + data: formData + }).then(response => { + console.log(response.data); + }).catch(error => { + console.error(error); + }); + }) + .catch(error => { + console.error(error); + }); + + + -// now make a POST request to the API -const xhr = new XMLHttpRequest(); -xhr.open('POST', this.API_URL + this.API_PRIVATE_KEY + this.API_SIMSEARCH_OPTION + this.API_LANG, true); -xhr.setRequestHeader('Content-Type', 'application/json'); -xhr.onload = function () { - // do something to response - console.log(this.responseText); }; -xhr.send(JSON.stringify({ - images: [ - { - url: this.IMAGE_1, - organ: this.ORGAN_1 + + + + + + + + + + + + + + + + + + + + + savetoParse() { + + const plantnet_data_store = Parse.Object.extend('plantnet_data'); + + // create new instance of parse class + + const plantnet_data = new plantnet_data_store(); + + // set value for parse clas + + const file = new Parse.File('plantnet_image.jpg', { base64: this.image }); + file.save().then( + (file) => { + console.log(file); }, - { - url: this.IMAGE_2, - organ: this.ORGAN_2 - - } - ] -})); - - - - - + (error) => { + console.log(error); + } + ); + // add location and clasiification + + plantnet_data.set('user_uid', this.user.uid); + plantnet_data.set('name', this.user.displayName); + plantnet_data.set('email', this.user.email); + plantnet_data.set('image', file); + plantnet_data.set('latitude', this.latitude); + plantnet_data.set('longitude', this.longitude); + plantnet_data.set('altitude', this.altitude); + plantnet_data.save().then( + (result: any) => { + console.log(result); + }, + (error: any) => { + console.log(error); + } + ); + } + async getLocation() { + const position = await Geolocation.getCurrentPosition({ + enableHighAccuracy: true, + }); + this.latitude = position.coords.latitude; + console.log(position.coords.latitude); + this.longitude = position.coords.longitude; + this.altitude = position.coords.altitude; + return position.coords; } } diff --git a/src/app/mobisplugins/plantnet/plantnet.page.html b/src/app/mobisplugins/plantnet/plantnet.page.html index b3a64b7..d89254b 100644 --- a/src/app/mobisplugins/plantnet/plantnet.page.html +++ b/src/app/mobisplugins/plantnet/plantnet.page.html @@ -11,7 +11,7 @@ Take a picture -Welcome to the Plantnet API +Welcome to the Plantnet API
@@ -29,4 +29,4 @@ Welcome to the Plantnet API Take a picture - \ No newline at end of file + diff --git a/src/app/mobisplugins/plantnet/plantnet.page.ts b/src/app/mobisplugins/plantnet/plantnet.page.ts index d9a3762..8f045b7 100644 --- a/src/app/mobisplugins/plantnet/plantnet.page.ts +++ b/src/app/mobisplugins/plantnet/plantnet.page.ts @@ -1,18 +1,13 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import * as Parse from 'parse'; -import { ENV } from '../../app.constant'; + import { Component, OnInit, ViewChild, ElementRef } from '@angular/core'; import { ModalController } from '@ionic/angular'; import { PreviewPage } from './preview/preview.page'; import { TranslateService } from '@ngx-translate/core'; -import { AuthService } from '../../services/auth.service'; -import { Auth, user } from '@angular/fire/auth'; + import { Storage } from '@ionic/storage-angular'; import { Router } from '@angular/router'; -import { Geolocation } from '@capacitor/geolocation'; -Parse.initialize(ENV.parseAppId, ENV.parseJSKey); -(Parse as any).serverURL = ENV.parseServerUrl; // use your server url let uploadSuccess = false; @@ -33,37 +28,23 @@ export class PlantnetPage implements OnInit { constructor( private modal: ModalController, private translateService: TranslateService, - private authService: AuthService, - private afAuth: Auth, + private storage: Storage, private router: Router ) { - user(this.afAuth).subscribe((response) => { - //fill the user to verify if someone is logged in - this.user = response; - console.log(this.user.uid); - }); + } ngOnInit() { - this.getLocation(); + } - async getLocation() { - const position = await Geolocation.getCurrentPosition({ - enableHighAccuracy: true, - }); - this.latitude = position.coords.latitude; - console.log(position.coords.latitude); - this.longitude = position.coords.longitude; - this.altitude = position.coords.altitude; - return position.coords; - } + async openCamera() { const modal = await this.modal.create({ component: PreviewPage, @@ -71,49 +52,17 @@ export class PlantnetPage implements OnInit { animated: true, }); - modal.onDidDismiss().then((data) => { + modal.onDidDismiss().then(async (data) => { if (data !== null) { this.image = data.data; this.uploadSuccess = true; // create parse class - const plantnet_data_store = Parse.Object.extend('plantnet_data'); - // create new instance of parse class - - const plantnet_data = new plantnet_data_store(); - - // set value for parse clas - - const file = new Parse.File('image.jpg', { base64: this.image }); - file.save().then( - (file) => { - console.log(file); - }, - (error) => { - console.log(error); - } - ); - // add location and clasiification - - plantnet_data.set('user_uid', this.user.uid); - plantnet_data.set('name', this.user.displayName); - plantnet_data.set('email', this.user.email); - plantnet_data.set('image', file); - plantnet_data.set('latitude', this.latitude); - plantnet_data.set('longitude', this.longitude); - plantnet_data.set('altitude', this.altitude); - - plantnet_data.save().then( - (result: any) => { - console.log(result); - }, - (error: any) => { - console.log(error); - } - ); - } else { + // store image in local storage + await this.storage.set('plantnet_image', this.image); + } else { console.log('no data'); } }); diff --git a/src/app/mobisplugins/plantnet/preview/preview.page.ts b/src/app/mobisplugins/plantnet/preview/preview.page.ts index 8eda050..919bedc 100644 --- a/src/app/mobisplugins/plantnet/preview/preview.page.ts +++ b/src/app/mobisplugins/plantnet/preview/preview.page.ts @@ -21,7 +21,7 @@ export class PreviewPage implements OnInit { launchCamera() { const cameraPreviewOptions: CameraPreviewOptions = { - position: 'front', // front or rear + position: 'rear', // front or rear parent: 'content', // the id on the ion-content className: '', width: window.screen.width, //width of the camera display