Version 1.5.0: Update check and dialog popups implemented
2
Makefile
|
@ -1,6 +1,8 @@
|
|||
install:
|
||||
ionic cordova plugin add cordova-plugin-local-notification
|
||||
npm install --save @ionic-native/local-notifications
|
||||
npm install --save @ionic-native/background-mode
|
||||
npm install --save @ionic-native/app-minimize
|
||||
npm install --save @ionic-native/core
|
||||
npm install --save @capacitor/core
|
||||
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
id="svg9367"
|
||||
version="1.1"
|
||||
viewBox="0 0 75.361905 75.361907"
|
||||
height="75.361908mm"
|
||||
width="75.361908mm"
|
||||
viewBox="0 0 74.938352 74.938354"
|
||||
height="74.938354mm"
|
||||
width="74.938354mm"
|
||||
sodipodi:docname="ic_launcher.svg"
|
||||
inkscape:version="1.0.2 (e86c870879, 2021-01-15)">
|
||||
<sodipodi:namedview
|
||||
|
@ -49,20 +49,19 @@
|
|||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<rect
|
||||
style="fill:#2d122d;fill-opacity:1;stroke-width:1.19397;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.858824"
|
||||
id="rect868"
|
||||
width="75.361908"
|
||||
height="75.361908"
|
||||
x="0"
|
||||
y="0" />
|
||||
<circle
|
||||
style="fill:#512051;fill-opacity:1;stroke-width:0.999478;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.858824"
|
||||
id="path830"
|
||||
r="37.469177"
|
||||
cy="37.469177"
|
||||
cx="37.469177" />
|
||||
<path
|
||||
id="rect882"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke-width:1.064;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.858824"
|
||||
d="m 22.941029,12.684805 -10.256227,10.256222 5.696296,5.69681 10.256741,-10.256222 z m 29.479854,0 -5.69681,5.69681 10.256224,10.256222 5.69681,-5.69681 z M 31.90534,18.248807 v 2.764689 l 2.888197,2.981213 h 2.886644 2.888197 l 2.888197,-2.981213 V 18.248807 H 37.680181 Z M 18.249839,31.904304 v 5.776908 5.775875 h 2.764175 l 2.981215,-2.888194 v -2.887681 -2.888195 l -2.981215,-2.888713 z m 36.09806,0 -2.98173,2.888713 v 2.888195 2.887681 l 2.98173,2.888194 h 2.764171 v -5.775875 -5.776908 z m -35.966801,14.819768 -5.696296,5.69681 10.256227,10.256222 5.69681,-5.696294 z m 38.599199,0 -10.256224,10.256738 5.69681,5.696294 10.256224,-10.256222 z m -22.18676,4.643644 -2.888197,2.981214 v 2.763655 h 5.774841 5.776394 V 54.34893 l -2.888197,-2.981214 h -2.888197 z"
|
||||
d="M 22.729251,12.473028 12.473024,22.72925 18.16932,28.42606 28.426061,18.169838 Z m 29.479854,0 -5.69681,5.69681 10.256224,10.256222 5.69681,-5.69681 z M 31.693562,18.03703 v 2.764689 l 2.888197,2.981213 h 2.886644 2.888197 l 2.888197,-2.981213 V 18.03703 H 37.468403 Z M 18.038061,31.692527 v 5.776908 5.775875 h 2.764175 l 2.981215,-2.888194 V 37.469435 34.58124 l -2.981215,-2.888713 z m 36.09806,0 -2.98173,2.888713 v 2.888195 2.887681 l 2.98173,2.888194 h 2.764171 v -5.775875 -5.776908 z m -35.966801,14.819768 -5.696296,5.69681 10.256227,10.256222 5.69681,-5.696294 z m 38.599199,0 -10.256224,10.256738 5.69681,5.696294 10.256224,-10.256222 z m -22.18676,4.643644 -2.888197,2.981214 v 2.763655 h 5.774841 5.776394 V 54.137153 L 40.3566,51.155939 h -2.888197 z"
|
||||
sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccccccccccccccccc" />
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
|
@ -1,67 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
id="svg9367"
|
||||
version="1.1"
|
||||
viewBox="0 0 74.938352 74.938354"
|
||||
height="74.938354mm"
|
||||
width="74.938354mm"
|
||||
sodipodi:docname="ic_launcher_round.svg"
|
||||
inkscape:version="1.0.2 (e86c870879, 2021-01-15)">
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1829"
|
||||
inkscape:window-height="1016"
|
||||
id="namedview1452"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.0134608"
|
||||
inkscape:cx="298.30195"
|
||||
inkscape:cy="201.14212"
|
||||
inkscape:window-x="91"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg9367"
|
||||
inkscape:document-rotation="0"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0" />
|
||||
<defs
|
||||
id="defs9361" />
|
||||
<metadata
|
||||
id="metadata9364">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<circle
|
||||
style="fill:#2d122d;fill-opacity:1;stroke-width:0.999478;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.858824"
|
||||
id="path830"
|
||||
r="37.469177"
|
||||
cy="37.469177"
|
||||
cx="37.469177" />
|
||||
<path
|
||||
id="rect882"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke-width:1.064;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.858824"
|
||||
d="M 22.729251,12.473028 12.473024,22.72925 18.16932,28.42606 28.426061,18.169838 Z m 29.479854,0 -5.69681,5.69681 10.256224,10.256222 5.69681,-5.69681 z M 31.693562,18.03703 v 2.764689 l 2.888197,2.981213 h 2.886644 2.888197 l 2.888197,-2.981213 V 18.03703 H 37.468403 Z M 18.038061,31.692527 v 5.776908 5.775875 h 2.764175 l 2.981215,-2.888194 V 37.469435 34.58124 l -2.981215,-2.888713 z m 36.09806,0 -2.98173,2.888713 v 2.888195 2.887681 l 2.98173,2.888194 h 2.764171 v -5.775875 -5.776908 z m -35.966801,14.819768 -5.696296,5.69681 10.256227,10.256222 5.69681,-5.696294 z m 38.599199,0 -10.256224,10.256738 5.69681,5.696294 10.256224,-10.256222 z m -22.18676,4.643644 -2.888197,2.981214 v 2.763655 h 5.774841 5.776394 V 54.137153 L 40.3566,51.155939 h -2.888197 z"
|
||||
sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccccccccccccccccc" />
|
||||
</svg>
|
Before Width: | Height: | Size: 2.8 KiB |
|
@ -1,5 +1,5 @@
|
|||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<widget id="io.ionic.starter" version="1.4.3" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
|
||||
<widget id="io.ionic.starter" version="1.5.0" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
|
||||
<name>METAsocket</name>
|
||||
<description>WowApp's awesome instant messenger for the whole Greifentanzgeschwader</description>
|
||||
<author email="webmaster@sabolli.de" href="https://sabolli.de/metasocket/">sabolli</author>
|
||||
|
|
|
@ -19,8 +19,6 @@
|
|||
"@ionic-native/core": "^5.31.1",
|
||||
"@ionic-native/foreground-service": "^5.31.1",
|
||||
"@ionic-native/local-notifications": "^5.31.1",
|
||||
"@ionic-native/network": "^5.31.1",
|
||||
"@ionic-native/power-management": "^5.31.1",
|
||||
"@ionic/angular": "^5.5.2",
|
||||
"rxjs": "~6.6.0",
|
||||
"tslib": "^2.0.0",
|
||||
|
@ -36,6 +34,7 @@
|
|||
"@types/jasmine": "~3.6.0",
|
||||
"@types/jasminewd2": "~2.0.3",
|
||||
"@types/node": "^12.11.1",
|
||||
"co.mylonas.cordova.applicationstate": "github:leomylonas/cordova-plugin-applicationstate",
|
||||
"codelyzer": "^6.0.0",
|
||||
"cordova-android": "^9.0.0",
|
||||
"cordova-plugin-app-exit": "0.0.2",
|
||||
|
@ -47,8 +46,6 @@
|
|||
"cordova-plugin-ionic-keyboard": "^2.2.0",
|
||||
"cordova-plugin-ionic-webview": "^4.2.1",
|
||||
"cordova-plugin-local-notification": "^0.9.0-beta.2",
|
||||
"cordova-plugin-network-information": "^2.0.2",
|
||||
"cordova-plugin-powermanagement-orig": "^1.1.2",
|
||||
"cordova-plugin-splashscreen": "^5.0.2",
|
||||
"cordova-plugin-statusbar": "^2.4.2",
|
||||
"cordova-plugin-whitelist": "^1.3.3",
|
||||
|
@ -1777,30 +1774,6 @@
|
|||
"@types/cordova": "^0.0.34"
|
||||
}
|
||||
},
|
||||
"node_modules/@ionic-native/network": {
|
||||
"version": "5.31.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic-native/network/-/network-5.31.1.tgz",
|
||||
"integrity": "sha512-dSN7jaiXXgm8kVcvxcD39wWPFg2NujWTrEnj9Fq7Fx2aGKkxPkocNsxoy02aFVyBp1LQZvp+uiDNmVIVRjrA7A==",
|
||||
"dependencies": {
|
||||
"@types/cordova": "latest"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ionic-native/core": "^5.1.0",
|
||||
"rxjs": "^5.5.0 || ^6.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@ionic-native/power-management": {
|
||||
"version": "5.31.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic-native/power-management/-/power-management-5.31.1.tgz",
|
||||
"integrity": "sha512-SJiTOMMkEEJ7B/MNztCjnwCKEF416hRDLquSeK6zJbRhPzMsWLr7Cb+BzjvwV5pfo05ilfzV08yB95IBdRteUg==",
|
||||
"dependencies": {
|
||||
"@types/cordova": "latest"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ionic-native/core": "^5.1.0",
|
||||
"rxjs": "^5.5.0 || ^6.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@ionic/angular": {
|
||||
"version": "5.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/angular/-/angular-5.5.5.tgz",
|
||||
|
@ -3962,6 +3935,18 @@
|
|||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/co.mylonas.cordova.applicationstate": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "git+ssh://git@github.com/leomylonas/cordova-plugin-applicationstate.git#1ead7d5045eed494bd1bb8dabde461208634780b",
|
||||
"dev": true,
|
||||
"engines": [
|
||||
{
|
||||
"name": "cordova",
|
||||
"version": ">=3.0.0"
|
||||
}
|
||||
],
|
||||
"license": "CC-BY-4.0"
|
||||
},
|
||||
"node_modules/coa": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz",
|
||||
|
@ -4891,25 +4876,6 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"node_modules/cordova-plugin-network-information": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/cordova-plugin-network-information/-/cordova-plugin-network-information-2.0.2.tgz",
|
||||
"integrity": "sha512-NwO3qDBNL/vJxUxBTPNOA1HvkDf9eTeGH8JSZiwy1jq2W2mJKQEDBwqWkaEQS19Yd/MQTiw0cykxg5D7u4J6cQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"cordovaDependencies": {
|
||||
"3.0.0": {
|
||||
"cordova": ">100"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/cordova-plugin-powermanagement-orig": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/cordova-plugin-powermanagement-orig/-/cordova-plugin-powermanagement-orig-1.1.2.tgz",
|
||||
"integrity": "sha1-hVuljKvnndWxECXkWG/ywe0YnOA=",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/cordova-plugin-splashscreen": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/cordova-plugin-splashscreen/-/cordova-plugin-splashscreen-5.0.2.tgz",
|
||||
|
@ -20432,22 +20398,6 @@
|
|||
"@types/cordova": "^0.0.34"
|
||||
}
|
||||
},
|
||||
"@ionic-native/network": {
|
||||
"version": "5.31.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic-native/network/-/network-5.31.1.tgz",
|
||||
"integrity": "sha512-dSN7jaiXXgm8kVcvxcD39wWPFg2NujWTrEnj9Fq7Fx2aGKkxPkocNsxoy02aFVyBp1LQZvp+uiDNmVIVRjrA7A==",
|
||||
"requires": {
|
||||
"@types/cordova": "latest"
|
||||
}
|
||||
},
|
||||
"@ionic-native/power-management": {
|
||||
"version": "5.31.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic-native/power-management/-/power-management-5.31.1.tgz",
|
||||
"integrity": "sha512-SJiTOMMkEEJ7B/MNztCjnwCKEF416hRDLquSeK6zJbRhPzMsWLr7Cb+BzjvwV5pfo05ilfzV08yB95IBdRteUg==",
|
||||
"requires": {
|
||||
"@types/cordova": "latest"
|
||||
}
|
||||
},
|
||||
"@ionic/angular": {
|
||||
"version": "5.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/angular/-/angular-5.5.5.tgz",
|
||||
|
@ -22330,6 +22280,11 @@
|
|||
"shallow-clone": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"co.mylonas.cordova.applicationstate": {
|
||||
"version": "git+ssh://git@github.com/leomylonas/cordova-plugin-applicationstate.git#1ead7d5045eed494bd1bb8dabde461208634780b",
|
||||
"dev": true,
|
||||
"from": "co.mylonas.cordova.applicationstate@github:leomylonas/cordova-plugin-applicationstate"
|
||||
},
|
||||
"coa": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz",
|
||||
|
@ -23070,18 +23025,6 @@
|
|||
"integrity": "sha512-63n77K1pt8dnbWnNR8QWETi9Glezi1bvNHvHWmGNIOv0xCb0phZnm+Ku49BQ+omwe8Z5voMvrA4I03SYPpv38w==",
|
||||
"dev": true
|
||||
},
|
||||
"cordova-plugin-network-information": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/cordova-plugin-network-information/-/cordova-plugin-network-information-2.0.2.tgz",
|
||||
"integrity": "sha512-NwO3qDBNL/vJxUxBTPNOA1HvkDf9eTeGH8JSZiwy1jq2W2mJKQEDBwqWkaEQS19Yd/MQTiw0cykxg5D7u4J6cQ==",
|
||||
"dev": true
|
||||
},
|
||||
"cordova-plugin-powermanagement-orig": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/cordova-plugin-powermanagement-orig/-/cordova-plugin-powermanagement-orig-1.1.2.tgz",
|
||||
"integrity": "sha1-hVuljKvnndWxECXkWG/ywe0YnOA=",
|
||||
"dev": true
|
||||
},
|
||||
"cordova-plugin-splashscreen": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/cordova-plugin-splashscreen/-/cordova-plugin-splashscreen-5.0.2.tgz",
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
"@types/jasmine": "~3.6.0",
|
||||
"@types/jasminewd2": "~2.0.3",
|
||||
"@types/node": "^12.11.1",
|
||||
"co.mylonas.cordova.applicationstate": "github:leomylonas/cordova-plugin-applicationstate",
|
||||
"codelyzer": "^6.0.0",
|
||||
"cordova-android": "^9.0.0",
|
||||
"cordova-plugin-app-exit": "0.0.2",
|
||||
|
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 7.3 KiB |
|
@ -5,6 +5,7 @@ import {Token} from './token';
|
|||
import {Setting} from './setting';
|
||||
import {ChatMessage} from './chat.message';
|
||||
import {ChatTokenResponse} from './chat.token';
|
||||
import {VersionInfo} from './version.info';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
|
@ -15,15 +16,6 @@ export class ApiService {
|
|||
constructor(private client: HttpClient) {
|
||||
}
|
||||
|
||||
storeData(key: string, value: string): void
|
||||
{
|
||||
sessionStorage.setItem(key, value);
|
||||
}
|
||||
|
||||
getFromStorage(key: string): string {
|
||||
return sessionStorage.getItem(key);
|
||||
}
|
||||
|
||||
getAuthToken(username: string, password: string): Observable<Token> {
|
||||
return this.client.post<Token>(Setting.URL + '/token', {username, password});
|
||||
}
|
||||
|
@ -56,4 +48,9 @@ export class ApiService {
|
|||
{headers: {Authorization: 'Bearer ' + token}}
|
||||
);
|
||||
}
|
||||
|
||||
getCurrentVersion(): Observable<VersionInfo>
|
||||
{
|
||||
return this.client.get<VersionInfo>(Setting.URL + '/metasocket/info');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { ApiService } from './api.service';
|
||||
import AppStorage from './app.storage';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
|
@ -13,7 +14,7 @@ export class AppComponent {
|
|||
|
||||
public constructor(private apiService: ApiService)
|
||||
{
|
||||
AppComponent.token = this.apiService.getFromStorage('token');
|
||||
AppComponent.token = AppStorage.getToken();
|
||||
}
|
||||
|
||||
public getToken(): string
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
export default class AppConfig
|
||||
{
|
||||
public static readonly VERSION: string = '1.5.0';
|
||||
}
|
|
@ -1,14 +1,11 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { RouteReuseStrategy } from '@angular/router';
|
||||
|
||||
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
|
||||
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import {NgModule} from '@angular/core';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {RouteReuseStrategy} from '@angular/router';
|
||||
import {IonicModule, IonicRouteStrategy} from '@ionic/angular';
|
||||
import {FormsModule} from '@angular/forms';
|
||||
import {HttpClientModule} from '@angular/common/http';
|
||||
import {AppComponent} from './app.component';
|
||||
import {AppRoutingModule} from './app-routing.module';
|
||||
import {ChatComponent} from './chat/chat.component';
|
||||
import {LoginComponent} from './login/login.component';
|
||||
import {TopbarComponent} from './topbar/topbar.component';
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
import {ApiService} from './api.service';
|
||||
|
||||
export default class AppStorage
|
||||
{
|
||||
private static readonly LAST_VERSION_CHECK: string = 'lastVersionCheck';
|
||||
private static readonly IS_UPDATE_NOTIFICATION_DESIRED: string = 'isUpdateNotificationDesired';
|
||||
private static readonly TOKEN: string = 'token';
|
||||
private static readonly USER_ID: string = 'userId';
|
||||
private static readonly CHAT_TOKEN: string = 'chatToken';
|
||||
private static readonly LAST_LOGIN_NAME: string = 'lastLoginName';
|
||||
|
||||
public static getChatToken(): string
|
||||
{
|
||||
return sessionStorage.getItem(this.CHAT_TOKEN);
|
||||
}
|
||||
|
||||
public static getLastLoginName(): string
|
||||
{
|
||||
return localStorage.getItem(this.LAST_LOGIN_NAME);
|
||||
}
|
||||
|
||||
public static getLastVersionCheck(): number
|
||||
{
|
||||
const lastCheck = localStorage.getItem(this.LAST_VERSION_CHECK);
|
||||
|
||||
return lastCheck === null ? null : Number(lastCheck);
|
||||
}
|
||||
|
||||
public static getToken(): string
|
||||
{
|
||||
return sessionStorage.getItem(this.TOKEN);
|
||||
}
|
||||
|
||||
public static getUserId(): number
|
||||
{
|
||||
const userId = sessionStorage.getItem(this.USER_ID);
|
||||
|
||||
return userId === null ? null : Number(userId);
|
||||
}
|
||||
|
||||
public static isUpdateNotificationDesired(): boolean
|
||||
{
|
||||
const isDesired = localStorage.getItem(this.IS_UPDATE_NOTIFICATION_DESIRED);
|
||||
|
||||
return isDesired === null ? true : isDesired === 'true';
|
||||
}
|
||||
|
||||
public static setChatToken(chatToken: string): void
|
||||
{
|
||||
sessionStorage.setItem(this.CHAT_TOKEN, chatToken);
|
||||
}
|
||||
|
||||
public static setIsUpdateNotificationDesired(isDesired: boolean): void
|
||||
{
|
||||
localStorage.setItem(this.IS_UPDATE_NOTIFICATION_DESIRED, isDesired.toString());
|
||||
}
|
||||
|
||||
public static setLastLoginName(loginName: string): void
|
||||
{
|
||||
localStorage.setItem(this.LAST_LOGIN_NAME, loginName);
|
||||
}
|
||||
|
||||
public static setLastVersionCheck(versionCheck: number): void
|
||||
{
|
||||
localStorage.setItem(this.LAST_VERSION_CHECK, versionCheck.toString());
|
||||
}
|
||||
|
||||
public static setToken(token: string): void
|
||||
{
|
||||
sessionStorage.setItem(this.TOKEN, token);
|
||||
}
|
||||
|
||||
public static setUserId(userId: number): void
|
||||
{
|
||||
sessionStorage.setItem(this.USER_ID, userId.toString());
|
||||
}
|
||||
}
|
|
@ -9,6 +9,12 @@ import {LocalNotifications} from '@ionic-native/local-notifications/ngx';
|
|||
import {BackgroundMode} from '@ionic-native/background-mode/ngx';
|
||||
import {AppComponent} from '../app.component';
|
||||
import {Platform} from '@ionic/angular';
|
||||
import {VersionInfo} from '../version.info';
|
||||
import FullscreenError from '../fullscreen.error';
|
||||
import FullscreenNotification from '../fullscreen.notification';
|
||||
import AppConfig from '../app.config';
|
||||
import FullscreenDialog from '../fullscreen.dialog';
|
||||
import AppStorage from '../app.storage';
|
||||
|
||||
const {App} = Plugins;
|
||||
|
||||
|
@ -44,11 +50,12 @@ export class ChatComponent implements OnInit, AfterViewInit, AfterViewChecked, W
|
|||
private backgroundMode: BackgroundMode,
|
||||
private platform: Platform
|
||||
) {
|
||||
this.userToken = this.apiService.getFromStorage('token');
|
||||
this.userId = Number(this.apiService.getFromStorage('userId'));
|
||||
this.userToken = AppStorage.getToken();
|
||||
this.userId = AppStorage.getUserId();
|
||||
this.url = Setting.URL;
|
||||
this.websocketService.setListener(this);
|
||||
this.websocketService.initializeSocket(this.apiService.getFromStorage('chatToken'));
|
||||
this.websocketService.initializeSocket(AppStorage.getChatToken());
|
||||
this.backgroundMode.enable();
|
||||
this.backgroundMode.disableBatteryOptimizations();
|
||||
this.backgroundMode.disableWebViewOptimizations();
|
||||
}
|
||||
|
@ -94,7 +101,7 @@ export class ChatComponent implements OnInit, AfterViewInit, AfterViewChecked, W
|
|||
}
|
||||
).catch(
|
||||
(error) => {
|
||||
window.alert('Fehler ' + error.status + ': Verbindung zur Web-API gescheitert!');
|
||||
const notification = new FullscreenError('Verbindung zur Web-API gescheitert!\n\nStatus-Code: ' + error.status);
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -104,9 +111,9 @@ export class ChatComponent implements OnInit, AfterViewInit, AfterViewChecked, W
|
|||
|
||||
this.platform.backButton.subscribe(
|
||||
() => {
|
||||
if (window.confirm('Möchtest du wirklich ausloggen?')) {
|
||||
this.onLogout();
|
||||
}
|
||||
const question = new FullscreenDialog('App beenden', 'Möchtest du wirklich ausloggen?');
|
||||
question.addButton('Ja', () => {this.onLogout(); });
|
||||
question.addButton('Nein');
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -115,6 +122,13 @@ export class ChatComponent implements OnInit, AfterViewInit, AfterViewChecked, W
|
|||
this.websocketService.sendKeepAliveMessage();
|
||||
}, 1000 * 60 // every minute
|
||||
);
|
||||
|
||||
setTimeout(
|
||||
() => {
|
||||
this.checkVersion();
|
||||
},
|
||||
5000
|
||||
);
|
||||
}
|
||||
|
||||
onScroll(): void {
|
||||
|
@ -161,7 +175,7 @@ export class ChatComponent implements OnInit, AfterViewInit, AfterViewChecked, W
|
|||
}
|
||||
|
||||
onLogout() {
|
||||
this.apiService.storeData('token', null);
|
||||
AppStorage.setToken(null);
|
||||
this.websocketService.destroy();
|
||||
|
||||
AppComponent.token = null;
|
||||
|
@ -173,7 +187,7 @@ export class ChatComponent implements OnInit, AfterViewInit, AfterViewChecked, W
|
|||
this.messages.push(message);
|
||||
this.messageOffset++;
|
||||
|
||||
if (this.hasFocus || message.userId === this.userId) {
|
||||
if (!this.backgroundMode.isActive() || message.userId === this.userId) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -263,6 +277,46 @@ export class ChatComponent implements OnInit, AfterViewInit, AfterViewChecked, W
|
|||
);
|
||||
}
|
||||
|
||||
private checkVersion(): void
|
||||
{
|
||||
const lastChecked = AppStorage.getLastVersionCheck();
|
||||
const today = new Date();
|
||||
|
||||
if (lastChecked !== null) {
|
||||
const dateLastChecked = new Date(lastChecked);
|
||||
|
||||
if (dateLastChecked.toDateString() === today.toDateString()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
AppStorage.setLastVersionCheck(today.getTime());
|
||||
|
||||
this.apiService.getCurrentVersion().toPromise()
|
||||
.then(
|
||||
(versionInfo: VersionInfo) => {
|
||||
const isUpdateNotificationDesired = AppStorage.isUpdateNotificationDesired();
|
||||
|
||||
if (isUpdateNotificationDesired && AppConfig.VERSION < versionInfo.currentVersionAndroid) {
|
||||
const notification = new FullscreenNotification('Neue Version', 'Eine neue Version von METAsocket ist verfügbar.');
|
||||
const label = document.createElement('label');
|
||||
const checkbox = document.createElement('input');
|
||||
const text = document.createElement('span');
|
||||
text.innerText = ' Nerv mich nie wieder damit';
|
||||
checkbox.type = 'checkbox';
|
||||
label.appendChild(checkbox);
|
||||
label.appendChild(text);
|
||||
label.onclick = () => {
|
||||
AppStorage.setIsUpdateNotificationDesired(!checkbox.checked);
|
||||
};
|
||||
|
||||
notification.addExtendedInputElement(label);
|
||||
notification.addUrlButton('Runterladen', 'https://sabolli.de/wow/metasocket/download/android');
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private hasChatMessage(message: ChatMessage): boolean
|
||||
{
|
||||
for (const messageStored of this.messages) {
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
export default class FullscreenDialog
|
||||
{
|
||||
protected rootElement: HTMLDivElement;
|
||||
protected window: HTMLDivElement;
|
||||
protected title: HTMLHeadElement;
|
||||
protected message: HTMLParagraphElement;
|
||||
protected extendedInputArea: HTMLDivElement;
|
||||
protected buttonArea: HTMLDivElement;
|
||||
|
||||
public constructor(title: string, message: string) {
|
||||
this.rootElement = document.createElement('div');
|
||||
this.rootElement.classList.add('notification');
|
||||
|
||||
this.window = document.createElement('div');
|
||||
this.window.classList.add('notification-window');
|
||||
this.rootElement.appendChild(this.window);
|
||||
|
||||
this.title = document.createElement('h1');
|
||||
this.title.classList.add('notification-headline');
|
||||
this.title.innerText = title;
|
||||
this.window.appendChild(this.title);
|
||||
|
||||
this.message = document.createElement('p');
|
||||
this.message.innerText = message;
|
||||
this.window.appendChild(this.message);
|
||||
|
||||
this.extendedInputArea = document.createElement('div');
|
||||
this.extendedInputArea.classList.add('notification-extended-input-area');
|
||||
this.window.appendChild(this.extendedInputArea);
|
||||
|
||||
this.buttonArea = document.createElement('div');
|
||||
this.buttonArea.classList.add('notification-button-area');
|
||||
this.window.appendChild(this.buttonArea);
|
||||
|
||||
document.body.appendChild(this.rootElement);
|
||||
}
|
||||
|
||||
public addButton(title: string, callback: () => void = () => {}): void
|
||||
{
|
||||
const button = document.createElement('button');
|
||||
|
||||
button.classList.add('notification-button');
|
||||
button.innerText = title;
|
||||
button.onclick = () => {
|
||||
callback();
|
||||
this.close();
|
||||
};
|
||||
|
||||
this.buttonArea.appendChild(button);
|
||||
}
|
||||
|
||||
public addUrlButton(title: string, url: string): void
|
||||
{
|
||||
const button = document.createElement('a');
|
||||
|
||||
button.classList.add('notification-button');
|
||||
button.innerText = title;
|
||||
button.href = url;
|
||||
button.onclick = () => {this.close(); };
|
||||
|
||||
this.buttonArea.appendChild(button);
|
||||
}
|
||||
|
||||
public addExtendedInputElement(element: HTMLElement): void
|
||||
{
|
||||
this.extendedInputArea.appendChild(element);
|
||||
}
|
||||
|
||||
public close(): void
|
||||
{
|
||||
this.rootElement.remove();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
import FullscreenNotification from './fullscreen.notification';
|
||||
|
||||
export default class FullscreenError extends FullscreenNotification
|
||||
{
|
||||
public constructor(message: string) {
|
||||
super('Fehler', message);
|
||||
this.window.classList.add('notification-window-error');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import FullscreenDialog from './fullscreen.dialog';
|
||||
|
||||
export default class FullscreenNotification extends FullscreenDialog
|
||||
{
|
||||
public constructor(title: string, message: string) {
|
||||
super(title, message);
|
||||
|
||||
this.addButton('OK');
|
||||
}
|
||||
}
|
|
@ -6,15 +6,17 @@
|
|||
<form>
|
||||
<label>
|
||||
Username
|
||||
<input name="username" [(ngModel)] = "username" required>
|
||||
<input #loginName name="username" [(ngModel)] = "username" required autofocus>
|
||||
</label>
|
||||
|
||||
<label>
|
||||
Password
|
||||
<input type="password" name="password" [(ngModel)] = "password" required>
|
||||
<input #loginPassword type="password" name="password" [(ngModel)] = "password" required>
|
||||
</label>
|
||||
|
||||
<input type="submit" (click)="login($event)" value="Anmelden">
|
||||
</form>
|
||||
|
||||
<p class="app-version">{{version}}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import {Component, ElementRef, OnInit, ViewChild} from '@angular/core';
|
||||
import { ApiService } from '../api.service';
|
||||
import {Platform} from '@ionic/angular';
|
||||
import {AppMinimize} from '@ionic-native/app-minimize/ngx';
|
||||
import AppStorage from '../app.storage';
|
||||
import AppConfig from '../app.config';
|
||||
|
||||
@Component({
|
||||
selector: 'app-login',
|
||||
|
@ -12,8 +14,14 @@ export class LoginComponent implements OnInit {
|
|||
username = '';
|
||||
password = '';
|
||||
error: string = null;
|
||||
version: string;
|
||||
|
||||
constructor(private apiService: ApiService, private platform: Platform, private appMinimize: AppMinimize) { }
|
||||
@ViewChild('loginName') usernameElement: ElementRef;
|
||||
@ViewChild('loginPassword') passwordElement: ElementRef;
|
||||
|
||||
constructor(private apiService: ApiService, private platform: Platform, private appMinimize: AppMinimize) {
|
||||
this.version = AppConfig.VERSION;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.platform.backButton.subscribe(
|
||||
|
@ -21,6 +29,12 @@ export class LoginComponent implements OnInit {
|
|||
this.appMinimize.minimize();
|
||||
}
|
||||
);
|
||||
|
||||
const lastUsername = AppStorage.getLastLoginName() ?? '';
|
||||
|
||||
if (lastUsername.length > 0) {
|
||||
this.username = lastUsername;
|
||||
}
|
||||
}
|
||||
|
||||
login(event): void
|
||||
|
@ -31,19 +45,20 @@ export class LoginComponent implements OnInit {
|
|||
this.apiService.getAuthToken(this.username, this.password).toPromise()
|
||||
.then(
|
||||
(response) => {
|
||||
this.apiService.storeData('token', response.token);
|
||||
AppStorage.setToken(response.token);
|
||||
|
||||
this.apiService.getChatToken(response.token).toPromise()
|
||||
.then(
|
||||
(chatTokenResponse) => {
|
||||
this.apiService.storeData('chatToken', chatTokenResponse.token);
|
||||
this.apiService.storeData('userId', chatTokenResponse.userId.toString());
|
||||
AppStorage.setChatToken(chatTokenResponse.token);
|
||||
AppStorage.setUserId(chatTokenResponse.userId);
|
||||
AppStorage.setLastLoginName(this.username);
|
||||
|
||||
window.location.reload();
|
||||
}
|
||||
).catch(
|
||||
(error) => {
|
||||
this.apiService.storeData('token', null);
|
||||
AppStorage.setToken(null);
|
||||
this.error = error.name + ': ' + error.message;
|
||||
|
||||
event.target.disabled = false;
|
||||
|
@ -53,7 +68,7 @@ export class LoginComponent implements OnInit {
|
|||
}
|
||||
).catch (
|
||||
(error) => {
|
||||
this.apiService.storeData('token', null);
|
||||
AppStorage.setToken(null);
|
||||
|
||||
switch (error.status) {
|
||||
case 401:
|
||||
|
@ -76,7 +91,7 @@ export class LoginComponent implements OnInit {
|
|||
this.error = 'Fehler: Etwas unfassbar grauenhaftes ist passiert!';
|
||||
}
|
||||
|
||||
console.log(error);
|
||||
this.password = '';
|
||||
|
||||
event.target.disabled = false;
|
||||
event.target.style.visibility = 'visible';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import {Component, Input, OnInit} from '@angular/core';
|
||||
import {ApiService} from '../api.service';
|
||||
import {AppComponent} from '../app.component';
|
||||
import {ForegroundService} from '@ionic-native/foreground-service/ngx';
|
||||
import AppStorage from '../app.storage';
|
||||
|
||||
@Component({
|
||||
selector: 'app-topbar',
|
||||
|
@ -11,21 +11,20 @@ import {ForegroundService} from '@ionic-native/foreground-service/ngx';
|
|||
export class TopbarComponent implements OnInit {
|
||||
@Input() token: string;
|
||||
|
||||
constructor(private apiService: ApiService, private foregroundService: ForegroundService) {
|
||||
constructor(private apiService: ApiService) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
logout(): void {
|
||||
this.apiService.deleteAuthToken(this.apiService.getFromStorage('token')).toPromise()
|
||||
this.apiService.deleteAuthToken(AppStorage.getToken()).toPromise()
|
||||
.then()
|
||||
.catch(
|
||||
(error) => {console.log(error); }
|
||||
);
|
||||
this.apiService.storeData('token', null);
|
||||
this.foregroundService.stop();
|
||||
|
||||
AppStorage.setToken(null);
|
||||
AppComponent.token = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
export interface VersionInfo
|
||||
{
|
||||
success: boolean;
|
||||
currentVersionAndroid: string;
|
||||
}
|
|
@ -3,6 +3,15 @@
|
|||
to { top: 0}
|
||||
}
|
||||
|
||||
@keyframes fullscreen-notification-entrance {
|
||||
from { background-color: rgba(0, 0, 0, 0) }
|
||||
to { background-color: rgba(0, 0, 0, 0.5) }
|
||||
}
|
||||
|
||||
@keyframes fullscreen-notification-window-entrance {
|
||||
from { transform: scale(0)}
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
font-family: sans-serif;
|
||||
|
@ -158,6 +167,14 @@ html, body {
|
|||
|
||||
#login-form input[type=submit] {
|
||||
margin-top: 50px;
|
||||
background-color: white;
|
||||
color: #2a2a2a;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.app-version {
|
||||
color: white;
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
|
@ -247,6 +264,64 @@ html, body {
|
|||
background-color: #550000;
|
||||
}
|
||||
|
||||
.notification {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: white;
|
||||
animation-name: fullscreen-notification-entrance;
|
||||
animation-duration: 0.5s;
|
||||
}
|
||||
|
||||
.notification-window {
|
||||
background-color: #251a25;
|
||||
padding: 20px;
|
||||
margin: 20px;
|
||||
box-shadow: 0 0 20px black;
|
||||
animation-name: fullscreen-notification-window-entrance;
|
||||
animation-duration: 0.5s;
|
||||
}
|
||||
|
||||
.notification-window-error {
|
||||
background-color: #bb0000;
|
||||
}
|
||||
|
||||
.notification-button-area {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.notification-button {
|
||||
background-color: white;
|
||||
color: #251a25;
|
||||
font-weight: bold;
|
||||
padding: 5px 20px;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
border: solid 1px white !important;
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
a.notification-button {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.notification-headline {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
@media only screen and (max-height: 500px) {
|
||||
#login {
|
||||
position: static;
|
||||
|
|