Initial commit
70
.gitignore
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
# 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*
|
||||
|
||||
/.angular
|
||||
/.idea
|
||||
/.ionic
|
||||
/.sass-cache
|
||||
/.sourcemaps
|
||||
/.versions
|
||||
/.vscode
|
||||
/coverage
|
||||
/dist
|
||||
/node_modules
|
||||
/platforms
|
||||
/plugins
|
||||
/www
|
||||
|
||||
# Firebase
|
||||
.firebase
|
||||
*-debug.log
|
||||
.runtimeconfig.json
|
||||
src/app/app.constant.ts
|
||||
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.vscode
|
||||
.idea
|
||||
|
||||
/src/app/firebase.json
|
||||
/src/environments/environment.prod.ts
|
||||
/src/environments/environment.ts
|
||||
/src/app/app.constant.ts
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
14
MainActivity.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package io.ionic.starter;
|
||||
|
||||
import com.getcapacitor.BridgeActivity;
|
||||
|
||||
import com.codetrixstudio.capacitor.GoogleAuth.GoogleAuth;
|
||||
import android.os.Bundle; // required for onCreate parameter
|
||||
|
||||
public class MainActivity extends BridgeActivity {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
registerPlugin(GoogleAuth.class);
|
||||
}
|
||||
}
|
||||
86
README.md
Normal file
@@ -0,0 +1,86 @@
|
||||
# MOBIS_COS4CLOUD
|
||||

