232 lines
6.3 KiB
TypeScript
232 lines
6.3 KiB
TypeScript
import {Plugins, AppState} from '@capacitor/core';
|
|
import {AfterViewChecked, AfterViewInit, Component, ElementRef, OnInit, ViewChild} from '@angular/core';
|
|
import {ChatMessage} from '../chat.message';
|
|
import {Setting} from '../setting';
|
|
import {ApiService} from '../api.service';
|
|
import {WebsocketListener} from '../websocket.listener';
|
|
import {WebsocketService} from '../websocket.service';
|
|
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';
|
|
|
|
const {App} = Plugins;
|
|
|
|
@Component({
|
|
selector: 'app-chat',
|
|
templateUrl: './chat.component.html',
|
|
styleUrls: ['./chat.component.scss'],
|
|
})
|
|
export class ChatComponent implements OnInit, AfterViewInit, AfterViewChecked, WebsocketListener {
|
|
messages: ChatMessage[] = [];
|
|
userToken: string;
|
|
userId: number;
|
|
url: string;
|
|
|
|
@ViewChild('chatPostArea') chatPostArea: ElementRef;
|
|
@ViewChild('errorMessage') errorMessage: ElementRef;
|
|
chatText: string;
|
|
|
|
private oldScrollHeight = 0;
|
|
private messageOffset = 0;
|
|
private messageLimit = 10;
|
|
private hasBeenReloaded = false;
|
|
private hasFocus = true;
|
|
private isReconnection = false;
|
|
|
|
public constructor(
|
|
private apiService: ApiService,
|
|
private websocketService: WebsocketService,
|
|
private localNotifications: LocalNotifications,
|
|
private backgroundMode: BackgroundMode,
|
|
private platform: Platform
|
|
) {
|
|
this.userToken = this.apiService.getFromStorage('token');
|
|
this.userId = Number(this.apiService.getFromStorage('userId'));
|
|
this.url = Setting.URL;
|
|
this.websocketService.setListener(this);
|
|
this.websocketService.initializeSocket(this.apiService.getFromStorage('chatToken'));
|
|
this.backgroundMode.disableBatteryOptimizations();
|
|
this.backgroundMode.disableWebViewOptimizations();
|
|
}
|
|
|
|
ngAfterViewInit(): void {
|
|
this.chatPostArea.nativeElement.scroll(0, this.chatPostArea.nativeElement.scrollHeight);
|
|
}
|
|
|
|
ngAfterViewChecked(): void {
|
|
if (this.oldScrollHeight !== this.chatPostArea.nativeElement.scrollHeight) {
|
|
const scrollTop = this.chatPostArea.nativeElement.scrollTop;
|
|
const clientHeight = this.chatPostArea.nativeElement.clientHeight;
|
|
|
|
if (this.hasBeenReloaded) {
|
|
this.chatPostArea.nativeElement.scroll(0, this.chatPostArea.nativeElement.scrollHeight - this.oldScrollHeight);
|
|
this.hasBeenReloaded = false;
|
|
} else if (scrollTop + clientHeight > this.oldScrollHeight - 10) {
|
|
this.chatPostArea.nativeElement.scroll(0, this.oldScrollHeight);
|
|
}
|
|
|
|
this.oldScrollHeight = this.chatPostArea.nativeElement.scrollHeight;
|
|
}
|
|
}
|
|
|
|
ngOnInit(): void {
|
|
if (this.userToken === null) {
|
|
return;
|
|
}
|
|
|
|
this.localNotifications.requestPermission();
|
|
|
|
this.apiService.getChatHistory(this.userToken, this.messageOffset, this.messageLimit).toPromise()
|
|
.then(
|
|
(response) => {
|
|
response.forEach(
|
|
(message: ChatMessage) => {
|
|
this.messages.push(message);
|
|
this.messageOffset++;
|
|
}
|
|
);
|
|
}
|
|
).catch(
|
|
(error) => {
|
|
window.alert('Fehler ' + error.status + ': Verbindung zur Web-API gescheitert!');
|
|
}
|
|
);
|
|
|
|
App.addListener('appStateChange', (state: AppState) => {
|
|
this.hasFocus = state.isActive;
|
|
});
|
|
|
|
this.platform.backButton.subscribe(
|
|
() => {
|
|
if (window.confirm('Möchtest du wirklich ausloggen?')) {
|
|
this.onLogout();
|
|
}
|
|
}
|
|
);
|
|
|
|
setInterval(
|
|
() => {
|
|
this.websocketService.sendKeepAliveMessage();
|
|
}, 1000 * 60 // every minute
|
|
);
|
|
}
|
|
|
|
onScroll(): void {
|
|
if (this.chatPostArea.nativeElement.scrollTop === 0) {
|
|
this.apiService.getChatHistory(this.userToken, this.messageOffset, this.messageLimit).subscribe(
|
|
(response) => {
|
|
this.messages = response.concat(this.messages);
|
|
this.messageOffset += this.messageLimit;
|
|
this.hasBeenReloaded = true;
|
|
}
|
|
);
|
|
}
|
|
}
|
|
|
|
onTextInput(event: Event): void {
|
|
if (!(event instanceof KeyboardEvent)) {
|
|
return;
|
|
}
|
|
|
|
switch (event.key) {
|
|
case 'Enter':
|
|
event.preventDefault();
|
|
|
|
if (this.chatText.trim() === '') {
|
|
return;
|
|
}
|
|
|
|
this.websocketService.sendChatMessage(this.chatText);
|
|
this.chatText = '';
|
|
|
|
return;
|
|
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
|
|
onLogout() {
|
|
this.apiService.storeData('token', null);
|
|
|
|
AppComponent.token = null;
|
|
}
|
|
|
|
onChatMessage(message: ChatMessage): void {
|
|
this.messages.push(message);
|
|
this.messageOffset++;
|
|
|
|
if (message.userId === this.userId) {
|
|
return;
|
|
}
|
|
|
|
this.triggerNotification(message);
|
|
}
|
|
|
|
onConnection(): void
|
|
{
|
|
this.errorMessage.nativeElement.style.display = 'none';
|
|
|
|
this.apiService.getChatMessagesMissed(this.userToken, this.messages[this.messages.length - 1].id).toPromise()
|
|
.then(
|
|
(messagesMissed) => {
|
|
if (messagesMissed.length === 0) {
|
|
return;
|
|
}
|
|
|
|
this.messages.concat(messagesMissed);
|
|
this.messageOffset += messagesMissed.length;
|
|
}
|
|
).catch(
|
|
(error) => {
|
|
console.log('Failed to load messages missed after reconnect!', error);
|
|
}
|
|
);
|
|
|
|
this.isReconnection = true;
|
|
}
|
|
|
|
onReconnect(): void
|
|
{
|
|
this.isReconnection = true;
|
|
}
|
|
|
|
onError(message: string): void
|
|
{
|
|
this.errorMessage.nativeElement.style.display = 'block';
|
|
this.errorMessage.nativeElement.innerText = message;
|
|
}
|
|
|
|
triggerNotification(message: ChatMessage): void
|
|
{
|
|
this.localNotifications.schedule(
|
|
{
|
|
title: message.username,
|
|
text: message.message,
|
|
id: 1,
|
|
priority: 2,
|
|
lockscreen: true,
|
|
autoClear: true,
|
|
icon: Setting.URL + '/user/' + message.userId + '/avatar?token=' + this.userToken,
|
|
smallIcon: 'ic_stat_notification_icon_enabled',
|
|
led: '#ff00ff',
|
|
trigger: { at: new Date(new Date().getTime() + 1000) },
|
|
sound: 'file://assets/audio/murloc.wav',
|
|
vibrate: true
|
|
}
|
|
);
|
|
}
|
|
|
|
private hasChatMessage(message: ChatMessage): boolean
|
|
{
|
|
for (const messageStored of this.messages) {
|
|
if (messageStored.id === message.id) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|