feat(agent): Add loading screen (#444)
* feat(uhk-message): Add spin animation * feat(agent): Add loading page * fix device connected / disconnected events
This commit is contained in:
committed by
László Monda
parent
01b07a3ab7
commit
737897b40e
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
"unit-case": "lower",
|
"unit-case": "lower",
|
||||||
"unit-no-unknown": true,
|
"unit-no-unknown": true,
|
||||||
"unit-whitelist": ["px", "%", "deg", "ms", "em", "rem", "vh", "vv"],
|
"unit-whitelist": ["px", "%", "deg", "ms", "em", "rem", "vh", "vv", "s"],
|
||||||
|
|
||||||
"value-list-comma-space-after": "always-single-line",
|
"value-list-comma-space-after": "always-single-line",
|
||||||
"value-list-comma-space-before": "never",
|
"value-list-comma-space-before": "never",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
(doNotUpdateApp)="doNotUpdateApp()">
|
(doNotUpdateApp)="doNotUpdateApp()">
|
||||||
</app-update-available>
|
</app-update-available>
|
||||||
|
|
||||||
<side-menu *ngIf="deviceConnected$ | async"></side-menu>
|
<side-menu *ngIf="deviceConfigurationLoaded$ | async"></side-menu>
|
||||||
<div id="main-content" class="main-content">
|
<div id="main-content" class="main-content">
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { DoNotUpdateAppAction, UpdateAppAction } from './store/actions/app-updat
|
|||||||
import {
|
import {
|
||||||
AppState,
|
AppState,
|
||||||
getShowAppUpdateAvailable,
|
getShowAppUpdateAvailable,
|
||||||
deviceConnected,
|
deviceConfigurationLoaded,
|
||||||
runningInElectron,
|
runningInElectron,
|
||||||
saveToKeyboardState
|
saveToKeyboardState
|
||||||
} from './store';
|
} from './store';
|
||||||
@@ -37,13 +37,13 @@ import { SaveUserConfigInBinaryFileAction, SaveUserConfigInJsonFileAction } from
|
|||||||
})
|
})
|
||||||
export class MainAppComponent {
|
export class MainAppComponent {
|
||||||
showUpdateAvailable$: Observable<boolean>;
|
showUpdateAvailable$: Observable<boolean>;
|
||||||
deviceConnected$: Observable<boolean>;
|
deviceConfigurationLoaded$: Observable<boolean>;
|
||||||
runningInElectron$: Observable<boolean>;
|
runningInElectron$: Observable<boolean>;
|
||||||
saveToKeyboardState$: Observable<ProgressButtonState>;
|
saveToKeyboardState$: Observable<ProgressButtonState>;
|
||||||
|
|
||||||
constructor(private store: Store<AppState>) {
|
constructor(private store: Store<AppState>) {
|
||||||
this.showUpdateAvailable$ = store.select(getShowAppUpdateAvailable);
|
this.showUpdateAvailable$ = store.select(getShowAppUpdateAvailable);
|
||||||
this.deviceConnected$ = store.select(deviceConnected);
|
this.deviceConfigurationLoaded$ = store.select(deviceConfigurationLoaded);
|
||||||
this.runningInElectron$ = store.select(runningInElectron);
|
this.runningInElectron$ = store.select(runningInElectron);
|
||||||
this.saveToKeyboardState$ = store.select(saveToKeyboardState);
|
this.saveToKeyboardState$ = store.select(saveToKeyboardState);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ import { UhkDeviceUninitializedGuard } from './services/uhk-device-uninitialized
|
|||||||
import { UhkDeviceInitializedGuard } from './services/uhk-device-initialized.guard';
|
import { UhkDeviceInitializedGuard } from './services/uhk-device-initialized.guard';
|
||||||
import { MainPage } from './pages/main-page/main.page';
|
import { MainPage } from './pages/main-page/main.page';
|
||||||
import { settingsRoutes } from './components/settings/settings.routes';
|
import { settingsRoutes } from './components/settings/settings.routes';
|
||||||
|
import { LoadingDevicePageComponent } from './pages/loading-page/loading-device.page';
|
||||||
|
import { UhkDeviceLoadingGuard } from './services/uhk-device-loading.guard';
|
||||||
|
import { UhkDeviceLoadedGuard } from './services/uhk-device-loaded.guard';
|
||||||
|
|
||||||
const appRoutes: Routes = [
|
const appRoutes: Routes = [
|
||||||
{
|
{
|
||||||
@@ -25,10 +28,15 @@ const appRoutes: Routes = [
|
|||||||
component: PrivilegeCheckerComponent,
|
component: PrivilegeCheckerComponent,
|
||||||
canActivate: [UhkDeviceInitializedGuard]
|
canActivate: [UhkDeviceInitializedGuard]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'loading',
|
||||||
|
component: LoadingDevicePageComponent,
|
||||||
|
canActivate: [UhkDeviceLoadedGuard]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
component: MainPage,
|
component: MainPage,
|
||||||
canActivate: [UhkDeviceDisconnectedGuard],
|
canActivate: [UhkDeviceDisconnectedGuard, UhkDeviceLoadingGuard],
|
||||||
children: [
|
children: [
|
||||||
...deviceRoutes,
|
...deviceRoutes,
|
||||||
...keymapRoutes,
|
...keymapRoutes,
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
<span class="uhk-message-wrapper">
|
<span class="uhk-message-wrapper">
|
||||||
<img class="agent-logo" src="assets/images/agent-icon.png"/>
|
<img class="agent-logo spin-logo"
|
||||||
|
[ngClass]="{'spin-logo': rotateLogo}"
|
||||||
|
src="assets/images/agent-icon.png"/>
|
||||||
<div class="messages">
|
<div class="messages">
|
||||||
<h1> {{ title }} </h1>
|
<h1> {{ title }} </h1>
|
||||||
<h2> {{ subtitle }} </h2>
|
<h2> {{ subtitle }} </h2>
|
||||||
|
|||||||
@@ -17,3 +17,23 @@
|
|||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.spin-logo {
|
||||||
|
-webkit-animation: spin 2s ease-in-out infinite;
|
||||||
|
-moz-animation: spin 2s ease-in-out infinite;
|
||||||
|
animation: spin 2s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,4 +9,5 @@ import { Component, Input, ChangeDetectionStrategy } from '@angular/core';
|
|||||||
export class UhkMessageComponent {
|
export class UhkMessageComponent {
|
||||||
@Input() title: string;
|
@Input() title: string;
|
||||||
@Input() subtitle: string;
|
@Input() subtitle: string;
|
||||||
|
@Input() rotateLogo = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'loading-device',
|
||||||
|
template: `
|
||||||
|
<uhk-message title="Loading Agent..."
|
||||||
|
subtitle="Hang tight!"
|
||||||
|
[rotateLogo]="true"></uhk-message>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
export class LoadingDevicePageComponent {
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
}
|
||||||
|
}
|
||||||
25
packages/uhk-web/src/app/services/uhk-device-loaded.guard.ts
Normal file
25
packages/uhk-web/src/app/services/uhk-device-loaded.guard.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { CanActivate, Router } from '@angular/router';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
import 'rxjs/add/operator/do';
|
||||||
|
import 'rxjs/add/operator/map';
|
||||||
|
|
||||||
|
import { AppState, deviceConfigurationLoaded } from '../store';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class UhkDeviceLoadedGuard implements CanActivate {
|
||||||
|
|
||||||
|
constructor(private store: Store<AppState>, private router: Router) { }
|
||||||
|
|
||||||
|
canActivate(): Observable<boolean> {
|
||||||
|
return this.store.select(deviceConfigurationLoaded)
|
||||||
|
.do(loaded => {
|
||||||
|
if (loaded) {
|
||||||
|
this.router.navigate(['/']);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(loaded => !loaded);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { CanActivate, Router } from '@angular/router';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
import 'rxjs/add/operator/do';
|
||||||
|
|
||||||
|
import { AppState, deviceConfigurationLoaded } from '../store';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class UhkDeviceLoadingGuard implements CanActivate {
|
||||||
|
|
||||||
|
constructor(private store: Store<AppState>, private router: Router) { }
|
||||||
|
|
||||||
|
canActivate(): Observable<boolean> {
|
||||||
|
return this.store.select(deviceConfigurationLoaded)
|
||||||
|
.do(loaded => {
|
||||||
|
if (!loaded) {
|
||||||
|
this.router.navigate(['/loading']);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -85,11 +85,13 @@ import { UhkDeviceConnectedGuard } from './services/uhk-device-connected.guard';
|
|||||||
import { UhkDeviceDisconnectedGuard } from './services/uhk-device-disconnected.guard';
|
import { UhkDeviceDisconnectedGuard } from './services/uhk-device-disconnected.guard';
|
||||||
import { UhkDeviceUninitializedGuard } from './services/uhk-device-uninitialized.guard';
|
import { UhkDeviceUninitializedGuard } from './services/uhk-device-uninitialized.guard';
|
||||||
import { MainPage } from './pages/main-page/main.page';
|
import { MainPage } from './pages/main-page/main.page';
|
||||||
import { DeviceEffects } from './store/effects/device';
|
|
||||||
import { DeviceRendererService } from './services/device-renderer.service';
|
import { DeviceRendererService } from './services/device-renderer.service';
|
||||||
import { UhkDeviceInitializedGuard } from './services/uhk-device-initialized.guard';
|
import { UhkDeviceInitializedGuard } from './services/uhk-device-initialized.guard';
|
||||||
import { ProgressButtonComponent } from './components/progress-button/progress-button.component';
|
import { ProgressButtonComponent } from './components/progress-button/progress-button.component';
|
||||||
import { MainAppComponent } from './app.component';
|
import { MainAppComponent } from './app.component';
|
||||||
|
import { LoadingDevicePageComponent } from './pages/loading-page/loading-device.page';
|
||||||
|
import { UhkDeviceLoadingGuard } from './services/uhk-device-loading.guard';
|
||||||
|
import { UhkDeviceLoadedGuard } from './services/uhk-device-loaded.guard';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@@ -151,7 +153,8 @@ import { MainAppComponent } from './app.component';
|
|||||||
MissingDeviceComponent,
|
MissingDeviceComponent,
|
||||||
PrivilegeCheckerComponent,
|
PrivilegeCheckerComponent,
|
||||||
MainPage,
|
MainPage,
|
||||||
ProgressButtonComponent
|
ProgressButtonComponent,
|
||||||
|
LoadingDevicePageComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
@@ -180,7 +183,9 @@ import { MainAppComponent } from './app.component';
|
|||||||
UhkDeviceConnectedGuard,
|
UhkDeviceConnectedGuard,
|
||||||
UhkDeviceDisconnectedGuard,
|
UhkDeviceDisconnectedGuard,
|
||||||
UhkDeviceInitializedGuard,
|
UhkDeviceInitializedGuard,
|
||||||
UhkDeviceUninitializedGuard
|
UhkDeviceUninitializedGuard,
|
||||||
|
UhkDeviceLoadingGuard,
|
||||||
|
UhkDeviceLoadedGuard
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
UhkMessageComponent,
|
UhkMessageComponent,
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ export class UserConfigEffects {
|
|||||||
try {
|
try {
|
||||||
const userConfig = UserConfigEffects.getUserConfigFromDeviceResponse(data.userConfiguration);
|
const userConfig = UserConfigEffects.getUserConfigFromDeviceResponse(data.userConfiguration);
|
||||||
const hardwareConfig = UserConfigEffects.getHardwareConfigFromDeviceResponse(data.hardwareConfiguration);
|
const hardwareConfig = UserConfigEffects.getHardwareConfigFromDeviceResponse(data.hardwareConfiguration);
|
||||||
|
this.router.navigate(['/']);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
new LoadUserConfigSuccessAction(userConfig),
|
new LoadUserConfigSuccessAction(userConfig),
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ export const getPrevUserConfiguration = createSelector(appState, fromApp.getPrev
|
|||||||
export const runningInElectron = createSelector(appState, fromApp.runningInElectron);
|
export const runningInElectron = createSelector(appState, fromApp.runningInElectron);
|
||||||
export const getHardwareConfiguration = createSelector(appState, fromApp.getHardwareConfiguration);
|
export const getHardwareConfiguration = createSelector(appState, fromApp.getHardwareConfiguration);
|
||||||
export const getKeyboardLayout = createSelector(appState, fromApp.getKeyboardLayout);
|
export const getKeyboardLayout = createSelector(appState, fromApp.getKeyboardLayout);
|
||||||
|
export const deviceConfigurationLoaded = createSelector(appState, fromApp.deviceConfigurationLoaded);
|
||||||
|
|
||||||
export const appUpdateState = (state: AppState) => state.appUpdate;
|
export const appUpdateState = (state: AppState) => state.appUpdate;
|
||||||
export const getShowAppUpdateAvailable = createSelector(appUpdateState, fromAppUpdate.getShowAppUpdateAvailable);
|
export const getShowAppUpdateAvailable = createSelector(appUpdateState, fromAppUpdate.getShowAppUpdateAvailable);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { Action } from '@ngrx/store';
|
|||||||
import { HardwareConfiguration, runInElectron, Notification, NotificationType, UserConfiguration } from 'uhk-common';
|
import { HardwareConfiguration, runInElectron, Notification, NotificationType, UserConfiguration } from 'uhk-common';
|
||||||
import { ActionTypes, ShowNotificationAction } from '../actions/app';
|
import { ActionTypes, ShowNotificationAction } from '../actions/app';
|
||||||
import { ActionTypes as UserConfigActionTypes } from '../actions/user-config';
|
import { ActionTypes as UserConfigActionTypes } from '../actions/user-config';
|
||||||
|
import { ActionTypes as DeviceActionTypes } from '../actions/device';
|
||||||
import { KeyboardLayout } from '../../keyboard/keyboard-layout.enum';
|
import { KeyboardLayout } from '../../keyboard/keyboard-layout.enum';
|
||||||
|
|
||||||
export interface State {
|
export interface State {
|
||||||
@@ -57,7 +58,7 @@ export function reducer(state = initialState, action: Action & { payload: any })
|
|||||||
// When deleted a keymap or macro the app automaticaly navigate to other keymap, or macro, so
|
// When deleted a keymap or macro the app automaticaly navigate to other keymap, or macro, so
|
||||||
// so we have to count the navigations and when reach the 2nd then remove the dialog.
|
// so we have to count the navigations and when reach the 2nd then remove the dialog.
|
||||||
case ROUTER_NAVIGATION: {
|
case ROUTER_NAVIGATION: {
|
||||||
const newState = { ...state };
|
const newState = {...state};
|
||||||
newState.navigationCountAfterNotification++;
|
newState.navigationCountAfterNotification++;
|
||||||
|
|
||||||
if (newState.navigationCountAfterNotification > 1) {
|
if (newState.navigationCountAfterNotification > 1) {
|
||||||
@@ -98,6 +99,17 @@ export function reducer(state = initialState, action: Action & { payload: any })
|
|||||||
hardwareConfig: action.payload
|
hardwareConfig: action.payload
|
||||||
};
|
};
|
||||||
|
|
||||||
|
case DeviceActionTypes.CONNECTION_STATE_CHANGED:
|
||||||
|
|
||||||
|
if (action.payload === true) {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
hardwareConfig: null
|
||||||
|
};
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
@@ -115,3 +127,4 @@ export const getKeyboardLayout = (state: State): KeyboardLayout => {
|
|||||||
|
|
||||||
return KeyboardLayout.ANSI;
|
return KeyboardLayout.ANSI;
|
||||||
};
|
};
|
||||||
|
export const deviceConfigurationLoaded = (state: State) => !state.runningInElectron ? true : !!state.hardwareConfig;
|
||||||
|
|||||||
Reference in New Issue
Block a user