@illgrenoble/ngx-remote-desktop
Version:
ngx-remote-desktop is an Angular2+ module for connecting to a remote desktop using the guacamole protocol
304 lines (275 loc) • 10.8 kB
text/typescript
import { animate, state, style, transition, trigger } from '@angular/animations';
import {
ChangeDetectionStrategy,
Component,
ContentChild,
ElementRef,
Input,
OnDestroy,
OnInit,
ViewChild,
ViewEncapsulation,
HostListener,
Output,
} from '@angular/core';
import { BehaviorSubject, Subscription } from 'rxjs';
import * as screenfull from 'screenfull';
import { RemoteDesktopManager } from '../services';
import { ConnectingMessageComponent } from './messages/connecting-message.component';
import { DisconnectedMessageComponent } from './messages/disconnected-message.component';
import { ErrorMessageComponent } from './messages/error-message.component';
/**
* The main component for displaying a remote desktop
*/
export class RemoteDesktopComponent implements OnInit, OnDestroy {
/**
* Client that manages the connection to the remote desktop
*/
public manager: RemoteDesktopManager;
/**
* Guacamole has more states than the list below however for the component we are only interested
* in managing four states.
*/
public states = {
CONNECTING: 'CONNECTING',
CONNECTED: 'CONNECTED',
DISCONNECTED: 'DISCONNECTED',
ERROR: 'ERROR'
};
/**
* Manage the component state
*/
public state: BehaviorSubject<string> = new BehaviorSubject<string>(this.states.CONNECTING);
private connectingMessage: ConnectingMessageComponent;
private disconnectedMessage: DisconnectedMessageComponent;
private errorMessage: ErrorMessageComponent;
private container: ElementRef;
private toolbar: ElementRef;
/**
* Subscriptions
*/
private subscriptions: Subscription[] = [];
/**
* Hide or show the toolbar
*/
private toolbarVisible: boolean = true;
/**
* Subscribe to the connection state and full screen state when the component is initialised
*/
ngOnInit(): void {
this.bindSubscriptions();
}
/**
* Remove all subscriptions when the component is destroyed
*/
ngOnDestroy(): void {
this.unbindSubscriptions();
}
/**
* Bind the subscriptions
*/
private bindSubscriptions(): void {
this.subscriptions.push(this.manager.onStateChange.subscribe(this.handleState.bind(this)));
this.subscriptions.push(this.manager.onFullScreen.subscribe(this.handleFullScreen.bind(this)));
}
/**
* Unbind the subscriptions
*/
private unbindSubscriptions(): void {
this.subscriptions.forEach(subscription => subscription.unsubscribe());
}
/**
* Set the component state to the new guacamole state
* @param newState
*/
private setState(newState: string): void {
this.state.next(newState);
}
/**
* Receive the state from the desktop client and update this components state
* @param newState - state received from the guacamole client
*/
private handleState(newState: string) {
switch (newState) {
case RemoteDesktopManager.STATE.CONNECTED:
this.setState(this.states.CONNECTED);
break;
case RemoteDesktopManager.STATE.DISCONNECTED:
this.exitFullScreen();
this.setState(this.states.DISCONNECTED);
break;
case RemoteDesktopManager.STATE.CONNECTING:
case RemoteDesktopManager.STATE.WAITING:
this.setState(this.states.CONNECTING);
break;
case RemoteDesktopManager.STATE.CLIENT_ERROR:
case RemoteDesktopManager.STATE.TUNNEL_ERROR:
this.exitFullScreen();
this.setState(this.states.ERROR);
break;
}
}
/**
* Exit full screen and show the toolbar
*/
private exitFullScreen(): void {
if (!screenfull.isFullscreen) {
return;
}
const containerElement = this.container.nativeElement;
screenfull.exit(containerElement);
}
/**
* Enter full screen mode and auto hide the toolbar
*/
private enterFullScreen(): void {
if (screenfull.isFullscreen) {
return;
}
const containerElement = this.container.nativeElement;
screenfull.request(containerElement);
screenfull.on('change', (change: any) => {
if (!screenfull.isFullscreen) {
this.manager.setFullScreen(false);
}
this.handleToolbar();
});
}
/**
* Go in and out of full screen
*/
private handleFullScreen(newFullScreen: boolean): void {
if (newFullScreen) {
this.enterFullScreen();
} else {
this.exitFullScreen();
}
}
private handleToolbar(): void {
this.toolbarVisible = (this.manager.isFullScreen()) ? false : true;
}
/**
* Handle the display mouse movement
* @param event Mouse event
*/
private handleDisplayMouseMove($event: any): void {
if (!this.manager.isFullScreen()) {
return;
}
const toolbarWidth = this.toolbar.nativeElement.clientWidth;
if ($event.x >= toolbarWidth) {
this.toolbarVisible = false;
}
}
private onDocumentMousemove($event: MouseEvent) {
if (!this.manager.isFullScreen()) {
return;
}
const toolbarWidth = this.toolbar.nativeElement.clientWidth;
const x = $event.x;
if (x >= -1 && x <= 0) {
this.toolbarVisible = true;
}
if (x >= toolbarWidth) {
this.toolbarVisible = false;
}
}
}