Repository: paulsutherland/Polyonic Branch: master Commit: bfe318d726d2 Files: 68 Total size: 67.7 KB Directory structure: gitextract_wfs5lkbz/ ├── .editorconfig ├── .gitignore ├── README.md ├── angular.json ├── config.xml ├── e2e/ │ ├── protractor.conf.js │ ├── src/ │ │ ├── app.e2e-spec.ts │ │ └── app.po.ts │ └── tsconfig.e2e.json ├── electron-builder.json ├── electron.js ├── ionic.config.json ├── package.json ├── resources/ │ ├── android/ │ │ └── xml/ │ │ └── network_security_config.xml │ ├── electron/ │ │ ├── .gitkeep │ │ ├── linux/ │ │ │ ├── DEBIAN/ │ │ │ │ └── control │ │ │ └── app.desktop │ │ ├── osx/ │ │ │ ├── dmg-icon.icns │ │ │ └── icon.icns │ │ ├── polyonic.psd │ │ └── windows/ │ │ └── installer.nsi │ ├── icon.png.md5 │ └── splash.png.md5 ├── src/ │ ├── app/ │ │ ├── app-routing.module.ts │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── data.service.spec.ts │ │ ├── data.service.ts │ │ ├── electron.service.spec.ts │ │ ├── electron.service.ts │ │ ├── events.service.spec.ts │ │ ├── events.service.ts │ │ ├── tab1/ │ │ │ ├── tab1.module.ts │ │ │ ├── tab1.page.html │ │ │ ├── tab1.page.scss │ │ │ ├── tab1.page.spec.ts │ │ │ └── tab1.page.ts │ │ ├── tab2/ │ │ │ ├── tab2.module.ts │ │ │ ├── tab2.page.html │ │ │ ├── tab2.page.scss │ │ │ ├── tab2.page.spec.ts │ │ │ └── tab2.page.ts │ │ ├── tab3/ │ │ │ ├── tab3.module.ts │ │ │ ├── tab3.page.html │ │ │ ├── tab3.page.scss │ │ │ ├── tab3.page.spec.ts │ │ │ └── tab3.page.ts │ │ └── tabs/ │ │ ├── tabs.module.ts │ │ ├── tabs.page.html │ │ ├── tabs.page.scss │ │ ├── tabs.page.spec.ts │ │ ├── tabs.page.ts │ │ └── tabs.router.module.ts │ ├── environments/ │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── global.scss │ ├── index.html │ ├── karma.conf.js │ ├── main.ts │ ├── polyfills.ts │ ├── test.ts │ ├── theme/ │ │ └── variables.scss │ ├── tsconfig.app.json │ └── tsconfig.spec.json ├── tsconfig.json └── tslint.json ================================================ FILE CONTENTS ================================================ ================================================ FILE: .editorconfig ================================================ # editorconfig.org root = true [*] indent_style = space indent_size = 2 end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true [*.json] indent_size = 2 [*.md] trim_trailing_whitespace = false ================================================ FILE: .gitignore ================================================ node_modules *.log .DS_Store Thumbs.db *.swp *.autogenerated /build/* !/build/.gitkeep /releases/ /tmp/ /src/node_modules /src/platforms /src/plugins /src/www/build/ /src/.tmp/ .vscode /dist/* .sourcemaps/ plugins/* www/ release/ platforms/ app.db/ ================================================ FILE: README.md ================================================ # Polyonic ## The ultimate "Universal Web App" [![JavaScript Style Guide](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com/) [![devDependencies Status](https://david-dm.org/paulsutherland/Polyonic/dev-status.svg)](https://david-dm.org/paulsutherland/Polyonic?type=dev) [![optionalDependencies Status](https://david-dm.org/paulsutherland/Polyonic/optional-status.svg)](https://david-dm.org/paulsutherland/Polyonic?type=optional) [![MIT Licence](https://badges.frapsoft.com/os/mit/mit.svg?v=103)](https://opensource.org/licenses/mit-license.php) [![Open Source Love](https://badges.frapsoft.com/os/v1/open-source.svg?v=103)](https://github.com/ellerbrock/open-source-badge/) > Now using Ionic 5, Electron 11 and Angular 11 :tada:. See here for [Ionic 1](https://github.com/paulsutherland/Polyonic/tree/Ionic1) and [Ionic 3](https://github.com/paulsutherland/Polyonic/tree/Ionic3). ## Build once using web technologies and deploy everywhere! Polyonic is an Electron Ionic application shell for creating Web Apps, Progressive Mobile Web Apps, Native Mobile Apps and Desktop Apps. This project combines the [Electron Framework](http://electron.atom.io/) with the [Ionic Framework](https://ionicframework.com/) and provides a starter for building out an app that can run on either the desktop (macOS, Windows and Linux), a browser or mobile devices (iOS and Android). You can use this application to build and run on one or all of these platforms. ## Motivation When working in small teams creating web and mobile applications, it is difficult and time consuming for new team members to pick up the different technologies for each platform. I have also been asked a few questions that motivated me to try Polyonic out: - Is there a way to run this mobile app on the desktop? - Can we cache more in the browser for offline working? - Can we have one Universal app that can run on the desktop, mobile, web and Office 365? These questions made me think about the limitations of the browser for off-line editing and caching and was there a way to create a package that can be used to flesh out any app we require, whilst reducing the overhead of having to learn numerous libraries and frameworks for each platform. And that is why I decided to try combining Electron and Ionic. Is it wise to have a universal app using a mobile framework? Probably not, but it is fun :wink: ## Quick start The dependencies for this project are [Node.js](https://nodejs.org), [Ionic Framework](https://ionicframework.com/) and [Cordova](https://cordova.apache.org/). You will need the latest Node 14 LTS and NPM 7 installed. Make sure you have [node installed and running](https://nodejs.org/en/download/), then install Ionic and Cordova globally using npm. ```node npm install -g ionic@latest cordova@latest ``` Clone the repo, change into the Polyonic directory, install the npm packages and run the Electron app ```node git clone --depth 1 https://github.com/paulsutherland/Polyonic cd Polyonic npm install npm run electron:dev ``` You now have Electron and Ionic running as a Desktop app. ## Running live reload for development When developing, you will want to have the app live reload as you save your changes. ### Desktop ```node npm run electron:dev ``` For debugging the main process you will need to have the Chrome Browser installed. ```node npm run electron:dev:debug ``` Open Chrome and navigate to chrome://inspect/ and select the Electron remote target that is available to attach the debugger to. If you require live reloading of the main process debugging session, then it is recommended that you install the Chrome plugin [Node.js V8 --inspector Manager (NiM)](https://chrome.google.com/webstore/detail/nodejs-v8-inspector-manag/gnhhdgbaldcilmgcpfddgdbkhjohddkj?hl=en). In the plugin settings, set the host to localhost, the port to 9229 and the app to auto. This will allow you to live reload changes made to the main process (electron.js file). ```node npm run electron:dev:debug-live ``` ### iOS #### Emulator ```node npm run emulate:ios-dev ``` #### Device ```node npm run device:ios-dev ``` ### Android #### Emulator ```node npm run emulate:android-dev ``` #### Device ```node npm run device:android-dev ``` ## Building on Windows For building on Windows you will need to install the Nullsoft Scriptable Install System. You can [download NSIS here](http://nsis.sourceforge.net/Main_Page) You will need to make sure the NSIS path is added as an environment variable: ```node setx PATH "%PATH%;C:\Program Files (x86)\NSIS" ``` Or using [point and click](http://nsis.sourceforge.net/Main_Page). ## Porting existing Ionic Apps It is possible to port your existing apps to run on the desktop, but you may need to make some platform adjustments to call out to an equivalent api for any mobile plugins your app uses. The app includes and angular service for electron which makes is easy to call the Electron APIs from within the Ionic components. For example you may want to check what platform you are running on before you make an api call, either calling out to an Ionic plugin, an Electron api or a browser api. The data service component ```data.service.ts``` has an example of setting up a PouchDB database depending upon what platform the app is running on. ```javascript import { ElectronService } from './electron.service' import { Platform } from '@ionic/angular' ... constructor(public electron: ElectronService, private platform: Platform) {} ... public setup() { const ctx = this console.log('Setting up the application database') if (ctx.electron.isElectronApp) { return ctx.desktopDB() } if (ctx.platform.is('mobile')) { return ctx.mobileDB() } else { return ctx.webDB() } } ``` ## Encryption at rest If your app requires your data to be encrypted at rest, the app includes an example of using the [cordova-sqlcipher-adapter](https://github.com/brodybits/cordova-sqlcipher-adapter) plugin for Ionic and the [polyonic-secure-pouch](https://github.com/paulsutherland/polyonic-secure-pouch) plugin for the desktop and browser. The Cordova example encrypts the local sqlite database, whereas the secure pouch plugin encrypts and decrypts your data when it is saved or fetched from the browser database. Either way, at rest, your data is encrypted. You will need to include a key or password/secret from the user, or an api app, to encrypt the data. You can store this key in [Ionic Secure Storage](https://ionicframework.com/docs/native/secure-storage/) or for the desktop you can use [Keytar](https://github.com/atom/node-keytar). ## NPM Script Commands | Platform/Commands || |:-|:-| | **Desktop** || | `npm run electron:dev` | For development using live reload and opens with developer tools | | `npm run electron:local` | Build and run on the desktop, no livereload or developer tools | | `npm run electron:linux` | Production build for linux platform. (Requires Linux) | | `npm run electron:mac` | Production build for macOS. (Requires macOS) | | `npm run electron:windows` | Production build for Windows. (Requires Windows) | | **iOS** || | `npm run emulate:ios-dev` | For iOS development on the simulator using live reload | | `npm run emulate:ios` | For iOS development on the simulator | | `npm run device:ios-dev` | For iOS development on an iOS device using live reload | | `npm run device:ios` | For iOS development on an iOS device | | `npm run release:ios` | Production build for iOS. (Requires XCode on macOS) | | **Android** || | `npm run emulate:android-dev` | For Android development on an emulator using live reload | | `npm run emulate:android` | For Android development on an emulator | | `npm run device:android-dev` | For Android development on an Android device using live reload | | `npm run device:android` | For Android development on an Android device | | **Web Apps and PWA Apps** || | `npm run ionic` | For web and progressive web app development using live reload | ## Publishing your apps [How to publish an Android App](https://ionicframework.com/docs/publishing/play-store) [How to publish an iOS App](https://ionicframework.com/docs/publishing/play-store) [How to publish a macOS and/or Windows App](https://ionicframework.com/docs/publishing/desktop-app) [How to publish a progressive web app](https://ionicframework.com/docs/publishing/progressive-web-app) ## Credits This application was built using the [Electron Framework](http://electron.atom.io/) :heart: for creating desktop apps and [Ionic Framework](http://ionicframework.com/) :heart: for the UI and creating Native Mobile Applications, Progressive Mobile Web Applications and Web Applications. The app was inspired by: [Angular Electron Shell](https://github.com/maximegris/angular-electron) :punch: [Simple Cryptor Pouch Plugin](https://www.npmjs.com/package/simple-cryptor-pouch) (forked to create the [polyonic-secure-pouch](https://github.com/paulsutherland/polyonic-secure-pouch) plugin). :pray: ## Polyonic for Enterprise This project is a generic shell/seed project that lets you build your app for multiple platforms. For Enterprise use, including: - Azure AD multi-tenancy Integration - Office 365 apps - Realtime CouchDB integration - End to end encryption - Support services - WebXR - WebRTC You can contact us at [polyonic.com](http://polyonic.com) :metal: ## License Released under the MIT license. ================================================ FILE: angular.json ================================================ { "$schema": "./node_modules/@angular-devkit/core/src/workspace/workspace-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": { "progress": false, "outputPath": "www", "index": "src/index.html", "main": "src/main.ts", "polyfills": "src/polyfills.ts", "tsConfig": "src/tsconfig.app.json", "allowedCommonJsDependencies": [ "pouchdb-adapter-cordova-sqlite", "polyonic-secure-pouch", "pouchdb", "pouchdb-utils" ], "assets": [ { "glob": "**/*", "input": "src/assets", "output": "assets" }, { "glob": "**/*.svg", "input": "node_modules/ionicons/dist/ionicons/svg", "output": "./svg" } ], "styles": [ { "input": "src/theme/variables.scss" }, { "input": "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 } } }, "serve": { "builder": "@angular-devkit/build-angular:dev-server", "options": { "browserTarget": "app:build" }, "configurations": { "production": { "browserTarget": "app:build:production" } } }, "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": "src/tsconfig.spec.json", "karmaConfig": "src/karma.conf.js", "styles": [ "styles.css" ], "scripts": [], "assets": [ { "glob": "favicon.ico", "input": "src/", "output": "/" }, { "glob": "**/*", "input": "src/assets", "output": "/assets" } ] } }, "lint": { "builder": "@angular-devkit/build-angular:tslint", "options": { "tsConfig": [ "src/tsconfig.app.json", "src/tsconfig.spec.json" ], "exclude": [ "**/node_modules/**" ] } }, "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" } } } } }, "app-e2e": { "root": "e2e/", "projectType": "application", "architect": { "e2e": { "builder": "@angular-devkit/build-angular:protractor", "options": { "protractorConfig": "e2e/protractor.conf.js", "devServerTarget": "app:serve" } }, "lint": { "builder": "@angular-devkit/build-angular:tslint", "options": { "tsConfig": "e2e/tsconfig.e2e.json", "exclude": [ "**/node_modules/**" ] } } } } }, "cli": { "defaultCollection": "@ionic/angular-toolkit" }, "schematics": { "@ionic/angular-toolkit:component": { "styleext": "scss" }, "@ionic/angular-toolkit:page": { "styleext": "scss" } } } ================================================ FILE: config.xml ================================================ Polyonic An awesome Polyonic Ionic/Cordova app. Polyonic Framework Team ================================================ FILE: e2e/protractor.conf.js ================================================ // Protractor configuration file, see link for more information // https://github.com/angular/protractor/blob/master/lib/config.ts const { SpecReporter } = require('jasmine-spec-reporter'); exports.config = { allScriptsTimeout: 11000, specs: [ './src/**/*.e2e-spec.ts' ], capabilities: { 'browserName': 'chrome' }, directConnect: true, baseUrl: 'http://localhost:4200/', framework: 'jasmine', jasmineNodeOpts: { showColors: true, defaultTimeoutInterval: 30000, print: function() {} }, onPrepare() { require('ts-node').register({ project: 'e2e/tsconfig.e2e.json' }); jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); } }; ================================================ FILE: e2e/src/app.e2e-spec.ts ================================================ import { AppPage } from './app.po'; describe('new App', () => { let page: AppPage; beforeEach(() => { page = new AppPage(); }); it('should display welcome message', () => { page.navigateTo(); expect(page.getParagraphText()).toContain('The world is your oyster.'); }); }); ================================================ FILE: e2e/src/app.po.ts ================================================ import { browser, by, element } from 'protractor'; export class AppPage { navigateTo() { return browser.get('/'); } getParagraphText() { return element(by.deepCss('app-root ion-content')).getText(); } } ================================================ FILE: e2e/tsconfig.e2e.json ================================================ { "extends": "../tsconfig.json", "compilerOptions": { "outDir": "../out-tsc/e2e", "baseUrl": "./", "module": "commonjs", "target": "es5" } } ================================================ FILE: electron-builder.json ================================================ { "productName": "Polyonic", "directories": { "buildResources": "./resources/electron", "output": "release/" }, "files": [ "**/*", "!*.ts", "!*.code-workspace", "!LICENSE.md", "!package.json", "!package-lock.json", "!config/", "!platforms/", "!plugins/", "!src/", "!e2e/", "!hooks/", "!.angular-cli.json", "!_config.yml", "!karma.conf.js", "!tsconfig.json", "!tslint.json", "!app.db/", "!release/", "!resources/" ], "win": { "icon": "resources/electron/windows/icon.ico", "target": [ "portable" ] }, "squirrelWindows": { "msi":"true" }, "msi" : { "warningsAsErrors": false }, "nsis" : { "oneClick": false, "allowToChangeInstallationDirectory": true }, "appx": { "publisherDisplayName":"Polyonic" }, "mac": { "icon": "resources/electron/osx/icon.icns", "target": [ "dmg" ] }, "linux": { "icon": "dist", "target": [ "AppImage" ] } } ================================================ FILE: electron.js ================================================ const electron = require('electron') const app = electron.app const BrowserWindow = electron.BrowserWindow const path = require('path') // process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = true let win const args = process.argv.slice(1) const serve = args.some(val => val === '--serve') function createWindow () { debugger win = new BrowserWindow({ width: 1800, height: 1200, center: true, icon: path.join(__dirname, './resources/electron/icons/64x64.png'), webPreferences: { nodeIntegration: true, enableRemoteModule: true, contextIsolation: false } }) if (serve) { win.loadURL('http://localhost:4200') } else { win.loadURL(`file://${__dirname}/www/index.html`) } win.webContents.on('did-fail-load', () => { win.loadURL(`file://${__dirname}/www/index.html`) }) console.log(`Node Environment: ${process.env.NODE_ENV}`) if (process.env.NODE_ENV === 'development') { win.toggleDevTools() } // Emitted when the window is closed. win.on('closed', () => { // Dereference the window object, usually you would store window // in an array if your app supports multi windows, this is the time // when you should delete the corresponding element. win = null }) } try { // This method will be called when Electron has finished // initialization and is ready to create browser windows. // Some APIs can only be used after this event occurs. app.on('ready', createWindow) // Quit when all windows are closed. app.on('window-all-closed', () => { // On OS X it is common for applications and their menu bar // to stay active until the user quits explicitly with Cmd + Q if (process.platform !== 'darwin') { app.quit() } }) app.on('activate', () => { // On OS X it's common to re-create a window in the app when the // dock icon is clicked and there are no other windows open. if (win === null) { createWindow() } }) } catch (e) { // Catch Error // throw e; } ================================================ FILE: ionic.config.json ================================================ { "name": "ionic5", "integrations": { "cordova": {} }, "type": "angular" } ================================================ FILE: package.json ================================================ { "name": "polyonic", "productName": "Polyonic App", "description": "An Ionic project", "version": "3.0.6", "author": { "name": "Your Name", "email": "email@your-email.com", "url": "http://yourwebsite.com" }, "repository": "https://github.com/paulsutherland/polyonic", "copyright": "© 2018, Your Name", "private": true, "main": "electron.js", "scripts": { "build:electron": "ng build --base-href ./", "build:electron:dev": "npm run build:electron -- -c dev", "build:electron:prod": "npm run build:electron -- -c production", "electron:dev": "export NODE_ENV=development || set NODE_ENV=development && npm-run-all -p ng:serve electron:serve", "electron:dev:debug": "npm-run-all -p ng:serve electron:serve:debug", "electron:dev:debug-live": "npm-run-all -p ng:serve electron:serve:debug-live", "electron:serve": "wait-on http-get://localhost:4200/ && run-electron . --serve", "electron:serve:debug": "wait-on http-get://localhost:4200/ && run-electron --inspect-brk=9229 . --serve", "electron:serve:debug-live": "wait-on http-get://localhost:4200/ && nodemon --watch electron.js --exec run-electron --inspect-brk=9229 . --serve", "electron:local": "npm run build:electron:prod && run-electron .", "electron:linux": "npm run build:electron:prod && npx electron-builder build --linux", "electron:windows": "npm run build:electron:prod && npx electron-builder build --windows", "electron:mac": "npm run build:electron:prod && npx electron-builder build --mac", "ionic": "npm run ng:serve:web", "emulate:ios-dev": "ionic cordova emulate ios --l", "run:ios-dev": "ionic cordova run ios --l --device", "emulate:ios": "ionic cordova emulate ios", "run:ios": "ionic cordova run ios --device", "release:ios": "ionic cordova build ios --prod --release", "emulate:android-dev": "ionic cordova emulate android --l", "run:android-dev": "ionic cordova run android --device --l", "emulate:android": "ionic cordova emulate android", "run:android": "ionic cordova run android --device", "release:android": "ionic cordova build android --prod --release ", "ng": "ng", "ng:serve": "ng serve", "ng:serve:web": "ng serve -o", "test": "ng test", "e2e": "ng e2e", "xcode": "open -a Xcode platforms/ios/" }, "dependencies": { "@angular/common": "11.2.6", "@angular/core": "11.2.6", "@angular/forms": "11.2.6", "@angular/platform-browser": "11.2.6", "@angular/platform-browser-dynamic": "11.2.6", "@angular/router": "11.2.6", "@ionic-native/core": "5.31.1", "@ionic-native/splash-screen": "5.31.1", "@ionic-native/status-bar": "5.31.1", "@ionic/angular": "5.6.1", "cordova-android": "9.0.0", "cordova-ios": "6.2.0", "cordova-plugin-device": "2.0.3", "cordova-plugin-ionic-keyboard": "2.2.0", "cordova-plugin-ionic-webview": "^5.0.0", "cordova-plugin-splashscreen": "^6.0.0", "cordova-plugin-statusbar": "2.4.3", "cordova-plugin-whitelist": "1.3.4", "cordova-sqlcipher-adapter": "^0.5.3", "core-js": "3.9.1", "polyonic-secure-pouch": "1.0.7", "pouchdb": "7.2.2", "pouchdb-adapter-cordova-sqlite": "2.0.8", "run-electron": "1.0.0", "rxjs": "6.6.6", "zone.js": "0.11.4" }, "devDependencies": { "@angular-devkit/build-angular": "^0.1102.5", "@angular/cli": "~11.2.5", "@angular/compiler": "11.2.6", "@angular/compiler-cli": "11.2.6", "@angular/language-service": "11.2.6", "@ionic/angular-toolkit": "^3.1.1", "@types/jasmine": "3.6.7", "@types/jasminewd2": "2.0.8", "@types/node": "14.14.35", "codelyzer": "6.0.1", "electron": "11.3.0", "electron-builder": "22.10.5", "husky": "5.1.3", "jasmine-core": "3.7.1", "jasmine-spec-reporter": "6.0.0", "karma": "6.2.0", "karma-chrome-launcher": "3.1.0", "karma-coverage-istanbul-reporter": "3.0.3", "karma-jasmine": "4.0.1", "karma-jasmine-html-reporter": "1.5.4", "nodemon": "^2.0.7", "npm-run-all": "4.1.5", "protractor": "7.0.0", "ts-node": "9.1.1", "tslint": "6.1.3", "typescript": "4.1.5", "wait-on": "5.3.0" }, "cordova": { "plugins": { "cordova-plugin-whitelist": {}, "cordova-plugin-statusbar": {}, "cordova-plugin-device": {}, "cordova-plugin-splashscreen": {}, "cordova-plugin-ionic-webview": {}, "cordova-plugin-ionic-keyboard": {}, "cordova-sqlcipher-adapter": {}, "cordova-plugin-androidx-adapter": {} }, "platforms": [] } } ================================================ FILE: resources/android/xml/network_security_config.xml ================================================ localhost ================================================ FILE: resources/electron/.gitkeep ================================================ ================================================ FILE: resources/electron/linux/DEBIAN/control ================================================ Package: {{name}} Version: {{version}} Maintainer: {{author}} Priority: optional Architecture: amd64 Installed-Size: {{size}} Description: {{description}} ================================================ FILE: resources/electron/linux/app.desktop ================================================ [Desktop Entry] Version=1.0 Type=Application Encoding=UTF-8 Name={{productName}} Comment={{description}} Exec=/opt/{{name}}/{{name}} Path=/opt/{{name}}/ Icon=/opt/{{name}}/icon.png Terminal=false Categories=Application; ================================================ FILE: resources/electron/windows/installer.nsi ================================================ ; NSIS packaging/install script ; Docs: http://nsis.sourceforge.net/Docs/Contents.html !include LogicLib.nsh !include nsDialogs.nsh ; -------------------------------- ; Variables ; -------------------------------- !define dest "{{dest}}" !define src "{{src}}" !define name "{{name}}" !define productName "{{productName}}" !define author "{{author}}" !define version "{{version}}" !define icon "{{icon}}" !define setupIcon "{{setupIcon}}" !define banner "{{banner}}" !define exec "{{productName}}.exe" !define regkey "Software\${productName}" !define uninstkey "Software\Microsoft\Windows\CurrentVersion\Uninstall\${productName}" !define uninstaller "uninstall.exe" ; -------------------------------- ; Installation ; -------------------------------- Unicode true SetCompressor /SOLID lzma Name "${productName}" Icon "${setupIcon}" OutFile "${dest}" InstallDir "$PROGRAMFILES\${productName}" InstallDirRegKey HKLM "${regkey}" "" RequestExecutionLevel admin CRCCheck on SilentInstall normal XPStyle on ShowInstDetails nevershow AutoCloseWindow false WindowIcon off Caption "${productName} Setup" ; Don't add sub-captions to title bar SubCaption 3 " " SubCaption 4 " " Page custom welcome Page instfiles Var Image Var ImageHandle Function .onInit ; Extract banner image for welcome page InitPluginsDir ReserveFile "${banner}" File /oname=$PLUGINSDIR\banner.bmp "${banner}" FunctionEnd ; Custom welcome page Function welcome nsDialogs::Create 1018 ${NSD_CreateLabel} 185 1u 210 100% "Welcome to ${productName} version ${version} installer.$\r$\n$\r$\nClick install to begin." ${NSD_CreateBitmap} 0 0 170 210 "" Pop $Image ${NSD_SetImage} $Image $PLUGINSDIR\banner.bmp $ImageHandle nsDialogs::Show ${NSD_FreeImage} $ImageHandle FunctionEnd ; Installation declarations Section "Install" WriteRegStr HKLM "${regkey}" "Install_Dir" "$INSTDIR" WriteRegStr HKLM "${uninstkey}" "DisplayName" "${productName}" WriteRegStr HKLM "${uninstkey}" "DisplayIcon" '"$INSTDIR\icon.ico"' WriteRegStr HKLM "${uninstkey}" "UninstallString" '"$INSTDIR\${uninstaller}"' WriteRegStr HKLM "${uninstkey}" "Publisher" "${author}" WriteRegStr HKLM "${uninstkey}" "DisplayVersion" "${version}" ; Remove all application files copied by previous installation RMDir /r "$INSTDIR" SetOutPath $INSTDIR ; Include all files from /build directory File /r "${src}\*" ; Create start menu shortcut SetShellVarContext all CreateShortCut "$SMPROGRAMS\${productName}.lnk" "$INSTDIR\${exec}" "" "$INSTDIR\icon.ico" ; Create desktop shortcut CreateShortCut "$DESKTOP\${productName}.lnk" "$INSTDIR\${exec}" "" "$INSTDIR\icon.ico" WriteUninstaller "${uninstaller}" SectionEnd ; -------------------------------- ; Uninstaller ; -------------------------------- ShowUninstDetails nevershow UninstallCaption "Uninstall ${productName}" UninstallText "Don't like ${productName} anymore? Hit uninstall button." UninstallIcon "${icon}" UninstPage custom un.confirm un.confirmOnLeave UninstPage instfiles Var RemoveAppDataCheckbox Var RemoveAppDataCheckbox_State ; Custom uninstall confirm page Function un.confirm nsDialogs::Create 1018 ${NSD_CreateLabel} 1u 1u 100% 24u "If you really want to remove ${productName} from your computer press uninstall button." ${NSD_CreateCheckbox} 1u 35u 100% 10u "Remove also my ${productName} personal data" Pop $RemoveAppDataCheckbox nsDialogs::Show FunctionEnd Function un.confirmOnLeave ; Save checkbox state on page leave ${NSD_GetState} $RemoveAppDataCheckbox $RemoveAppDataCheckbox_State FunctionEnd ; Uninstall declarations Section "Uninstall" DeleteRegKey HKLM "${uninstkey}" DeleteRegKey HKLM "${regkey}" SetShellVarContext all Delete "$SMPROGRAMS\${productName}.lnk" ; Remove desktop shortcut Delete "$DESKTOP\${productName}.lnk" ; Remove whole directory from Program Files RMDir /r "$INSTDIR" ; Remove also appData directory generated by your app if user checked this option ${If} $RemoveAppDataCheckbox_State == ${BST_CHECKED} RMDir /r "$APPDATA\${productName}" ${EndIf} SectionEnd ================================================ FILE: resources/icon.png.md5 ================================================ e495003092b862d39b09a0f1b31f732b ================================================ FILE: resources/splash.png.md5 ================================================ f010d2a2420ae8b5b5fa398e77da6397 ================================================ FILE: src/app/app-routing.module.ts ================================================ import { NgModule } from '@angular/core' import { Routes, RouterModule } from '@angular/router' const routes: Routes = [ { path: '', loadChildren: './tabs/tabs.module#TabsPageModule' } ] @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule {} ================================================ FILE: src/app/app.component.html ================================================ ================================================ FILE: src/app/app.component.spec.ts ================================================ import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core' import { TestBed, async } from '@angular/core/testing' import { Platform } from '@ionic/angular' import { SplashScreen } from '@ionic-native/splash-screen/ngx' import { StatusBar } from '@ionic-native/status-bar/ngx' import { AppComponent } from './app.component' describe('AppComponent', () => { let statusBarSpy, splashScreenSpy, platformReadySpy, platformSpy beforeEach(async(() => { statusBarSpy = jasmine.createSpyObj('StatusBar', ['styleDefault']) splashScreenSpy = jasmine.createSpyObj('SplashScreen', ['hide']) platformReadySpy = Promise.resolve() platformSpy = jasmine.createSpyObj('Platform', { ready: platformReadySpy }) TestBed.configureTestingModule({ declarations: [AppComponent], schemas: [CUSTOM_ELEMENTS_SCHEMA], providers: [ { provide: StatusBar, useValue: statusBarSpy }, { provide: SplashScreen, useValue: splashScreenSpy }, { provide: Platform, useValue: platformSpy }, ], }).compileComponents() })) it('should create the app', () => { const fixture = TestBed.createComponent(AppComponent) const app = fixture.debugElement.componentInstance expect(app).toBeTruthy() }) it('should initialize the app', async () => { TestBed.createComponent(AppComponent) expect(platformSpy.ready).toHaveBeenCalled() await platformReadySpy expect(statusBarSpy.styleDefault).toHaveBeenCalled() expect(splashScreenSpy.hide).toHaveBeenCalled() }) // TODO: add more tests! }) ================================================ FILE: src/app/app.component.ts ================================================ import { Component } from '@angular/core' import { Platform } from '@ionic/angular' import { SplashScreen } from '@ionic-native/splash-screen/ngx' import { StatusBar } from '@ionic-native/status-bar/ngx' import { DataService } from './data.service' @Component({ selector: 'app-root', templateUrl: 'app.component.html' }) export class AppComponent { constructor( private platform: Platform, private splashScreen: SplashScreen, private statusBar: StatusBar, private data: DataService ) { this.initializeApp() } initializeApp() { this.platform.ready().then(() => { if (this.platform.is('mobile')) { this.statusBar.styleLightContent() this.splashScreen.hide() } this.data.setup() .then(info => { console.log('Database setup complete') }) .catch(error => console.log('Error setting up the Database: ', error)) }) } } ================================================ FILE: src/app/app.module.ts ================================================ import { NgModule } from '@angular/core' import { BrowserModule } from '@angular/platform-browser' import { RouteReuseStrategy } from '@angular/router' import { IonicModule, IonicRouteStrategy } from '@ionic/angular' import { SplashScreen } from '@ionic-native/splash-screen/ngx' import { StatusBar } from '@ionic-native/status-bar/ngx' import { AppRoutingModule } from './app-routing.module' import { AppComponent } from './app.component' @NgModule({ declarations: [AppComponent], entryComponents: [], imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule], providers: [ StatusBar, SplashScreen, { provide: RouteReuseStrategy, useClass: IonicRouteStrategy } ], bootstrap: [AppComponent] }) export class AppModule {} ================================================ FILE: src/app/data.service.spec.ts ================================================ import { TestBed, inject } from '@angular/core/testing' import { DataService } from './data.service' describe('DataService', () => { beforeEach(() => { TestBed.configureTestingModule({ providers: [DataService] }) }) it('should be created', inject([DataService], (service: DataService) => { expect(service).toBeTruthy() })) }) ================================================ FILE: src/app/data.service.ts ================================================ import { Injectable } from '@angular/core' import { Platform } from '@ionic/angular' import { environment } from '../environments/environment' import { ElectronService } from './electron.service' import { EventService } from './events.service' import * as PouchDB from 'pouchdb/dist/pouchdb' import SecurePouch from 'polyonic-secure-pouch' import cordovaSqlitePlugin from 'pouchdb-adapter-cordova-sqlite' @Injectable({ providedIn: 'root' }) export class DataService { public db: any public dbInfo: any constructor( public electron: ElectronService, private events: EventService, private platform: Platform ) {} public setup() { const ctx = this console.log('Setting up the application database') if (ctx.platform.is('mobile')) { return ctx.mobileDB() } else { return ctx.webDB() } } private mobileDB() { const ctx = this console.log('This app is running on a mobile device') return new Promise((resolve, reject) => { ctx.platform.ready() .then(() => { // Go for either an encrypted db or encrypted data // There is a greater performance hit on the encrypted data option PouchDB.plugin(cordovaSqlitePlugin) return ctx.db = new PouchDB('app.db', { adapter: 'cordova-sqlite', key: 'secret', // <<<<<<<<<<<<< Replace with your secret key iosDatabaseLocation: 'Documents' }) // PouchDB.plugin(SecurePouch) // ctx.db = new PouchDB('app.db') // ctx.db.securePouch('secret') // <<<<<<<<<<<<< Replace with your secret key }) .then(res => { return ctx.db.info() }) .then(info => { ctx.events.publish('database:available', info) resolve() }) .catch(error => { console.log('Error waiting for platform to load', error) reject(error) }) }) } private webDB() { const ctx = this console.log('This app is running in a web browser') return new Promise((resolve, reject) => { ctx.platform.ready() .then(() => { PouchDB.plugin(SecurePouch) return ctx.db = new PouchDB('app.db') }) .then(res => { ctx.db.encrypt('password') // <<<<<<<<<<<<< Replace with your secret key return ctx.db.info() }) .then(info => { ctx.events.publish('database:available', info) resolve() }) .catch(error => { console.log('Error waiting for platform to load', error) reject(error) }) }) } } ================================================ FILE: src/app/electron.service.spec.ts ================================================ import { TestBed } from '@angular/core/testing'; import { ElectronService } from './electron.service'; describe('ElectronService', () => { let service: ElectronService; beforeEach(() => { TestBed.configureTestingModule({}); service = TestBed.inject(ElectronService); }); it('should be created', () => { expect(service).toBeTruthy(); }); }); ================================================ FILE: src/app/electron.service.ts ================================================ import { Injectable } from '@angular/core' import { ipcRenderer, webFrame, remote } from 'electron' import * as childProcess from 'child_process' import * as fs from 'fs' @Injectable({ providedIn: 'root' }) export class ElectronService { ipcRenderer: typeof ipcRenderer webFrame: typeof webFrame remote: typeof remote childProcess: typeof childProcess fs: typeof fs get isElectron(): boolean { return !!(typeof navigator === 'object' && typeof navigator.userAgent === 'string' && navigator.userAgent.indexOf('Electron') >= 0) } get isElectronApp(): boolean { // For compatibility with anyone who used the ngx-electron package return this.isElectron } constructor() { if (this.isElectron) { this.ipcRenderer = window.require('electron').ipcRenderer this.webFrame = window.require('electron').webFrame this.remote = window.require('electron').remote this.childProcess = window.require('child_process') this.fs = window.require('fs') } } } ================================================ FILE: src/app/events.service.spec.ts ================================================ import { TestBed } from '@angular/core/testing'; import { EventsService } from './events.service'; describe('EventsService', () => { beforeEach(() => TestBed.configureTestingModule({})); it('should be created', () => { const service: EventsService = TestBed.get(EventsService); expect(service).toBeTruthy(); }); }); ================================================ FILE: src/app/events.service.ts ================================================ import { Injectable } from '@angular/core' import { Subject, Subscription } from 'rxjs' @Injectable({ providedIn: 'root' }) export class EventService { private channels: { [key: string]: Subject } = {} subscribe(topic: string, observer: (_: any) => void): Subscription { const ctx = this if (!ctx.channels[topic]) { ctx.channels[topic] = new Subject() } return ctx.channels[topic].subscribe(observer) } publish(topic: string, data: any): void { const ctx = this const subject = ctx.channels[topic] if (!subject) { return } // Or you can create a new subject for future subscribers subject.next(data) } destroy(topic: string): null { const ctx = this const subject = ctx.channels[topic] if (!subject) { return } subject.complete() delete ctx.channels[topic] } } ================================================ FILE: src/app/tab1/tab1.module.ts ================================================ import { IonicModule } from '@ionic/angular'; import { RouterModule } from '@angular/router'; import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; import { Tab1Page } from './tab1.page'; @NgModule({ imports: [ IonicModule, CommonModule, FormsModule, RouterModule.forChild([{ path: '', component: Tab1Page }]) ], declarations: [Tab1Page] }) export class Tab1PageModule {} ================================================ FILE: src/app/tab1/tab1.page.html ================================================ Tab One Get Started Welcome to Polyonic

