diff --git a/client/angular.json b/client/angular.json index dee0fe99b..3251ca8bf 100644 --- a/client/angular.json +++ b/client/angular.json @@ -22,8 +22,14 @@ "main": "src/main.ts", "polyfills": "src/polyfills.ts", "tsConfig": "src/tsconfig.app.json", - "assets": ["src/favicon.ico", "src/assets"], - "styles": ["src/styles.scss", "node_modules/material-design-icons/iconfont/material-icons.css"], + "assets": [ + "src/assets", + "src/manifest.json" + ], + "styles": [ + "src/styles.scss", + "node_modules/material-design-icons/iconfont/material-icons.css" + ], "scripts": [ "node_modules/tinymce/tinymce.min.js", "node_modules/tinymce/themes/modern/theme.js", @@ -58,7 +64,8 @@ "aot": true, "extractLicenses": true, "vendorChunk": false, - "buildOptimizer": true + "buildOptimizer": true, + "serviceWorker": true } } }, @@ -86,11 +93,16 @@ "polyfills": "src/polyfills.ts", "tsConfig": "src/tsconfig.spec.json", "karmaConfig": "src/karma.conf.js", - "styles": ["src/styles.scss"], + "styles": [ + "src/styles.scss" + ], "scripts": [ "node_modules/tinymce/tinymce.min.js" ], - "assets": ["src/favicon.ico", "src/assets"] + "assets": [ + "src/assets", + "src/manifest.json" + ] } }, "lint": { @@ -98,7 +110,9 @@ "options": { "tsConfig": "src/tsconfig.spec.json", "format": "stylish", - "exclude": ["**/node_modules/**"] + "exclude": [ + "**/node_modules/**" + ] } } } @@ -123,7 +137,9 @@ "builder": "@angular-devkit/build-angular:tslint", "options": { "tsConfig": "e2e/tsconfig.e2e.json", - "exclude": ["**/node_modules/**"] + "exclude": [ + "**/node_modules/**" + ] } } } diff --git a/client/ngsw-config.json b/client/ngsw-config.json new file mode 100644 index 000000000..818b90e44 --- /dev/null +++ b/client/ngsw-config.json @@ -0,0 +1,26 @@ +{ + "index": "/index.html", + "assetGroups": [ + { + "name": "app", + "installMode": "prefetch", + "resources": { + "files": [ + "/favicon.png", + "/index.html", + "/*.css", + "/*.js" + ] + } + }, { + "name": "assets", + "installMode": "lazy", + "updateMode": "prefetch", + "resources": { + "files": [ + "/assets/**" + ] + } + } + ] +} diff --git a/client/package.json b/client/package.json index 2bbc8168e..54cae7dc5 100644 --- a/client/package.json +++ b/client/package.json @@ -32,7 +32,9 @@ "@angular/material": "^7.1.0", "@angular/platform-browser": "^7.1.1", "@angular/platform-browser-dynamic": "^7.1.1", + "@angular/pwa": "^0.12.1", "@angular/router": "^7.1.1", + "@angular/service-worker": "^7.1.1", "@ngx-pwa/local-storage": "^7.2.0", "@ngx-translate/core": "^11.0.1", "@ngx-translate/http-loader": "^4.0.0", diff --git a/client/src/app/app.component.html b/client/src/app/app.component.html index 8b7e40f66..e7f953e2e 100644 --- a/client/src/app/app.component.html +++ b/client/src/app/app.component.html @@ -1,3 +1,3 @@
-
\ No newline at end of file + diff --git a/client/src/app/app.module.ts b/client/src/app/app.module.ts index b7c5bc91f..631b827e3 100644 --- a/client/src/app/app.module.ts +++ b/client/src/app/app.module.ts @@ -16,6 +16,10 @@ import { PruningTranslationLoader } from './core/pruning-loader'; import { LoginModule } from './site/login/login.module'; import { AppLoadService } from './core/services/app-load.service'; +// PWA +import { ServiceWorkerModule } from '@angular/service-worker'; +import { environment } from '../environments/environment'; + /** * For the translation module. Loads a Custom 'translation loader' and provides it as loader. * @param http Just the HttpClient to load stuff @@ -55,7 +59,8 @@ export function AppLoaderFactory(appLoadService: AppLoadService): () => Promise< AppRoutingModule, CoreModule, LoginModule, - PapaParseModule + PapaParseModule, + ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production }) ], providers: [{ provide: APP_INITIALIZER, useFactory: AppLoaderFactory, deps: [AppLoadService], multi: true }], bootstrap: [AppComponent] diff --git a/client/src/app/core/services/pwa.service.spec.ts b/client/src/app/core/services/pwa.service.spec.ts new file mode 100644 index 000000000..6faa381f6 --- /dev/null +++ b/client/src/app/core/services/pwa.service.spec.ts @@ -0,0 +1,17 @@ +import { TestBed } from '@angular/core/testing'; + +import { PwaService } from './pwa.service'; +import { E2EImportsModule } from 'e2e-imports.module'; + +describe('PwaService', () => { + beforeEach(() => + TestBed.configureTestingModule({ + imports: [E2EImportsModule] + }) + ); + + it('should be created', () => { + const service: PwaService = TestBed.get(PwaService); + expect(service).toBeTruthy(); + }); +}); diff --git a/client/src/app/core/services/pwa.service.ts b/client/src/app/core/services/pwa.service.ts new file mode 100644 index 000000000..0b5ffe0fc --- /dev/null +++ b/client/src/app/core/services/pwa.service.ts @@ -0,0 +1,25 @@ +import { Injectable } from '@angular/core'; +import { SwUpdate } from '@angular/service-worker'; + +/** + * Service for Progressive Web App options + */ +@Injectable({ + providedIn: 'root' +}) +export class PwaService { + public promptEvent; + + public constructor(swUpdate: SwUpdate) { + // check if an update is available + swUpdate.available.subscribe(event => { + // TODO: ask user if app should update now + window.location.reload(); + }); + + // install button + window.addEventListener('beforeinstallprompt', event => { + this.promptEvent = event; + }); + } +} diff --git a/client/src/app/core/services/viewport.service.ts b/client/src/app/core/services/viewport.service.ts index b26bda5bb..a00f7f719 100644 --- a/client/src/app/core/services/viewport.service.ts +++ b/client/src/app/core/services/viewport.service.ts @@ -48,7 +48,7 @@ export class ViewportService { */ public checkForChange(): void { this.breakpointObserver - .observe([Breakpoints.Small, Breakpoints.HandsetPortrait]) + .observe([Breakpoints.Handset, '(min-width: 600px) and (max-width: 899.99px)']) .subscribe((state: BreakpointState) => { if (state.matches) { this.isMobile = true; diff --git a/client/src/assets/icons/icon-128x128.png b/client/src/assets/icons/icon-128x128.png new file mode 100644 index 000000000..9f9241f0b Binary files /dev/null and b/client/src/assets/icons/icon-128x128.png differ diff --git a/client/src/assets/icons/icon-144x144.png b/client/src/assets/icons/icon-144x144.png new file mode 100644 index 000000000..4a5f8c163 Binary files /dev/null and b/client/src/assets/icons/icon-144x144.png differ diff --git a/client/src/assets/icons/icon-152x152.png b/client/src/assets/icons/icon-152x152.png new file mode 100644 index 000000000..34a1a8d64 Binary files /dev/null and b/client/src/assets/icons/icon-152x152.png differ diff --git a/client/src/assets/icons/icon-192x192.png b/client/src/assets/icons/icon-192x192.png new file mode 100644 index 000000000..9172e5dd2 Binary files /dev/null and b/client/src/assets/icons/icon-192x192.png differ diff --git a/client/src/assets/icons/icon-384x384.png b/client/src/assets/icons/icon-384x384.png new file mode 100644 index 000000000..e54e8d3ea Binary files /dev/null and b/client/src/assets/icons/icon-384x384.png differ diff --git a/client/src/assets/icons/icon-512x512.png b/client/src/assets/icons/icon-512x512.png new file mode 100644 index 000000000..51ee297df Binary files /dev/null and b/client/src/assets/icons/icon-512x512.png differ diff --git a/client/src/assets/icons/icon-72x72.png b/client/src/assets/icons/icon-72x72.png new file mode 100644 index 000000000..2814a3f30 Binary files /dev/null and b/client/src/assets/icons/icon-72x72.png differ diff --git a/client/src/assets/icons/icon-96x96.png b/client/src/assets/icons/icon-96x96.png new file mode 100644 index 000000000..d271025c4 Binary files /dev/null and b/client/src/assets/icons/icon-96x96.png differ diff --git a/client/src/index.html b/client/src/index.html index 2677afdef..ee05d1189 100644 --- a/client/src/index.html +++ b/client/src/index.html @@ -3,15 +3,18 @@ - OpenSlides 3 + OpenSlides + + + diff --git a/client/src/manifest.json b/client/src/manifest.json new file mode 100644 index 000000000..77bf39340 --- /dev/null +++ b/client/src/manifest.json @@ -0,0 +1,51 @@ +{ + "name": "OpenSlides", + "short_name": "OpenSlides", + "theme_color": "#317796", + "background_color": "#317796", + "display": "standalone", + "scope": "/", + "start_url": "/", + "icons": [ + { + "src": "/assets/icons/icon-72x72.png", + "sizes": "72x72", + "type": "image/png" + }, + { + "src": "/assets/icons/icon-96x96.png", + "sizes": "96x96", + "type": "image/png" + }, + { + "src": "/assets/icons/icon-128x128.png", + "sizes": "128x128", + "type": "image/png" + }, + { + "src": "/assets/icons/icon-144x144.png", + "sizes": "144x144", + "type": "image/png" + }, + { + "src": "/assets/icons/icon-152x152.png", + "sizes": "152x152", + "type": "image/png" + }, + { + "src": "/assets/icons/icon-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/assets/icons/icon-384x384.png", + "sizes": "384x384", + "type": "image/png" + }, + { + "src": "/assets/icons/icon-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ] +}