|
||||
|
||||
|
||||
# MOBIS FRONT END SUPPORT PACKAGE
|
||||
|
||||
|
||||
# What is MOBIS?
|
||||
|
||||
|
||||
## Introduction
|
||||
Mobis is a citizen science platform that enables app developers and researchers to incorporate air and water quality monitoring, as well as biodiversity research, into their own apps. The software includes example integrations with Canair.io, mini-secchi, iSPEX and Plant*Net, which are tools for measuring air and water quality and studying biodiversity, respectively.
|
||||
Mobis also includes features for user login and storage on the European Open Science Cloud. This makes it easy for researchers and app developers to collect and share data for their projects.
|
||||
|
||||
|
||||
# About this repository
|
||||
|
||||
Here you will find software and documentation for our low cost sensors (iSPEX, kDUINO, Fresh Water Watch)
|
||||
The software is developed using the IONIC framework, Parse Server (Back End).
|
||||
For iSPEX(r) we offer a basic interface. The iSPEX (r) professional software is using native closed source software and developed outside the EU research project.
|
||||
|
||||
|
||||
Mobis is an open source citizen science software framework that allows app developers and researchers to easily integrate air and water quality monitoring, as well as biodiversity research, into their own apps.
|
||||
The sample software includes integrations with Canair.io (for air quality), mini-secchi (for water quality), and Plant*Net (for biodiversity research), as well as user login and storage on the European Open Science Cloud.
|
||||
|
||||
This readme acts as a reference for the mobis software and / or documentation. Both software and documentation are still into development, so the contents of this file/wiki can and will change over time.
|
||||
|
||||
|
||||
## Audience
|
||||
Scientists, (app) developers, project partners, people who are lookikng for low cost sensor integration solutions.
|
||||
|
||||
|
||||
## Generic
|
||||
Provided functionalities in R 1.0:
|
||||
User login (Apple/Google/Email)
|
||||
Language switcher
|
||||
Data sync/upload
|
||||
|
||||
WIP:
|
||||
Full offline support (Parse Server)
|
||||
Push notifications
|
||||
|
||||
# Plugin description
|
||||
### General description
|
||||
|
||||
## CANAIR.IO
|
||||
### Description
|
||||
|
||||
## MINI SECCHI
|
||||
### Description of the mobis Mini Secchi Plugin
|
||||
Mini Secchi is a water quality tool that measures the Secchi depth of a lake or river. This is a measure of the water transparency and is used to assess water quality. The Mini Secchi is a low-cost, open-source sensor that can be used to collect water quality data in lakes, rivers and streams.
|
||||
|
||||
## iSPEX
|
||||
### Description of the mobis iSPEX spectropolarimeter Plugin
|
||||
|
||||
iSPEX is a spectropolarimeter that measures the optical properties of water or air. It is a low-cost, open-source sensor that can be used to collect water quality data in lakes, rivers and streams.
|
||||
|
||||
|
||||
## Description of the mobis PLANT*NET API plugin
|
||||
### Description
|
||||
Plant*Net is a platformfor plant identification
|
||||
that allows users to identify plants using a smartphone camera.
|
||||
|
||||
# BACK END SCRIPTS
|
||||
|
||||
Mobile back end. Used for storage, metadata, push notifications, offline sync.
|
||||
Parse Server
|
||||
|
||||
### Parse Server setup
|
||||
You can run your own (Dockerized) Parse Server or use the Cos4Cloud instance.
|
||||
If you want to run your own instance, please check the [Parse Server documentation](https://docs.parseplatform.org/parse-server/guide/).
|
||||
If you want to use the Cos4Cloud instance, please contact us via the [Cos4Cloud Slack channel](https://join.slack.com/t/cos4cloud/shared_invite/zt-8q3vzq1p-7b3hGdYk8jvRyRJd1Nn9gg).
|
||||
|
||||
|
||||
### Sensor Things API 1.1 support
|
||||
The Cos4Cloud instance of Parse Server supports the Sensor Things API 1.1.
|
||||
Please check the [Sensor Things API 1.1 documentation](https://developers.sensorup.com/docs/#section/Introduction) for more information.
|
||||
|
||||
# FUNDING
|
||||
|
||||

|
||||
|
||||
This project has received funding from the European Union’s Horizon 2020 research and innovation programme under grant agreement No 863463
|
||||
|
||||
|
||||
|
||||
178
angular.json
Normal file
@@ -0,0 +1,178 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"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",
|
||||
"src/styles.css",
|
||||
"./node_modules/leaflet/dist/leaflet.css",
|
||||
"node_modules/leaflet.markercluster/dist/MarkerCluster.css",
|
||||
"node_modules/leaflet.markercluster/dist/MarkerCluster.Default.css"
|
||||
],
|
||||
"scripts": [],
|
||||
"vendorChunk": true,
|
||||
"extractLicenses": false,
|
||||
"buildOptimizer": false,
|
||||
"sourceMap": true,
|
||||
"optimization": false,
|
||||
"namedChunks": true
|
||||
},
|
||||
"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"
|
||||
}
|
||||
}
|
||||
},
|
||||
"deploy": {
|
||||
"builder": "@angular/fire:deploy",
|
||||
"options": {
|
||||
"prerender": false,
|
||||
"ssr": false,
|
||||
"browserTarget": "app:build:production",
|
||||
"firebaseProject": "mobis-auth",
|
||||
"firebaseHostingSite": "mobis-auth"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cli": {
|
||||
"schematicCollections": [
|
||||
"@ionic/angular-toolkit"
|
||||
],
|
||||
"analytics": false
|
||||
},
|
||||
"schematics": {
|
||||
"@ionic/angular-toolkit:component": {
|
||||
"styleext": "scss"
|
||||
},
|
||||
"@ionic/angular-toolkit:page": {
|
||||
"styleext": "scss"
|
||||
}
|
||||
}
|
||||
}
|
||||
15
capacitor.config.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"appId": "nl.ddq.mobisapp",
|
||||
"appName": "mobisapp",
|
||||
"bundledWebRuntime": false,
|
||||
"npmClient": "npm",
|
||||
"webDir": "dist/demo",
|
||||
"cordova": {},
|
||||
"plugins": {
|
||||
"GoogleAuth": {
|
||||
"scopes": ["profile", "email"],
|
||||
"clientId": "778522712103-tqkc468qermr7hvbqsmm2p2ueglcmjsi.apps.googleusercontent.com",
|
||||
"forceCodeForRefreshToken" : true
|
||||
}
|
||||
}
|
||||
}
|
||||
18
capacitor.config.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { CapacitorConfig } from '@capacitor/cli';
|
||||
|
||||
const config: CapacitorConfig = {
|
||||
appId: 'nl.ddq.mobisapp',
|
||||
appName: 'mobisapp',
|
||||
webDir: 'www',
|
||||
bundledWebRuntime: false,
|
||||
plugins: {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
GoogleAuth: {
|
||||
scopes: ['profile', 'email'],
|
||||
androidClientId: '778522712103-tqkc468qermr7hvbqsmm2p2ueglcmjsi.apps.googleusercontent.com',
|
||||
forceCodeForRefreshToken: true,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default config;
|
||||
101
config.xml
Normal file
@@ -0,0 +1,101 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<widget id="nl.ddq.mobisapp" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
|
||||
<name>mobisapp</name>
|
||||
<description>The Mobis demonstration app.</description>
|
||||
<author email="web@ddq.nl" href="http://ionicframework.com/">DDQ/Pocket science</author>
|
||||
<content src="index.html" />
|
||||
<access origin="*" />
|
||||
<allow-intent href="http://*/*" />
|
||||
<allow-intent href="https://*/*" />
|
||||
<allow-intent href="tel:*" />
|
||||
<allow-intent href="sms:*" />
|
||||
<allow-intent href="mailto:*" />
|
||||
<allow-intent href="geo:*" />
|
||||
<preference name="ScrollEnabled" value="false" />
|
||||
<preference name="BackupWebStorage" value="none" />
|
||||
<preference name="SplashMaintainAspectRatio" value="true" />
|
||||
<preference name="FadeSplashScreenDuration" value="300" />
|
||||
<preference name="SplashShowOnlyFirstTime" value="false" />
|
||||
<preference name="SplashScreen" value="screen" />
|
||||
<preference name="SplashScreenDelay" value="3000" />
|
||||
<platform name="android">
|
||||
<preference name="Scheme" value="http" />
|
||||
<edit-config file="app/src/main/AndroidManifest.xml" mode="merge" target="/manifest/application" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<application android:networkSecurityConfig="@xml/network_security_config" />
|
||||
</edit-config>
|
||||
<resource-file src="resources/android/xml/network_security_config.xml" target="app/src/main/res/xml/network_security_config.xml" />
|
||||
<allow-intent href="market:*" />
|
||||
<icon density="ldpi" src="resources/android/icon/drawable-ldpi-icon.png" />
|
||||
<icon density="mdpi" src="resources/android/icon/drawable-mdpi-icon.png" />
|
||||
<icon density="hdpi" src="resources/android/icon/drawable-hdpi-icon.png" />
|
||||
<icon density="xhdpi" src="resources/android/icon/drawable-xhdpi-icon.png" />
|
||||
<icon density="xxhdpi" src="resources/android/icon/drawable-xxhdpi-icon.png" />
|
||||
<icon density="xxxhdpi" src="resources/android/icon/drawable-xxxhdpi-icon.png" />
|
||||
<splash density="land-ldpi" src="resources/android/splash/drawable-land-ldpi-screen.png" />
|
||||
<splash density="land-mdpi" src="resources/android/splash/drawable-land-mdpi-screen.png" />
|
||||
<splash density="land-hdpi" src="resources/android/splash/drawable-land-hdpi-screen.png" />
|
||||
<splash density="land-xhdpi" src="resources/android/splash/drawable-land-xhdpi-screen.png" />
|
||||
<splash density="land-xxhdpi" src="resources/android/splash/drawable-land-xxhdpi-screen.png" />
|
||||
<splash density="land-xxxhdpi" src="resources/android/splash/drawable-land-xxxhdpi-screen.png" />
|
||||
<splash density="port-ldpi" src="resources/android/splash/drawable-port-ldpi-screen.png" />
|
||||
<splash density="port-mdpi" src="resources/android/splash/drawable-port-mdpi-screen.png" />
|
||||
<splash density="port-hdpi" src="resources/android/splash/drawable-port-hdpi-screen.png" />
|
||||
<splash density="port-xhdpi" src="resources/android/splash/drawable-port-xhdpi-screen.png" />
|
||||
<splash density="port-xxhdpi" src="resources/android/splash/drawable-port-xxhdpi-screen.png" />
|
||||
<splash density="port-xxxhdpi" src="resources/android/splash/drawable-port-xxxhdpi-screen.png" />
|
||||
</platform>
|
||||
<platform name="ios">
|
||||
<allow-intent href="itms:*" />
|
||||
<allow-intent href="itms-apps:*" />
|
||||
<icon height="57" src="resources/ios/icon/icon.png" width="57" />
|
||||
<icon height="114" src="resources/ios/icon/icon@2x.png" width="114" />
|
||||
<icon height="29" src="resources/ios/icon/icon-small.png" width="29" />
|
||||
<icon height="58" src="resources/ios/icon/icon-small@2x.png" width="58" />
|
||||
<icon height="87" src="resources/ios/icon/icon-small@3x.png" width="87" />
|
||||
<icon height="20" src="resources/ios/icon/icon-20.png" width="20" />
|
||||
<icon height="40" src="resources/ios/icon/icon-20@2x.png" width="40" />
|
||||
<icon height="60" src="resources/ios/icon/icon-20@3x.png" width="60" />
|
||||
<icon height="48" src="resources/ios/icon/icon-24@2x.png" width="48" />
|
||||
<icon height="55" src="resources/ios/icon/icon-27.5@2x.png" width="55" />
|
||||
<icon height="29" src="resources/ios/icon/icon-29.png" width="29" />
|
||||
<icon height="58" src="resources/ios/icon/icon-29@2x.png" width="58" />
|
||||
<icon height="87" src="resources/ios/icon/icon-29@3x.png" width="87" />
|
||||
<icon height="40" src="resources/ios/icon/icon-40.png" width="40" />
|
||||
<icon height="80" src="resources/ios/icon/icon-40@2x.png" width="80" />
|
||||
<icon height="120" src="resources/ios/icon/icon-40@3x.png" width="120" />
|
||||
<icon height="88" src="resources/ios/icon/icon-44@2x.png" width="88" />
|
||||
<icon height="50" src="resources/ios/icon/icon-50.png" width="50" />
|
||||
<icon height="100" src="resources/ios/icon/icon-50@2x.png" width="100" />
|
||||
<icon height="60" src="resources/ios/icon/icon-60.png" width="60" />
|
||||
<icon height="120" src="resources/ios/icon/icon-60@2x.png" width="120" />
|
||||
<icon height="180" src="resources/ios/icon/icon-60@3x.png" width="180" />
|
||||
<icon height="72" src="resources/ios/icon/icon-72.png" width="72" />
|
||||
<icon height="144" src="resources/ios/icon/icon-72@2x.png" width="144" />
|
||||
<icon height="76" src="resources/ios/icon/icon-76.png" width="76" />
|
||||
<icon height="152" src="resources/ios/icon/icon-76@2x.png" width="152" />
|
||||
<icon height="167" src="resources/ios/icon/icon-83.5@2x.png" width="167" />
|
||||
<icon height="172" src="resources/ios/icon/icon-86@2x.png" width="172" />
|
||||
<icon height="196" src="resources/ios/icon/icon-98@2x.png" width="196" />
|
||||
<icon height="1024" src="resources/ios/icon/icon-1024.png" width="1024" />
|
||||
<splash height="480" src="resources/ios/splash/Default~iphone.png" width="320" />
|
||||
<splash height="960" src="resources/ios/splash/Default@2x~iphone.png" width="640" />
|
||||
<splash height="1024" src="resources/ios/splash/Default-Portrait~ipad.png" width="768" />
|
||||
<splash height="768" src="resources/ios/splash/Default-Landscape~ipad.png" width="1024" />
|
||||
<splash height="1125" src="resources/ios/splash/Default-Landscape-2436h.png" width="2436" />
|
||||
<splash height="1242" src="resources/ios/splash/Default-Landscape-736h.png" width="2208" />
|
||||
<splash height="2048" src="resources/ios/splash/Default-Portrait@2x~ipad.png" width="1536" />
|
||||
<splash height="1536" src="resources/ios/splash/Default-Landscape@2x~ipad.png" width="2048" />
|
||||
<splash height="2732" src="resources/ios/splash/Default-Portrait@~ipadpro.png" width="2048" />
|
||||
<splash height="2048" src="resources/ios/splash/Default-Landscape@~ipadpro.png" width="2732" />
|
||||
<splash height="1136" src="resources/ios/splash/Default-568h@2x~iphone.png" width="640" />
|
||||
<splash height="1334" src="resources/ios/splash/Default-667h.png" width="750" />
|
||||
<splash height="2208" src="resources/ios/splash/Default-736h.png" width="1242" />
|
||||
<splash height="2436" src="resources/ios/splash/Default-2436h.png" width="1125" />
|
||||
<splash height="2732" src="resources/ios/splash/Default@2x~universal~anyany.png" width="2732" />
|
||||
</platform>
|
||||
<plugin name="cordova-plugin-statusbar" spec="2.4.2" />
|
||||
<plugin name="cordova-plugin-device" spec="2.0.2" />
|
||||
<plugin name="cordova-plugin-splashscreen" spec="5.0.2" />
|
||||
<plugin name="cordova-plugin-ionic-webview" spec="^5.0.0" />
|
||||
<plugin name="cordova-plugin-ionic-keyboard" spec="^2.0.5" />
|
||||
</widget>
|
||||
37
e2e/protractor.conf.js
Normal file
@@ -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
|
||||
}
|
||||
}));
|
||||
}
|
||||
};
|
||||
14
e2e/src/app.e2e-spec.ts
Normal file
@@ -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');
|
||||
});
|
||||
});
|
||||
11
e2e/src/app.po.ts
Normal file
@@ -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();
|
||||
}
|
||||
}
|
||||
12
e2e/tsconfig.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/e2e",
|
||||
"module": "commonjs",
|
||||
"target": "es2018",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"node"
|
||||
]
|
||||
}
|
||||
}
|
||||
8
ionic.config.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "mobisapp",
|
||||
"integrations": {
|
||||
"capacitor": {},
|
||||
"cordova": {}
|
||||
},
|
||||
"type": "angular"
|
||||
}
|
||||
44
karma.conf.js
Normal file
@@ -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
|
||||
});
|
||||
};
|
||||
100
package.json
Normal file
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"name": "firebase-login",
|
||||
"version": "0.0.1",
|
||||
"author": "Ionic Framework",
|
||||
"homepage": "https://ionicframework.com/",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/common": "^14.0.0",
|
||||
"@angular/core": "^14.0.0",
|
||||
"@angular/fire": "^7.4.1",
|
||||
"@angular/forms": "^14.0.0",
|
||||
"@angular/platform-browser": "^14.0.0",
|
||||
"@angular/platform-browser-dynamic": "^14.0.0",
|
||||
"@angular/router": "^14.0.0",
|
||||
"@awesome-cordova-plugins/background-mode": "^6.2.0",
|
||||
"@awesome-cordova-plugins/core": "6.2.0",
|
||||
"@capacitor-community/apple-sign-in": "^4.0.0",
|
||||
"@capacitor-community/bluetooth-le": "^2.0.1",
|
||||
"@capacitor-community/camera-preview": "^4.0.0",
|
||||
"@capacitor/android": "4.0.1",
|
||||
"@capacitor/app": "4.0.1",
|
||||
"@capacitor/camera": "^4.0.1",
|
||||
"@capacitor/core": "4.0.1",
|
||||
"@capacitor/device": "4.1.0",
|
||||
"@capacitor/geolocation": "^4.0.1",
|
||||
"@capacitor/haptics": "4.0.1",
|
||||
"@capacitor/ios": "4.0.1",
|
||||
"@capacitor/keyboard": "4.0.1",
|
||||
"@capacitor/status-bar": "4.0.1",
|
||||
"@codetrix-studio/capacitor-google-auth": "^3.2.0",
|
||||
"@ionic-native/vibration": "^5.36.0",
|
||||
"@ionic/angular": "^6.1.9",
|
||||
"@ionic/pwa-elements": "^3.1.1",
|
||||
"@ionic/storage-angular": "^3.0.6",
|
||||
"@ngx-translate/core": "^14.0.0",
|
||||
"@ngx-translate/http-loader": "^7.0.0",
|
||||
"@types/leaflet.markercluster": "^1.5.1",
|
||||
"@types/parse": "^2.18.18",
|
||||
"cordova-plugin-background-mode": "^0.7.3",
|
||||
"cordova-plugin-device": "2.1.0",
|
||||
"guid-typescript": "^1.0.9",
|
||||
"leaflet": "^1.9.2",
|
||||
"leaflet.markercluster": "^1.5.3",
|
||||
"ng-apexcharts": "^1.7.1",
|
||||
"parse": "^3.5.1",
|
||||
"rxjs": "^7.5.7",
|
||||
"stream": "^0.0.2",
|
||||
"timers": "^0.1.1",
|
||||
"tslib": "^2.2.0",
|
||||
"xml2js": "^0.4.23",
|
||||
"zone.js": "~0.11.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^14.0.0",
|
||||
"@angular-eslint/builder": "~13.0.1",
|
||||
"@angular-eslint/eslint-plugin": "~13.0.1",
|
||||
"@angular-eslint/eslint-plugin-template": "~13.0.1",
|
||||
"@angular-eslint/template-parser": "~13.0.1",
|
||||
"@angular/cli": "^14.0.0",
|
||||
"@angular/compiler": "^14.0.0",
|
||||
"@angular/compiler-cli": "^14.0.0",
|
||||
"@angular/language-service": "^14.0.0",
|
||||
"@capacitor/cli": "4.0.1",
|
||||
"@ionic/angular-toolkit": "^6.0.0",
|
||||
"@ionic/cli": "6.20.4",
|
||||
"@ionic/lab": "3.2.15",
|
||||
"@types/jasmine": "~3.6.0",
|
||||
"@types/jasminewd2": "~2.0.3",
|
||||
"@types/leaflet": "^1.9.0",
|
||||
"@types/node": "^12.11.1",
|
||||
"@types/xml2js": "^0.4.11",
|
||||
"@typescript-eslint/eslint-plugin": "5.3.0",
|
||||
"@typescript-eslint/parser": "5.3.0",
|
||||
"cordova-res": "0.15.4",
|
||||
"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.8.0",
|
||||
"jasmine-spec-reporter": "~5.0.0",
|
||||
"karma": "~6.3.2",
|
||||
"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.7.3"
|
||||
},
|
||||
"description": "An Ionic project"
|
||||
}
|
||||
93
project-summary.md
Normal file
@@ -0,0 +1,93 @@
|
||||
## Capacitor Plugins
|
||||
|
||||
### @capacitor-community
|
||||
- **apple-sign-in@4.0.0**
|
||||
### @capacitor
|
||||
- **app@4.0.1** - (Latest 4.1.1)
|
||||
- **camera@4.1.3** - (Latest 4.1.4)
|
||||
- **geolocation@4.0.1** - (Latest 4.1.0)
|
||||
- **haptics@4.0.1** - (Latest 4.1.0)
|
||||
- **keyboard@4.0.1** - (Latest 4.1.0)
|
||||
- **status-bar@4.0.1** - (Latest 4.1.1)
|
||||
### @codetrix-studio
|
||||
- **capacitor-google-auth@3.2.0**
|
||||
## Cordova Plugins
|
||||
|
||||
## Dependencies
|
||||
|
||||
### @angular-devkit
|
||||
- **build-angular@14.2.6** - (Latest 15.0.2)
|
||||
### @angular-eslint
|
||||
- **builder@13.0.1** - (Latest 15.1.0)
|
||||
- **eslint-plugin@13.0.1** - (Latest 15.1.0)
|
||||
- **eslint-plugin-template@13.0.1** - (Latest 15.1.0)
|
||||
- **template-parser@13.0.1** - (Latest 15.1.0)
|
||||
### @angular
|
||||
- **cli@14.2.6** - (Latest 15.0.2)
|
||||
- **common@14.2.7** - (Latest 15.0.2)
|
||||
- **compiler@14.2.7** - (Latest 15.0.2)
|
||||
- **compiler-cli@14.2.7** - (Latest 15.0.2)
|
||||
- **core@14.2.7** - (Latest 15.0.2)
|
||||
- **fire@7.4.1** - (Latest 7.5.0)
|
||||
- **forms@14.2.7** - (Latest 15.0.2)
|
||||
- **language-service@14.2.7** - (Latest 15.0.2)
|
||||
- **platform-browser@14.2.7** - (Latest 15.0.2)
|
||||
- **platform-browser-dynamic@14.2.7** - (Latest 15.0.2)
|
||||
- **router@14.2.7** - (Latest 15.0.2)
|
||||
### @capacitor
|
||||
- **android@4.0.1** - (Latest 4.6.1)
|
||||
- **cli@4.0.1** - (Latest 4.6.1)
|
||||
- **core@4.0.1** - (Latest 4.6.1)
|
||||
- **ios@4.0.1** - (Latest 4.6.1)
|
||||
### @ionic
|
||||
- **angular@6.3.2** - (Latest 6.3.9)
|
||||
- **angular-toolkit@6.1.0** - (Latest 7.0.0)
|
||||
- **cli@6.20.4**
|
||||
- **pwa-elements@3.1.1**
|
||||
- **storage-angular@3.0.6**
|
||||
### @ngx-translate
|
||||
- **core@14.0.0**
|
||||
- **http-loader@7.0.0**
|
||||
### @types
|
||||
- **jasmine@3.6.11** - (Latest 4.3.1)
|
||||
- **jasminewd2@2.0.10**
|
||||
- **leaflet@1.9.0**
|
||||
- **leaflet.markercluster@1.5.1**
|
||||
- **node@12.20.55** - (Latest 18.11.11)
|
||||
- **parse@2.18.18** - (Latest 3.0.1)
|
||||
- **xml2js@0.4.11**
|
||||
### @typescript-eslint
|
||||
- **eslint-plugin@5.3.0** - (Latest 5.45.1)
|
||||
- **parser@5.3.0** - (Latest 5.45.1)
|
||||
### Other Dependencies
|
||||
- **cordova-res@0.15.4**
|
||||
- **eslint@7.32.0** - (Latest 8.29.0)
|
||||
- **eslint-plugin-import@2.22.1** - (Latest 2.26.0)
|
||||
- **eslint-plugin-jsdoc@30.7.6** - (Latest 39.6.4)
|
||||
- **eslint-plugin-prefer-arrow@1.2.2** - (Latest 1.2.3)
|
||||
- **jasmine-core@3.8.0** - (Latest 4.5.0)
|
||||
- **jasmine-spec-reporter@5.0.2** - (Latest 7.0.0)
|
||||
- **karma@6.3.20** - (Latest 6.4.1)
|
||||
- **karma-chrome-launcher@3.1.1**
|
||||
- **karma-coverage@2.0.3** - (Latest 2.2.0)
|
||||
- **karma-coverage-istanbul-reporter@3.0.3**
|
||||
- **karma-jasmine@4.0.2** - (Latest 5.1.0)
|
||||
- **karma-jasmine-html-reporter@1.7.0** - (Latest 2.0.0)
|
||||
- **leaflet@1.9.2** - (Latest 1.9.3)
|
||||
- **leaflet.markercluster@1.5.3**
|
||||
- **ng-apexcharts@1.7.4**
|
||||
- **parse@3.4.4** - (Latest 3.5.1)
|
||||
- **protractor@7.0.0**
|
||||
- **rxjs@7.5.7** - (Latest 7.6.0)
|
||||
- **stream@0.0.2**
|
||||
- **timers@0.1.1**
|
||||
- **ts-node@8.3.0** - (Latest 10.9.1)
|
||||
- **tslib@2.4.0** - (Latest 2.4.1)
|
||||
- **typescript@4.7.4** - (Latest 4.9.3)
|
||||
- **xml2js@0.4.23**
|
||||
- **zone.js@0.11.8** - (Latest 0.12.0)
|
||||
|
||||
|
||||
## Nonstandard naming
|
||||
The following files and folders do not follow the standard naming convention:
|
||||
|
||||
8
resources/README.md
Normal file
@@ -0,0 +1,8 @@
|
||||
These are Cordova resources. You can replace icon.png and splash.png and run
|
||||
`ionic cordova resources` to generate custom icons and splash screens for your
|
||||
app. See `ionic cordova resources --help` for details.
|
||||
|
||||
Cordova reference documentation:
|
||||
|
||||
- Icons: https://cordova.apache.org/docs/en/latest/config_ref/images.html
|
||||
- Splash Screens: https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-splashscreen/
|
||||
BIN
resources/android/icon-background.png
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
BIN
resources/android/icon-foreground.png
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
BIN
resources/android/icon/drawable-hdpi-icon.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
resources/android/icon/drawable-ldpi-icon.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
resources/android/icon/drawable-mdpi-icon.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
resources/android/icon/drawable-xhdpi-icon.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
resources/android/icon/drawable-xxhdpi-icon.png
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
BIN
resources/android/icon/drawable-xxxhdpi-icon.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
resources/android/splash/drawable-land-hdpi-screen.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
resources/android/splash/drawable-land-ldpi-screen.png
Normal file
|
After Width: | Height: | Size: 8.2 KiB |
BIN
resources/android/splash/drawable-land-mdpi-screen.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
resources/android/splash/drawable-land-xhdpi-screen.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
resources/android/splash/drawable-land-xxhdpi-screen.png
Normal file
|
After Width: | Height: | Size: 78 KiB |
BIN
resources/android/splash/drawable-land-xxxhdpi-screen.png
Normal file
|
After Width: | Height: | Size: 110 KiB |
BIN
resources/android/splash/drawable-port-hdpi-screen.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
resources/android/splash/drawable-port-ldpi-screen.png
Normal file
|
After Width: | Height: | Size: 7.9 KiB |
BIN
resources/android/splash/drawable-port-mdpi-screen.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
resources/android/splash/drawable-port-xhdpi-screen.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
resources/android/splash/drawable-port-xxhdpi-screen.png
Normal file
|
After Width: | Height: | Size: 69 KiB |
BIN
resources/android/splash/drawable-port-xxxhdpi-screen.png
Normal file
|
After Width: | Height: | Size: 97 KiB |
6
resources/android/xml/network_security_config.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<network-security-config>
|
||||
<domain-config cleartextTrafficPermitted="true">
|
||||
<domain includeSubdomains="true">localhost</domain>
|
||||
</domain-config>
|
||||
</network-security-config>
|
||||
BIN
resources/icon.png
Normal file
|
After Width: | Height: | Size: 85 KiB |
BIN
resources/ios/icon/icon-1024.png
Normal file
|
After Width: | Height: | Size: 53 KiB |
BIN
resources/ios/icon/icon-108@2x.png
Normal file
|
After Width: | Height: | Size: 9.0 KiB |
BIN
resources/ios/icon/icon-20.png
Normal file
|
After Width: | Height: | Size: 616 B |
BIN
resources/ios/icon/icon-20@2x.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
resources/ios/icon/icon-20@3x.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
resources/ios/icon/icon-24@2x.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
resources/ios/icon/icon-27.5@2x.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
resources/ios/icon/icon-29.png
Normal file
|
After Width: | Height: | Size: 978 B |
BIN
resources/ios/icon/icon-29@2x.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
resources/ios/icon/icon-29@3x.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
resources/ios/icon/icon-40.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
resources/ios/icon/icon-40@2x.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
resources/ios/icon/icon-40@3x.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
resources/ios/icon/icon-44@2x.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
resources/ios/icon/icon-50.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
resources/ios/icon/icon-50@2x.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
resources/ios/icon/icon-60.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
resources/ios/icon/icon-60@2x.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
resources/ios/icon/icon-60@3x.png
Normal file
|
After Width: | Height: | Size: 7.1 KiB |
BIN
resources/ios/icon/icon-72.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
resources/ios/icon/icon-72@2x.png
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
BIN
resources/ios/icon/icon-76.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
resources/ios/icon/icon-76@2x.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
BIN
resources/ios/icon/icon-83.5@2x.png
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
BIN
resources/ios/icon/icon-86@2x.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
BIN
resources/ios/icon/icon-98@2x.png
Normal file
|
After Width: | Height: | Size: 8.0 KiB |
BIN
resources/ios/icon/icon-small.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
resources/ios/icon/icon-small@2x.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
resources/ios/icon/icon-small@3x.png
Normal file
|
After Width: | Height: | Size: 5.8 KiB |
BIN
resources/ios/icon/icon.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
resources/ios/icon/icon@2x.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
resources/ios/splash/Default-1792h~iphone.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
resources/ios/splash/Default-2436h.png
Normal file
|
After Width: | Height: | Size: 104 KiB |
BIN
resources/ios/splash/Default-2688h~iphone.png
Normal file
|
After Width: | Height: | Size: 110 KiB |
BIN
resources/ios/splash/Default-568h@2x~iphone.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
resources/ios/splash/Default-667h.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
resources/ios/splash/Default-736h.png
Normal file
|
After Width: | Height: | Size: 104 KiB |
BIN
resources/ios/splash/Default-Landscape-1792h~iphone.png
Normal file
|
After Width: | Height: | Size: 72 KiB |
BIN
resources/ios/splash/Default-Landscape-2436h.png
Normal file
|
After Width: | Height: | Size: 113 KiB |
BIN
resources/ios/splash/Default-Landscape-2688h~iphone.png
Normal file
|
After Width: | Height: | Size: 121 KiB |
BIN
resources/ios/splash/Default-Landscape-736h.png
Normal file
|
After Width: | Height: | Size: 116 KiB |
BIN
resources/ios/splash/Default-Landscape@2x~ipad.png
Normal file
|
After Width: | Height: | Size: 124 KiB |
BIN
resources/ios/splash/Default-Landscape@~ipadpro.png
Normal file
|
After Width: | Height: | Size: 93 KiB |
BIN
resources/ios/splash/Default-Landscape~ipad.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
resources/ios/splash/Default-Portrait@2x~ipad.png
Normal file
|
After Width: | Height: | Size: 127 KiB |
BIN
resources/ios/splash/Default-Portrait@~ipadpro.png
Normal file
|
After Width: | Height: | Size: 99 KiB |
BIN
resources/ios/splash/Default-Portrait~ipad.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
resources/ios/splash/Default@2x~iphone.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
resources/ios/splash/Default@2x~universal~anyany.png
Normal file
|
After Width: | Height: | Size: 120 KiB |
BIN
resources/ios/splash/Default~iphone.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
resources/splash.png
Normal file
|
After Width: | Height: | Size: 77 KiB |
88
src/app/app-routing.module.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { PreloadAllModules, RouterModule, Routes } from '@angular/router';
|
||||
import {redirectUnauthorizedTo, redirectLoggedInTo, canActivate } from '@angular/fire/auth-guard';
|
||||
|
||||
const redirectUnauthorizedToLogin = () => redirectUnauthorizedTo(['login']);
|
||||
const redirectLoggedInToProfile = () => redirectLoggedInTo(['profile']);
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: 'home',
|
||||
loadChildren: () => import('./home/home.module').then( m => m.HomePageModule),
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
redirectTo: 'home',
|
||||
pathMatch: 'full'
|
||||
},
|
||||
{
|
||||
path: 'login',
|
||||
loadChildren: () => import('./auth/login/login.module').then( m => m.LoginPageModule),
|
||||
...canActivate(redirectLoggedInToProfile)
|
||||
},
|
||||
{
|
||||
path: 'resetpw',
|
||||
loadChildren: () => import('./auth/resetpw/resetpw.module').then( m => m.ResetpwPageModule)
|
||||
},
|
||||
{
|
||||
path: 'profile',
|
||||
loadChildren: () => import('./auth/profile/profile.module').then( m => m.ProfilePageModule),
|
||||
...canActivate(redirectUnauthorizedToLogin)
|
||||
},
|
||||
{
|
||||
path: 'signup',
|
||||
loadChildren: () => import('./auth/signup/signup.module').then( m => m.SignupPageModule)
|
||||
},
|
||||
{
|
||||
path: 'observe',
|
||||
loadChildren: () => import('./observe/observe.module').then( m => m.MeasurePageModule)
|
||||
},
|
||||
{
|
||||
path: 'options',
|
||||
loadChildren: () => import('./options/options.module').then( m => m.OptionsPageModule)
|
||||
},
|
||||
{
|
||||
path: 'plantnet',
|
||||
loadChildren: () => import('./mobisplugins/plantnet/plantnet.module').then( m => m.PlantnetPageModule)
|
||||
},
|
||||
{
|
||||
path: 'ispex',
|
||||
loadChildren: () => import('./mobisplugins/ispex/ispex.module').then( m => m.IspexPageModule)
|
||||
},
|
||||
{
|
||||
path: 'minisecchi',
|
||||
loadChildren: () => import('./mobisplugins/minisecchi/minisecchi.module').then( m => m.MinisecchiPageModule)
|
||||
},
|
||||
{
|
||||
path: 'canairiopm25',
|
||||
loadChildren: () => import('./mobisplugins/canairiopm25/canairiopm25.module').then( m => m.Canairiopm25PageModule)
|
||||
},
|
||||
|
||||
{
|
||||
path: 'canairioco2',
|
||||
loadChildren: () => import('./mobisplugins/canairioco2/canairioco2.module').then( m => m.Canairioco2PageModule)
|
||||
},
|
||||
|
||||
{
|
||||
path: 'ms_measure',
|
||||
loadChildren: () => import('./mobisplugins/minisecchi/measure/measure.module').then( m => m.MeasurePageModule)
|
||||
},
|
||||
{
|
||||
path: 'ms_instructions',
|
||||
loadChildren: () => import('./mobisplugins/minisecchi/instructions/instructions.module').then( m => m.InstructionsPageModule)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })
|
||||
],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class AppRoutingModule { }
|
||||
60
src/app/app.component.html
Normal file
@@ -0,0 +1,60 @@
|
||||
<ion-app>
|
||||
<ion-menu side="start" contentId="main">
|
||||
<ion-menu-toggle>
|
||||
<ion-header color="primary">
|
||||
<ion-toolbar>
|
||||
|
||||
<ion-item lines="none">
|
||||
<ion-label routerLink="home">M O B I S</ion-label>
|
||||
<ion-buttons>
|
||||
<ion-button type="icon-only" (click)="closeMenu()"><ion-icon name="close-outline" color="dark"></ion-icon></ion-button>
|
||||
</ion-buttons>
|
||||
</ion-item>
|
||||
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
</ion-menu-toggle>
|
||||
<ion-content>
|
||||
<ion-list>
|
||||
<ion-list-header>
|
||||
<ion-label>{{ "menu.account" | translate }}</ion-label>
|
||||
</ion-list-header>
|
||||
<ion-menu-toggle>
|
||||
<ion-item button routerLink="signup" [disabled]="user">
|
||||
<ion-icon name="person-add-outline"></ion-icon>
|
||||
<ion-label>{{ "menu.signup" | translate }}</ion-label>
|
||||
</ion-item>
|
||||
</ion-menu-toggle>
|
||||
<ion-menu-toggle>
|
||||
<ion-item button routerLink="login" [disabled]="user">
|
||||
<ion-icon name="log-in-outline"></ion-icon>
|
||||
<ion-label>{{ "menu.signin" | translate }}</ion-label>
|
||||
</ion-item>
|
||||
</ion-menu-toggle>
|
||||
|
||||
<ion-menu-toggle>
|
||||
<ion-item button routerLink="profile" [disabled]="!user">
|
||||
<ion-icon name="person-circle-outline"></ion-icon>
|
||||
<ion-label>{{ "menu.profile" | translate }}</ion-label>
|
||||
</ion-item>
|
||||
</ion-menu-toggle>
|
||||
<ion-menu-toggle>
|
||||
<ion-item button (click)="logout()" [disabled]="!user">
|
||||
<ion-icon name="log-out-outline"></ion-icon>
|
||||
<ion-label>{{ "menu.signout" | translate }}</ion-label>
|
||||
</ion-item>
|
||||
</ion-menu-toggle>
|
||||
<ion-list-header>
|
||||
<ion-label>{{ "menu.settings" | translate }}</ion-label>
|
||||
</ion-list-header>
|
||||
<ion-menu-toggle>
|
||||
<ion-item button routerLink="options">
|
||||
<ion-icon name="settings-outline"></ion-icon>
|
||||
<ion-label>{{ "menu.options" | translate }}</ion-label>
|
||||
</ion-item>
|
||||
</ion-menu-toggle>
|
||||
</ion-list>
|
||||
</ion-content>
|
||||
</ion-menu>
|
||||
<ion-router-outlet id="main"></ion-router-outlet>
|
||||
</ion-app>
|
||||
1
src/app/app.component.scss
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
23
src/app/app.component.spec.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
import { TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
describe('AppComponent', () => {
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [AppComponent],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
it('should create the app', () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.debugElement.componentInstance;
|
||||
expect(app).toBeTruthy();
|
||||
});
|
||||
// TODO: add more tests!
|
||||
|
||||
});
|
||||
53
src/app/app.component.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Auth, user } from '@angular/fire/auth';
|
||||
import { Router } from '@angular/router';
|
||||
import { MenuController } from '@ionic/angular';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { AuthService } from './services/auth.service';
|
||||
import { Storage } from '@ionic/storage-angular';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: 'app.component.html',
|
||||
styleUrls: ['app.component.scss'],
|
||||
})
|
||||
export class AppComponent implements OnInit{
|
||||
user = null;
|
||||
language= '';
|
||||
|
||||
constructor(
|
||||
private menuCtrl: MenuController,
|
||||
private authService: AuthService,
|
||||
private router: Router,
|
||||
private afAuth: Auth,
|
||||
private translateService: TranslateService,
|
||||
private storage: Storage
|
||||
) {
|
||||
user(this.afAuth).subscribe((response) => {
|
||||
//fill the user to verify if someone is logged in
|
||||
this.user = response;
|
||||
});
|
||||
}
|
||||
async ngOnInit() {
|
||||
this.storage.create();
|
||||
this.translateService.setDefaultLang('en'); //set default language English
|
||||
|
||||
this.language = await this.storage.get('language');
|
||||
if (this.language === null){
|
||||
console.log('no value for language in storage, trying getting from browser');
|
||||
this.language = this.translateService.getBrowserLang();
|
||||
//if
|
||||
}
|
||||
this.translateService.use(this.language);
|
||||
}
|
||||
|
||||
|
||||
closeMenu() {
|
||||
this.menuCtrl.close();
|
||||
}
|
||||
|
||||
async logout() {
|
||||
await this.authService.logout();
|
||||
this.router.navigateByUrl('/home', { replaceUrl: true });
|
||||
}
|
||||
}
|
||||
41
src/app/app.module.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { RouteReuseStrategy } from '@angular/router';
|
||||
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
|
||||
import { AppComponent } from './app.component';
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { initializeApp, provideFirebaseApp } from '@angular/fire/app';
|
||||
import { environment } from '../environments/environment';
|
||||
import { provideAuth, getAuth } from '@angular/fire/auth';
|
||||
import { provideFirestore, getFirestore } from '@angular/fire/firestore';
|
||||
import { provideStorage, getStorage } from '@angular/fire/storage';
|
||||
|
||||
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
|
||||
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
|
||||
import { HttpClient, HttpClientModule } from '@angular/common/http';
|
||||
import { IonicStorageModule } from '@ionic/storage-angular';
|
||||
|
||||
//define loader to load local files(on given path) with HttpClient
|
||||
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
|
||||
export function createTranslateLoader(http: HttpClient) {
|
||||
return new TranslateHttpLoader(http, './assets/languages/', '.json');
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [AppComponent],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
IonicModule.forRoot(),
|
||||
AppRoutingModule,
|
||||
HttpClientModule,
|
||||
IonicStorageModule.forRoot(),
|
||||
TranslateModule.forRoot({loader: {provide: TranslateLoader, useFactory: (createTranslateLoader), deps: [HttpClient]}}),
|
||||
provideFirebaseApp(() => initializeApp(environment.firebase)),
|
||||
provideAuth(() => getAuth()),
|
||||
provideFirestore(() => getFirestore()),
|
||||
provideStorage(() => getStorage()),
|
||||
],
|
||||
providers: [{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }],
|
||||
bootstrap: [AppComponent],
|
||||
})
|
||||
export class AppModule {}
|
||||
17
src/app/auth/login/login-routing.module.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
|
||||
import { LoginPage } from './login.page';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: LoginPage
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class LoginPageRoutingModule {}
|
||||
23
src/app/auth/login/login.module.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
import { IonicModule } from '@ionic/angular';
|
||||
|
||||
import { LoginPageRoutingModule } from './login-routing.module';
|
||||
|
||||
import { LoginPage } from './login.page';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
IonicModule,
|
||||
ReactiveFormsModule,
|
||||
LoginPageRoutingModule,
|
||||
TranslateModule
|
||||
],
|
||||
declarations: [LoginPage]
|
||||
})
|
||||
export class LoginPageModule {}
|
||||
52
src/app/auth/login/login.page.html
Normal file
@@ -0,0 +1,52 @@
|
||||
<ion-header class="ion-no-border">
|
||||
<ion-toolbar color="primary">
|
||||
<ion-buttons slot="start">
|
||||
<ion-back-button defaultHref="home" icon="chevron-back-outline"></ion-back-button>
|
||||
</ion-buttons>
|
||||
<ion-title class="ion-text-center">{{ "loginPage.title" | translate}}</ion-title>
|
||||
<ion-buttons slot="end">
|
||||
<ion-menu-button></ion-menu-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content>
|
||||
<ion-card>
|
||||
<ion-card-content>
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col sizeSm="6" offsetSm="3" sizeLg="4" offsetLg="4" sizeMd="6" offsetMd="3" *ngIf="showForm" class="ion-text-center">
|
||||
<form (ngSubmit)="login()" [formGroup]="credentials">
|
||||
<ion-item fill="solid" class="ion-margin-bottom">
|
||||
<ion-input type="email" [placeholder]="'loginPage.email-placeholder' | translate" formControlName="email"><ion-icon name="mail-outline"></ion-icon></ion-input>
|
||||
<ion-icon name="person-outline" slot=“end” align-self-center></ion-icon>
|
||||
<ion-note slot="error" *ngIf="(email.dirty || email.touched) && email.errors">{{ "loginPage.email-invalid" | translate }}</ion-note>
|
||||
</ion-item>
|
||||
<ion-item fill="solid" class="ion-margin-bottom">
|
||||
<ion-input type="password" [placeholder]="'loginPage.password-placeholder' | translate" formControlName="password"><ion-icon name="key-outline"></ion-icon></ion-input>
|
||||
<ion-note slot="error" *ngIf="(password.dirty || password.touched) && password.errors">{{ "loginPage.password-invalid" | translate }}</ion-note>
|
||||
</ion-item>
|
||||
|
||||
<ion-button type="submit" expand="block" [disabled]="!credentials.valid">{{ "loginPage.login-button" | translate }}</ion-button>
|
||||
<a [routerLink]="['/resetpw']">{{ "loginPage.forgot-password" | translate }}</a>
|
||||
</form>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
<ion-row>
|
||||
<ion-col class="ion-text-center" sizeSm="6" offsetSm="3" sizeLg="4" offsetLg="4" sizeMd="6" offsetMd="3">
|
||||
<ion-button type="button" (click)="toggleForm()" expand="block"><ion-icon name="person-outline"></ion-icon>{{ "loginPage.login-username" | translate }}</ion-button>
|
||||
<ion-button type="button" (click)="anonymousLogin()" expand="block"><ion-icon name="eye-outline"></ion-icon>{{ "loginPage.login-anonymous" | translate }}</ion-button>
|
||||
<ion-button type="button" (click)="loginWithGoogle()" expand="block" color="danger"><ion-icon name="logo-google"></ion-icon>{{ "loginPage.login-google" | translate }}</ion-button>
|
||||
<ion-button type="button" (click)="loginWithApple()" expand="block" color="dark"><ion-icon name="logo-apple"></ion-icon>{{ "loginPage.login-apple" | translate }}</ion-button>
|
||||
<a href="signup">{{ "loginPage.goto-signup" | translate }}</a>
|
||||
|
||||
<br>
|
||||
|
||||
</ion-col>
|
||||
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</ion-card-content>
|
||||
</ion-card>
|
||||
|
||||
</ion-content>
|
||||
11
src/app/auth/login/login.page.scss
Normal file
@@ -0,0 +1,11 @@
|
||||
ion-input ion-icon{
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
ion-button {
|
||||
border: 1px solid var(--ion-color-grey);
|
||||
border-radius: 16px;
|
||||
--color-hover: var(--ion-color-primary)
|
||||
}
|
||||
|
||||
|
||||
24
src/app/auth/login/login.page.spec.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { IonicModule } from '@ionic/angular';
|
||||
|
||||
import { LoginPage } from './login.page';
|
||||
|
||||
describe('LoginPage', () => {
|
||||
let component: LoginPage;
|
||||
let fixture: ComponentFixture<LoginPage>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ LoginPage ],
|
||||
imports: [IonicModule.forRoot()]
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(LoginPage);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
}));
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||