Now that your app has been created, you'll want to start building out features and components. Check out some of the resources below for next steps.

System Data
          Node v{{electron.remote.process.versions.node}}
          Chromium v{{electron.remote.process.versions.chrome}}
          Electron v{{electron.remote.process.versions.electron}}
        
We are using PouchDB for our Database
{{dbInfo | json}}
================================================ FILE: src/app/tab1/tab1.page.scss ================================================ .welcome-card ion-img { max-height: 35vh; overflow: hidden; } ================================================ FILE: src/app/tab1/tab1.page.spec.ts ================================================ import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { Tab1Page } from './tab1.page'; describe('Tab1Page', () => { let component: Tab1Page; let fixture: ComponentFixture; beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [Tab1Page], schemas: [CUSTOM_ELEMENTS_SCHEMA], }).compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(Tab1Page); component = fixture.componentInstance; fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); }); ================================================ FILE: src/app/tab1/tab1.page.ts ================================================ import { Component, OnInit } from '@angular/core' import { ElectronService } from '../electron.service' import { DataService } from '../data.service' import { EventService } from '../events.service' @Component({ selector: 'app-tab1', templateUrl: 'tab1.page.html', styleUrls: ['tab1.page.scss'] }) export class Tab1Page implements OnInit { public db: any public dbInfo: Object public electron: any constructor( public electronService: ElectronService, private data: DataService, private events: EventService ) { this.events.subscribe('database:available', (info) => { console.log('Database is now available') this.db = this.data.db this.dbInfo = info }) } ngOnInit () { const ctx = this ctx.electron = ctx.electronService if (ctx.electron.isElectronApp) { ctx.db = ctx.data.db ctx.data.db.info() .then(info => ctx.dbInfo = info) .catch(err => console.log(err)) } } } ================================================ FILE: src/app/tab2/tab2.module.ts ================================================ import { IonicModule } from '@ionic/angular'; import { RouterModule } from '@angular/router'; import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; import { Tab2Page } from './tab2.page'; @NgModule({ imports: [ IonicModule, CommonModule, FormsModule, RouterModule.forChild([{ path: '', component: Tab2Page }]) ], declarations: [Tab2Page] }) export class Tab2PageModule {} ================================================ FILE: src/app/tab2/tab2.page.html ================================================ Tab Two ================================================ FILE: src/app/tab2/tab2.page.scss ================================================ ================================================ FILE: src/app/tab2/tab2.page.spec.ts ================================================ import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { Tab2Page } from './tab2.page'; describe('Tab2Page', () => { let component: Tab2Page; let fixture: ComponentFixture; beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [Tab2Page], schemas: [CUSTOM_ELEMENTS_SCHEMA], }).compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(Tab2Page); component = fixture.componentInstance; fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); }); ================================================ FILE: src/app/tab2/tab2.page.ts ================================================ import { Component } from '@angular/core'; @Component({ selector: 'app-tab2', templateUrl: 'tab2.page.html', styleUrls: ['tab2.page.scss'] }) export class Tab2Page {} ================================================ FILE: src/app/tab3/tab3.module.ts ================================================ import { IonicModule } from '@ionic/angular'; import { RouterModule } from '@angular/router'; import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; import { Tab3Page } from './tab3.page'; @NgModule({ imports: [ IonicModule, CommonModule, FormsModule, RouterModule.forChild([{ path: '', component: Tab3Page }]) ], declarations: [Tab3Page] }) export class Tab3PageModule {} ================================================ FILE: src/app/tab3/tab3.page.html ================================================ Tab Three ================================================ FILE: src/app/tab3/tab3.page.scss ================================================ ================================================ FILE: src/app/tab3/tab3.page.spec.ts ================================================ import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { Tab3Page } from './tab3.page'; describe('Tab3Page', () => { let component: Tab3Page; let fixture: ComponentFixture; beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [Tab3Page], schemas: [CUSTOM_ELEMENTS_SCHEMA], }).compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(Tab3Page); component = fixture.componentInstance; fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); }); ================================================ FILE: src/app/tab3/tab3.page.ts ================================================ import { Component } from '@angular/core'; @Component({ selector: 'app-tab3', templateUrl: 'tab3.page.html', styleUrls: ['tab3.page.scss'] }) export class Tab3Page {} ================================================ FILE: src/app/tabs/tabs.module.ts ================================================ import { IonicModule } from '@ionic/angular'; import { RouterModule } from '@angular/router'; import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; import { TabsPageRoutingModule } from './tabs.router.module'; import { TabsPage } from './tabs.page'; @NgModule({ imports: [ IonicModule, CommonModule, FormsModule, TabsPageRoutingModule ], declarations: [TabsPage] }) export class TabsPageModule {} ================================================ FILE: src/app/tabs/tabs.page.html ================================================ Tab One Tab Two Tab Three ================================================ FILE: src/app/tabs/tabs.page.scss ================================================ ================================================ FILE: src/app/tabs/tabs.page.spec.ts ================================================ import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { TabsPage } from './tabs.page'; describe('TabsPage', () => { let component: TabsPage; let fixture: ComponentFixture; beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [TabsPage], schemas: [CUSTOM_ELEMENTS_SCHEMA], }).compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(TabsPage); component = fixture.componentInstance; fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); }); ================================================ FILE: src/app/tabs/tabs.page.ts ================================================ import { Component } from '@angular/core'; @Component({ selector: 'app-tabs', templateUrl: 'tabs.page.html', styleUrls: ['tabs.page.scss'] }) export class TabsPage {} ================================================ FILE: src/app/tabs/tabs.router.module.ts ================================================ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { TabsPage } from './tabs.page'; const routes: Routes = [ { path: 'tabs', component: TabsPage, children: [ { path: 'tab1', children: [ { path: '', loadChildren: '../tab1/tab1.module#Tab1PageModule' } ] }, { path: 'tab2', children: [ { path: '', loadChildren: '../tab2/tab2.module#Tab2PageModule' } ] }, { path: 'tab3', children: [ { path: '', loadChildren: '../tab3/tab3.module#Tab3PageModule' } ] }, { path: '', redirectTo: '/tabs/tab1', pathMatch: 'full' } ] }, { path: '', redirectTo: '/tabs/tab1', pathMatch: 'full' } ]; @NgModule({ imports: [RouterModule.forChild(routes)], exports: [RouterModule] }) export class TabsPageRoutingModule {} ================================================ FILE: src/environments/environment.prod.ts ================================================ export const environment = { production: true }; ================================================ FILE: src/environments/environment.ts ================================================ // The file contents for the current environment will overwrite these during build. // The build system defaults to the dev environment which uses `environment.ts`, but if you do // `ng build --env=prod` then `environment.prod.ts` will be used instead. // The list of which env maps to which file can be found in `.angular-cli.json`. export const environment = { production: false }; /* * In development mode, to ignore zone related error stack frames such as * `zone.run`, `zoneDelegate.invokeTask` for easier debugging, you can * import the following file, but please comment it out in production mode * because it will have performance impact when throw error */ // import 'zone.js/dist/zone-error'; // Included with Angular CLI. ================================================ FILE: src/global.scss ================================================ // http://ionicframework.com/docs/theming/ @import "~@ionic/angular/css/core.css"; @import "~@ionic/angular/css/normalize.css"; @import "~@ionic/angular/css/structure.css"; @import "~@ionic/angular/css/typography.css"; @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"; ================================================ FILE: src/index.html ================================================ Ionic App ================================================ FILE: src/karma.conf.js ================================================ // 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-istanbul-reporter'), require('@angular-devkit/build-angular/plugins/karma') ], client: { clearContext: false // leave Jasmine Spec Runner output visible in browser }, coverageIstanbulReporter: { dir: require('path').join(__dirname, '../coverage'), reports: ['html', 'lcovonly'], fixWebpackSourcePaths: true }, reporters: ['progress', 'kjhtml'], port: 9876, colors: true, logLevel: config.LOG_INFO, autoWatch: true, browsers: ['Chrome'], singleRun: false }); }; ================================================ FILE: src/main.ts ================================================ 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)) ================================================ FILE: src/polyfills.ts ================================================ /** * 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 */ /** IE9, IE10 and IE11 requires all of the following polyfills. **/ // import 'core-js/es6/symbol'; // import 'core-js/es6/object'; // import 'core-js/es6/function'; // import 'core-js/es6/parse-int'; // import 'core-js/es6/parse-float'; // import 'core-js/es6/number'; // import 'core-js/es6/math'; // import 'core-js/es6/string'; // import 'core-js/es6/date'; // import 'core-js/es6/regexp'; // import 'core-js/es6/map'; // import 'core-js/es6/weak-map'; // import 'core-js/es6/set'; /** * If your app need to indexed by Google Search, your app require polyfills 'core-js/es6/array' * Google bot use ES5. * FYI: Googlebot uses a renderer following the similar spec to Chrome 41. * https://developers.google.com/search/docs/guides/rendering **/ // import 'core-js/es6/array'; /** IE10 and IE11 requires the following for NgClass support on SVG elements */ // import 'classlist.js'; // Run `npm install --save classlist.js`. /** IE10 and IE11 requires the following for the Reflect API. */ // import 'core-js/es6/reflect'; /** Evergreen browsers require these. **/ // Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove. // import 'core-js/es7/reflect'; /** * 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 */ // (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__BLACK_LISTED_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; /*************************************************************************************************** * Zone JS is required by default for Angular itself. */ import 'zone.js/dist/zone'; // Included with Angular CLI. /*************************************************************************************************** * APPLICATION IMPORTS */ (window as any).global = window; (window as any).process = {}; (window as any).process.nextTick = setTimeout; ================================================ FILE: src/test.ts ================================================ // 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: any // 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) ================================================ FILE: src/theme/variables.scss ================================================ // 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: #0cd1e8; --ion-color-secondary-rgb: 12,209,232; --ion-color-secondary-contrast: #ffffff; --ion-color-secondary-contrast-rgb: 255,255,255; --ion-color-secondary-shade: #0bb8cc; --ion-color-secondary-tint: #24d6ea; /** tertiary **/ --ion-color-tertiary: #7044ff; --ion-color-tertiary-rgb: 112,68,255; --ion-color-tertiary-contrast: #ffffff; --ion-color-tertiary-contrast-rgb: 255,255,255; --ion-color-tertiary-shade: #633ce0; --ion-color-tertiary-tint: #7e57ff; /** success **/ --ion-color-success: #10dc60; --ion-color-success-rgb: 16,220,96; --ion-color-success-contrast: #ffffff; --ion-color-success-contrast-rgb: 255,255,255; --ion-color-success-shade: #0ec254; --ion-color-success-tint: #28e070; /** warning **/ --ion-color-warning: #ffce00; --ion-color-warning-rgb: 255,206,0; --ion-color-warning-contrast: #ffffff; --ion-color-warning-contrast-rgb: 255,255,255; --ion-color-warning-shade: #e0b500; --ion-color-warning-tint: #ffd31a; /** danger **/ --ion-color-danger: #f04141; --ion-color-danger-rgb: 245,61,61; --ion-color-danger-contrast: #ffffff; --ion-color-danger-contrast-rgb: 255,255,255; --ion-color-danger-shade: #d33939; --ion-color-danger-tint: #f25454; /** dark **/ --ion-color-dark: #222428; --ion-color-dark-rgb: 34,34,34; --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: #989aa2; --ion-color-medium-rgb: 152,154,162; --ion-color-medium-contrast: #ffffff; --ion-color-medium-contrast-rgb: 255,255,255; --ion-color-medium-shade: #86888f; --ion-color-medium-tint: #a2a4ab; /** light **/ --ion-color-light: #f4f5f8; --ion-color-light-rgb: 244,244,244; --ion-color-light-contrast: #000000; --ion-color-light-contrast-rgb: 0,0,0; --ion-color-light-shade: #d7d8da; --ion-color-light-tint: #f5f6f9; } ================================================ FILE: src/tsconfig.app.json ================================================ { "extends": "../tsconfig.json", "compilerOptions": { "outDir": "../out-tsc/app", "baseUrl": "./", "module": "es2015" }, "exclude": [ "test.ts", "**/*.spec.ts", "environments/*.ts" ] } ================================================ FILE: src/tsconfig.spec.json ================================================ { "extends": "../tsconfig.json", "compilerOptions": { "outDir": "../out-tsc/spec", "baseUrl": "./", "module": "commonjs", "types": [ "jasmine", "node" ] }, "files": [ "test.ts" ], "include": [ "polyfills.ts", "**/*.spec.ts", "**/*.d.ts" ] } ================================================ FILE: tsconfig.json ================================================ { "compileOnSave": false, "compilerOptions": { "outDir": "./dist/out-tsc", "sourceMap": true, "declaration": false, "moduleResolution": "node", "emitDecoratorMetadata": true, "experimentalDecorators": true, "target": "es5", "lib": [ "es2017", "dom" ] } } ================================================ FILE: tslint.json ================================================ { "rulesDirectory": [ "node_modules/codelyzer" ], "rules": { "arrow-return-shorthand": true, "callable-types": true, "class-name": true, "comment-format": [ true, "check-space" ], "curly": true, "deprecation": { "severity": "warn" }, "eofline": true, "forin": true, "import-spacing": true, "indent": [ true, "spaces" ], "interface-over-type-literal": true, "label-position": true, "max-line-length": [ true, 140 ], "member-access": false, "member-ordering": [ true, { "order": [ "static-field", "instance-field", "static-method", "instance-method" ] } ], "no-arg": true, "no-bitwise": true, "no-console": [ true, "debug", "info", "time", "timeEnd", "trace" ], "no-construct": true, "no-debugger": true, "no-duplicate-super": true, "no-empty": false, "no-empty-interface": true, "no-eval": true, "no-inferrable-types": [ true, "ignore-params" ], "no-misused-new": true, "no-non-null-assertion": true, "no-shadowed-variable": true, "no-string-literal": false, "no-string-throw": true, "no-switch-case-fall-through": true, "no-trailing-whitespace": true, "no-unnecessary-initializer": true, "no-unused-expression": true, "no-use-before-declare": true, "no-var-keyword": true, "object-literal-sort-keys": false, "one-line": [ true, "check-open-brace", "check-catch", "check-else", "check-whitespace" ], "prefer-const": true, "quotemark": [ true, "single" ], "radix": true, "semicolon": [ false, "always" ], "triple-equals": [ true, "allow-null-check" ], "typedef-whitespace": [ true, { "call-signature": "nospace", "index-signature": "nospace", "parameter": "nospace", "property-declaration": "nospace", "variable-declaration": "nospace" } ], "unified-signatures": true, "variable-name": false, "whitespace": [ true, "check-branch", "check-decl", "check-operator", "check-separator", "check-type" ], "directive-selector": [ true, "attribute", "app", "camelCase" ], "component-selector": [ true, "element", "app", "page", "kebab-case" ], "no-output-on-prefix": true, "use-input-property-decorator": true, "use-output-property-decorator": true, "use-host-property-decorator": true, "no-input-rename": true, "no-output-rename": true, "use-life-cycle-interface": true, "use-pipe-transform-interface": true, "directive-class-suffix": true } }