refactore: create feature modules (#387)
* add @angular/cli to the project * increase nodejs version -> 8.2.1 * add lerna * merge web and shared module * move electron module into packages as uhk-agent Electron agent functionality is not working * delete symlinker * convert private properties to public of component if used in html * revert uhk-message.component * fix component path * fix the correct name of the uhk-message.component.scss * building web and electron module * delete uhk-renderer package * handle device connect disconnect state * add privilege detection * fix set privilege functionality * turn back download keymap functionality * add bootstrap, select2 js and fix null pointer exception * turn back upload data to keyboard * fix send keymap * fix test-serializer * add missing package.json * merging * fix appveyor build * fix linting * turn back electron storage service * commit the missing electron-datastorage-repository * update node to 8.3.0 in .nvmrc and log node version in appveyor build * set exact version number in appveyor build * vertical align privilege and missing device components * set back node version to 8 in appveyor * move node-usb dependency from usb dir to root maybe it is fix the appveyor build * revert usb to root * fix electron builder script * fix electron builder script * turn off electron devtools * remove CTRL+U functionality * fix CTRL+o * fix lint error * turnoff store freeze * start process when got `Error: EPERM: operation not permitted` error * move files from root usb dir -> packages/usb
This commit is contained in:
committed by
László Monda
parent
97770f67c0
commit
0f558e4132
@@ -0,0 +1,48 @@
|
||||
import { Action } from '@ngrx/store';
|
||||
import { type } from 'uhk-common';
|
||||
|
||||
const PREFIX = '[app-update] ';
|
||||
|
||||
// tslint:disable-next-line:variable-name
|
||||
export const ActionTypes = {
|
||||
UPDATE_AVAILABLE: type(PREFIX + 'update available'),
|
||||
UPDATE_APP: type(PREFIX + 'update app'),
|
||||
DO_NOT_UPDATE_APP: type(PREFIX + 'do not update app'),
|
||||
UPDATE_DOWNLOADED: type(PREFIX + 'update downloaded'),
|
||||
UPDATING: type(PREFIX + 'updating'),
|
||||
UPDATE_ERROR: type(PREFIX + 'error')
|
||||
};
|
||||
|
||||
export class UpdateAvailableAction implements Action {
|
||||
type = ActionTypes.UPDATE_AVAILABLE;
|
||||
}
|
||||
|
||||
export class UpdateAppAction implements Action {
|
||||
type = ActionTypes.UPDATE_APP;
|
||||
}
|
||||
|
||||
export class DoNotUpdateAppAction implements Action {
|
||||
type = ActionTypes.DO_NOT_UPDATE_APP;
|
||||
}
|
||||
|
||||
export class UpdateDownloadedAction implements Action {
|
||||
type = ActionTypes.UPDATE_DOWNLOADED;
|
||||
}
|
||||
|
||||
export class UpdatingAction implements Action {
|
||||
type = ActionTypes.UPDATING;
|
||||
}
|
||||
|
||||
export class UpdateErrorAction implements Action {
|
||||
type = ActionTypes.UPDATE_ERROR;
|
||||
|
||||
constructor(public payload: any) {}
|
||||
}
|
||||
|
||||
export type Actions
|
||||
= UpdateAvailableAction
|
||||
| UpdateAppAction
|
||||
| DoNotUpdateAppAction
|
||||
| UpdateDownloadedAction
|
||||
| UpdatingAction
|
||||
| UpdateErrorAction;
|
||||
@@ -0,0 +1,69 @@
|
||||
import { Action } from '@ngrx/store';
|
||||
|
||||
import { type } from 'uhk-common';
|
||||
import { Notification, CommandLineArgs } from 'uhk-common';
|
||||
import { AppStartInfo } from '../../../../../uhk-common/src/models/app-start-info';
|
||||
|
||||
const PREFIX = '[app] ';
|
||||
|
||||
// tslint:disable-next-line:variable-name
|
||||
export const ActionTypes = {
|
||||
APP_BOOTSRAPPED: type(PREFIX + 'bootstrapped'),
|
||||
APP_STARTED: type(PREFIX + 'started'),
|
||||
APP_SHOW_NOTIFICATION: type(PREFIX + 'show notification'),
|
||||
APP_TOGGLE_ADDON_MENU: type(PREFIX + 'toggle add-on menu'),
|
||||
APP_PROCESS_START_INFO: type(PREFIX + 'process start info'),
|
||||
UNDO_LAST: type(PREFIX + 'undo last action'),
|
||||
UNDO_LAST_SUCCESS: type(PREFIX + 'undo last action success'),
|
||||
DISMISS_UNDO_NOTIFICATION: type(PREFIX + 'dismiss notification action')
|
||||
};
|
||||
|
||||
export class AppBootsrappedAction implements Action {
|
||||
type = ActionTypes.APP_BOOTSRAPPED;
|
||||
}
|
||||
|
||||
export class AppStartedAction implements Action {
|
||||
type = ActionTypes.APP_STARTED;
|
||||
}
|
||||
|
||||
export class ShowNotificationAction implements Action {
|
||||
type = ActionTypes.APP_SHOW_NOTIFICATION;
|
||||
|
||||
constructor(public payload: Notification) { }
|
||||
}
|
||||
|
||||
export class ToggleAddonMenuAction implements Action {
|
||||
type = ActionTypes.APP_TOGGLE_ADDON_MENU;
|
||||
|
||||
constructor(public payload: boolean) { }
|
||||
}
|
||||
|
||||
export class ProcessAppStartInfoAction implements Action {
|
||||
type = ActionTypes.APP_PROCESS_START_INFO;
|
||||
|
||||
constructor(public payload: AppStartInfo) { }
|
||||
}
|
||||
|
||||
export class UndoLastAction implements Action {
|
||||
type = ActionTypes.UNDO_LAST;
|
||||
|
||||
constructor(public payload: any) {}
|
||||
}
|
||||
|
||||
export class UndoLastSuccessAction implements Action {
|
||||
type = ActionTypes.UNDO_LAST_SUCCESS;
|
||||
}
|
||||
|
||||
export class DismissUndoNotificationAction implements Action {
|
||||
type = ActionTypes.DISMISS_UNDO_NOTIFICATION;
|
||||
}
|
||||
|
||||
export type Actions
|
||||
= AppStartedAction
|
||||
| AppBootsrappedAction
|
||||
| ShowNotificationAction
|
||||
| ToggleAddonMenuAction
|
||||
| ProcessAppStartInfoAction
|
||||
| UndoLastAction
|
||||
| UndoLastSuccessAction
|
||||
| DismissUndoNotificationAction;
|
||||
@@ -0,0 +1,74 @@
|
||||
import { Action } from '@ngrx/store';
|
||||
|
||||
import { type } from 'uhk-common';
|
||||
import { AutoUpdateSettings } from '../../models/auto-update-settings';
|
||||
|
||||
const PREFIX = '[app-update-config] ';
|
||||
|
||||
// tslint:disable-next-line:variable-name
|
||||
export const ActionTypes = {
|
||||
TOGGLE_CHECK_FOR_UPDATE_ON_STARTUP: type(PREFIX + 'Check for update on startup'),
|
||||
CHECK_FOR_UPDATE_NOW: type(PREFIX + 'Check for update now'),
|
||||
CHECK_FOR_UPDATE_SUCCESS: type(PREFIX + 'Check for update success'),
|
||||
CHECK_FOR_UPDATE_FAILED: type(PREFIX + 'Check for update faild'),
|
||||
TOGGLE_PRE_RELEASE_FLAG: type(PREFIX + 'Toggle pre release update flag'),
|
||||
LOAD_AUTO_UPDATE_SETTINGS: type(PREFIX + 'Load auto update settings'),
|
||||
LOAD_AUTO_UPDATE_SETTINGS_SUCCESS: type(PREFIX + 'Load auto update settings success'),
|
||||
SAVE_AUTO_UPDATE_SETTINGS_SUCCESS: type(PREFIX + 'Save auto update settings success')
|
||||
};
|
||||
|
||||
export class ToggleCheckForUpdateOnStartupAction implements Action {
|
||||
type = ActionTypes.TOGGLE_CHECK_FOR_UPDATE_ON_STARTUP;
|
||||
|
||||
constructor(public payload: boolean) {
|
||||
}
|
||||
}
|
||||
|
||||
export class CheckForUpdateNowAction implements Action {
|
||||
type = ActionTypes.CHECK_FOR_UPDATE_NOW;
|
||||
}
|
||||
|
||||
export class CheckForUpdateSuccessAction implements Action {
|
||||
type = ActionTypes.CHECK_FOR_UPDATE_SUCCESS;
|
||||
constructor(public payload?: string) {
|
||||
}
|
||||
}
|
||||
|
||||
export class CheckForUpdateFailedAction implements Action {
|
||||
type = ActionTypes.CHECK_FOR_UPDATE_FAILED;
|
||||
|
||||
constructor(public payload: any) {
|
||||
}
|
||||
}
|
||||
|
||||
export class TogglePreReleaseFlagAction implements Action {
|
||||
type = ActionTypes.TOGGLE_PRE_RELEASE_FLAG;
|
||||
|
||||
constructor(public payload: boolean) {
|
||||
}
|
||||
}
|
||||
|
||||
export class LoadAutoUpdateSettingsAction implements Action {
|
||||
type = ActionTypes.LOAD_AUTO_UPDATE_SETTINGS_SUCCESS;
|
||||
}
|
||||
|
||||
export class LoadAutoUpdateSettingsSuccessAction implements Action {
|
||||
type = ActionTypes.LOAD_AUTO_UPDATE_SETTINGS_SUCCESS;
|
||||
|
||||
constructor(public payload: AutoUpdateSettings) {
|
||||
}
|
||||
}
|
||||
|
||||
export class SaveAutoUpdateSettingsSuccessAction implements Action {
|
||||
type = ActionTypes.SAVE_AUTO_UPDATE_SETTINGS_SUCCESS;
|
||||
}
|
||||
|
||||
export type Actions
|
||||
= ToggleCheckForUpdateOnStartupAction
|
||||
| CheckForUpdateNowAction
|
||||
| CheckForUpdateSuccessAction
|
||||
| CheckForUpdateFailedAction
|
||||
| TogglePreReleaseFlagAction
|
||||
| LoadAutoUpdateSettingsAction
|
||||
| LoadAutoUpdateSettingsSuccessAction
|
||||
| SaveAutoUpdateSettingsSuccessAction;
|
||||
@@ -0,0 +1,52 @@
|
||||
import { Action } from '@ngrx/store';
|
||||
import { type, IpcResponse } from 'uhk-common';
|
||||
|
||||
const PREFIX = '[device] ';
|
||||
|
||||
// tslint:disable-next-line:variable-name
|
||||
export const ActionTypes = {
|
||||
SET_PRIVILEGE_ON_LINUX: type(PREFIX + 'set privilege on linux'),
|
||||
SET_PRIVILEGE_ON_LINUX_REPLY: type(PREFIX + 'set privilege on linux reply'),
|
||||
CONNECTION_STATE_CHANGED: type(PREFIX + 'connection state changed'),
|
||||
PERMISSION_STATE_CHANGED: type(PREFIX + 'permission state changed'),
|
||||
SAVE_CONFIGURATION: type(PREFIX + 'save configuration'),
|
||||
SAVE_CONFIGURATION_REPLY: type(PREFIX + 'save configuration reply')
|
||||
};
|
||||
|
||||
export class SetPrivilegeOnLinuxAction implements Action {
|
||||
type = ActionTypes.SET_PRIVILEGE_ON_LINUX;
|
||||
}
|
||||
|
||||
export class SetPrivilegeOnLinuxReplyAction implements Action {
|
||||
type = ActionTypes.SET_PRIVILEGE_ON_LINUX_REPLY;
|
||||
|
||||
constructor(public payload: IpcResponse) {}
|
||||
}
|
||||
|
||||
export class ConnectionStateChangedAction implements Action {
|
||||
type = ActionTypes.CONNECTION_STATE_CHANGED;
|
||||
|
||||
constructor(public payload: boolean) {}
|
||||
}
|
||||
|
||||
export class PermissionStateChangedAction implements Action {
|
||||
type = ActionTypes.PERMISSION_STATE_CHANGED;
|
||||
|
||||
constructor(public payload: boolean) {}
|
||||
}
|
||||
|
||||
export class SaveConfigurationAction implements Action {
|
||||
type = ActionTypes.SAVE_CONFIGURATION;
|
||||
|
||||
constructor(public payload: Buffer) {}
|
||||
}
|
||||
|
||||
export class SaveConfigurationReplyAction implements Action {
|
||||
type = ActionTypes.SAVE_CONFIGURATION_REPLY;
|
||||
|
||||
constructor(public payload: IpcResponse) {}
|
||||
}
|
||||
|
||||
export type Actions
|
||||
= SetPrivilegeOnLinuxAction
|
||||
| ConnectionStateChangedAction;
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './keymap';
|
||||
export * from './macro';
|
||||
@@ -0,0 +1,102 @@
|
||||
import { Action } from '@ngrx/store';
|
||||
|
||||
import { KeyAction } from '../../config-serializer/config-items/key-action';
|
||||
import { Keymap } from '../../config-serializer/config-items/keymap';
|
||||
import { Macro } from '../../config-serializer/config-items/macro';
|
||||
|
||||
export namespace KeymapActions {
|
||||
export const PREFIX = '[Keymap] ';
|
||||
export const ADD = KeymapActions.PREFIX + 'Add keymap';
|
||||
export const DUPLICATE = KeymapActions.PREFIX + 'Duplicate keymap';
|
||||
export const EDIT_ABBR = KeymapActions.PREFIX + 'Edit keymap abbreviation';
|
||||
export const EDIT_NAME = KeymapActions.PREFIX + 'Edit keymap title';
|
||||
export const SAVE_KEY = KeymapActions.PREFIX + 'Save key action';
|
||||
export const SET_DEFAULT = KeymapActions.PREFIX + 'Set default option';
|
||||
export const REMOVE = KeymapActions.PREFIX + 'Remove keymap';
|
||||
export const CHECK_MACRO = KeymapActions.PREFIX + 'Check deleted macro';
|
||||
export const LOAD_KEYMAPS = KeymapActions.PREFIX + 'Load keymaps';
|
||||
export const LOAD_KEYMAPS_SUCCESS = KeymapActions.PREFIX + 'Load keymaps success';
|
||||
export const UNDO_LAST_ACTION = KeymapActions.PREFIX + 'Undo last action';
|
||||
|
||||
export function loadKeymaps(): Action {
|
||||
return {
|
||||
type: KeymapActions.LOAD_KEYMAPS
|
||||
};
|
||||
}
|
||||
|
||||
export function loadKeymapsSuccess(keymaps: Keymap[]): Action {
|
||||
return {
|
||||
type: KeymapActions.LOAD_KEYMAPS_SUCCESS,
|
||||
payload: keymaps
|
||||
};
|
||||
}
|
||||
|
||||
export function addKeymap(item: Keymap): Action {
|
||||
return {
|
||||
type: KeymapActions.ADD,
|
||||
payload: item
|
||||
};
|
||||
}
|
||||
|
||||
export function setDefault(abbr: string): Action {
|
||||
return {
|
||||
type: KeymapActions.SET_DEFAULT,
|
||||
payload: abbr
|
||||
};
|
||||
}
|
||||
|
||||
export function removeKeymap(abbr: string): Action {
|
||||
return {
|
||||
type: KeymapActions.REMOVE,
|
||||
payload: abbr
|
||||
};
|
||||
}
|
||||
|
||||
export function duplicateKeymap(keymap: Keymap): Action {
|
||||
return {
|
||||
type: KeymapActions.DUPLICATE,
|
||||
payload: keymap
|
||||
};
|
||||
}
|
||||
|
||||
export function editKeymapName(abbr: string, name: string): Action {
|
||||
return {
|
||||
type: KeymapActions.EDIT_NAME,
|
||||
payload: {
|
||||
abbr: abbr,
|
||||
name: name
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function editKeymapAbbr(name: string, abbr: string, newAbbr: string): Action {
|
||||
return {
|
||||
type: KeymapActions.EDIT_ABBR,
|
||||
payload: {
|
||||
name,
|
||||
abbr,
|
||||
newAbbr
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function saveKey(keymap: Keymap, layer: number, module: number, key: number, keyAction: KeyAction): Action {
|
||||
return {
|
||||
type: KeymapActions.SAVE_KEY,
|
||||
payload: {
|
||||
keymap,
|
||||
layer,
|
||||
module,
|
||||
key,
|
||||
keyAction
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function checkMacro(macro: Macro): Action {
|
||||
return {
|
||||
type: KeymapActions.CHECK_MACRO,
|
||||
payload: macro
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
import { Action } from '@ngrx/store';
|
||||
|
||||
import { Macro } from '../../config-serializer/config-items/macro';
|
||||
import { MacroAction } from '../../config-serializer/config-items/macro-action';
|
||||
|
||||
export namespace MacroActions {
|
||||
export const PREFIX = '[Macro] ';
|
||||
|
||||
export const DUPLICATE = MacroActions.PREFIX + 'Duplicate macro';
|
||||
export const EDIT_NAME = MacroActions.PREFIX + 'Edit macro title';
|
||||
export const REMOVE = MacroActions.PREFIX + 'Remove macro';
|
||||
export const ADD = MacroActions.PREFIX + 'Add macro';
|
||||
|
||||
export const ADD_ACTION = MacroActions.PREFIX + 'Add macro action';
|
||||
export const SAVE_ACTION = MacroActions.PREFIX + 'Save macro action';
|
||||
export const DELETE_ACTION = MacroActions.PREFIX + 'Delete macro action';
|
||||
export const REORDER_ACTION = MacroActions.PREFIX + 'Reorder macro action';
|
||||
|
||||
export function addMacro(): Action {
|
||||
return {
|
||||
type: MacroActions.ADD
|
||||
};
|
||||
}
|
||||
|
||||
export function removeMacro(macroId: number): Action {
|
||||
return {
|
||||
type: MacroActions.REMOVE,
|
||||
payload: macroId
|
||||
};
|
||||
}
|
||||
|
||||
export function duplicateMacro(macro: Macro): Action {
|
||||
return {
|
||||
type: MacroActions.DUPLICATE,
|
||||
payload: macro
|
||||
};
|
||||
}
|
||||
|
||||
export function editMacroName(id: number, name: string): Action {
|
||||
return {
|
||||
type: MacroActions.EDIT_NAME,
|
||||
payload: {
|
||||
id: id,
|
||||
name: name
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function addMacroAction(id: number, action: MacroAction): Action {
|
||||
return {
|
||||
type: MacroActions.ADD_ACTION,
|
||||
payload: {
|
||||
id: id,
|
||||
action: action
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function saveMacroAction(id: number, index: number, action: MacroAction): Action {
|
||||
return {
|
||||
type: MacroActions.SAVE_ACTION,
|
||||
payload: {
|
||||
id: id,
|
||||
index: index,
|
||||
action: action
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function deleteMacroAction(id: number, index: number, action: MacroAction): Action {
|
||||
return {
|
||||
type: MacroActions.DELETE_ACTION,
|
||||
payload: {
|
||||
id: id,
|
||||
index: index,
|
||||
action: action
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function reorderMacroAction(id: number, oldIndex: number, newIndex: number): Action {
|
||||
return {
|
||||
type: MacroActions.REORDER_ACTION,
|
||||
payload: {
|
||||
id: id,
|
||||
oldIndex: oldIndex,
|
||||
newIndex: newIndex
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { Action } from '@ngrx/store';
|
||||
|
||||
import { type } from 'uhk-common';
|
||||
import { UserConfiguration } from '../../config-serializer/config-items/user-configuration';
|
||||
|
||||
const PREFIX = '[user-config] ';
|
||||
|
||||
// tslint:disable-next-line:variable-name
|
||||
export const ActionTypes = {
|
||||
LOAD_USER_CONFIG: type(PREFIX + 'Load User Config'),
|
||||
LOAD_USER_CONFIG_SUCCESS: type(PREFIX + 'Load User Config Success'),
|
||||
SAVE_USER_CONFIG_SUCCESS: type(PREFIX + 'Save User Config Success')
|
||||
};
|
||||
|
||||
export class LoadUserConfigAction implements Action {
|
||||
type = ActionTypes.LOAD_USER_CONFIG;
|
||||
}
|
||||
|
||||
export class LoadUserConfigSuccessAction implements Action {
|
||||
type = ActionTypes.LOAD_USER_CONFIG_SUCCESS;
|
||||
|
||||
constructor(public payload: UserConfiguration) { }
|
||||
}
|
||||
|
||||
export class SaveUserConfigSuccessAction implements Action {
|
||||
type = ActionTypes.SAVE_USER_CONFIG_SUCCESS;
|
||||
|
||||
constructor(public payload: UserConfiguration) { }
|
||||
}
|
||||
|
||||
export type Actions
|
||||
= LoadUserConfigAction
|
||||
| LoadUserConfigSuccessAction
|
||||
| SaveUserConfigSuccessAction;
|
||||
@@ -0,0 +1,47 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Action } from '@ngrx/store';
|
||||
import { Actions, Effect, toPayload } from '@ngrx/effects';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
|
||||
import 'rxjs/add/operator/do';
|
||||
import 'rxjs/add/operator/map';
|
||||
import 'rxjs/add/operator/first';
|
||||
|
||||
import { NotificationType } from 'uhk-common';
|
||||
|
||||
import { ActionTypes } from '../actions/app-update.action';
|
||||
import { ActionTypes as AutoUpdateActionTypes } from '../actions/auto-update-settings';
|
||||
import { ShowNotificationAction } from '../actions/app';
|
||||
import { AppUpdateRendererService } from '../../services/app-update-renderer.service';
|
||||
|
||||
@Injectable()
|
||||
export class AppUpdateEffect {
|
||||
@Effect({ dispatch: false })
|
||||
appStart$: Observable<Action> = this.actions$
|
||||
.ofType(ActionTypes.UPDATE_APP)
|
||||
.first()
|
||||
.do(() => {
|
||||
this.appUpdateRendererService.sendUpdateAndRestartApp();
|
||||
});
|
||||
|
||||
@Effect({ dispatch: false }) checkForUpdate$: Observable<Action> = this.actions$
|
||||
.ofType(AutoUpdateActionTypes.CHECK_FOR_UPDATE_NOW)
|
||||
.do(() => {
|
||||
this.appUpdateRendererService.checkForUpdate();
|
||||
});
|
||||
|
||||
@Effect() handleError$: Observable<Action> = this.actions$
|
||||
.ofType(ActionTypes.UPDATE_ERROR)
|
||||
.map(toPayload)
|
||||
.map((message: string) => {
|
||||
return new ShowNotificationAction({
|
||||
type: NotificationType.Error,
|
||||
message
|
||||
});
|
||||
});
|
||||
|
||||
constructor(private actions$: Actions,
|
||||
private appUpdateRendererService: AppUpdateRendererService) {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Action } from '@ngrx/store';
|
||||
import { Actions, Effect, toPayload } from '@ngrx/effects';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { NotifierService } from 'angular-notifier';
|
||||
|
||||
import 'rxjs/add/observable/of';
|
||||
import 'rxjs/add/operator/do';
|
||||
import 'rxjs/add/operator/map';
|
||||
import 'rxjs/add/operator/mergeMap';
|
||||
import 'rxjs/add/operator/catch';
|
||||
|
||||
import { AppStartInfo, Notification, NotificationType, LogService } from 'uhk-common';
|
||||
import { ActionTypes, AppStartedAction, DismissUndoNotificationAction, ToggleAddonMenuAction } from '../actions/app';
|
||||
import { AppRendererService } from '../../services/app-renderer.service';
|
||||
import { AppUpdateRendererService } from '../../services/app-update-renderer.service';
|
||||
import { ConnectionStateChangedAction, PermissionStateChangedAction } from '../actions/device';
|
||||
|
||||
@Injectable()
|
||||
export class ApplicationEffects {
|
||||
|
||||
@Effect()
|
||||
appStart$: Observable<Action> = this.actions$
|
||||
.ofType(ActionTypes.APP_BOOTSRAPPED)
|
||||
.startWith(new AppStartedAction())
|
||||
.do(() => {
|
||||
this.logService.info('Renderer appStart effect start');
|
||||
this.appUpdateRendererService.sendAppStarted();
|
||||
this.appRendererService.getAppStartInfo();
|
||||
this.logService.info('Renderer appStart effect end');
|
||||
});
|
||||
|
||||
@Effect({ dispatch: false })
|
||||
showNotification$: Observable<Action> = this.actions$
|
||||
.ofType(ActionTypes.APP_SHOW_NOTIFICATION)
|
||||
.map(toPayload)
|
||||
.do((notification: Notification) => {
|
||||
if (notification.type === NotificationType.Undoable) {
|
||||
return;
|
||||
}
|
||||
this.notifierService.notify(notification.type, notification.message);
|
||||
});
|
||||
|
||||
@Effect()
|
||||
processStartInfo$: Observable<Action> = this.actions$
|
||||
.ofType(ActionTypes.APP_PROCESS_START_INFO)
|
||||
.map(toPayload)
|
||||
.mergeMap((appInfo: AppStartInfo) => {
|
||||
this.logService.debug('[AppEffect][processStartInfo] payload:', appInfo);
|
||||
return [
|
||||
new ToggleAddonMenuAction(appInfo.commandLineArgs.addons),
|
||||
new ConnectionStateChangedAction(appInfo.deviceConnected),
|
||||
new PermissionStateChangedAction(appInfo.hasPermission)
|
||||
];
|
||||
});
|
||||
|
||||
@Effect() undoLastNotification$: Observable<Action> = this.actions$
|
||||
.ofType(ActionTypes.UNDO_LAST)
|
||||
.map(toPayload)
|
||||
.mergeMap((action: Action) => [action, new DismissUndoNotificationAction()]);
|
||||
|
||||
constructor(private actions$: Actions,
|
||||
private notifierService: NotifierService,
|
||||
private appUpdateRendererService: AppUpdateRendererService,
|
||||
private appRendererService: AppRendererService,
|
||||
private logService: LogService) { }
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Actions, Effect, toPayload } from '@ngrx/effects';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { Action, Store } from '@ngrx/store';
|
||||
|
||||
import 'rxjs/add/operator/startWith';
|
||||
import 'rxjs/add/operator/switchMap';
|
||||
import 'rxjs/add/operator/withLatestFrom';
|
||||
import 'rxjs/add/operator/map';
|
||||
|
||||
import { NotificationType } from 'uhk-common';
|
||||
|
||||
import {
|
||||
ActionTypes,
|
||||
LoadAutoUpdateSettingsAction,
|
||||
LoadAutoUpdateSettingsSuccessAction,
|
||||
SaveAutoUpdateSettingsSuccessAction
|
||||
} from '../actions/auto-update-settings';
|
||||
|
||||
import { DataStorageRepositoryService } from '../../services/datastorage-repository.service';
|
||||
import { AppState, getAutoUpdateSettings } from '../index';
|
||||
import { initialState } from '../reducers/auto-update-settings';
|
||||
import { AutoUpdateSettings } from '../../models/auto-update-settings';
|
||||
import { ShowNotificationAction } from '../actions/app';
|
||||
|
||||
@Injectable()
|
||||
export class AutoUpdateSettingsEffects {
|
||||
@Effect() loadUserConfig$: Observable<Action> = this.actions$
|
||||
.ofType(ActionTypes.LOAD_AUTO_UPDATE_SETTINGS)
|
||||
.startWith(new LoadAutoUpdateSettingsAction())
|
||||
.switchMap(() => {
|
||||
let settings: AutoUpdateSettings = this.dataStorageRepository.getAutoUpdateSettings();
|
||||
if (!settings) {
|
||||
settings = initialState;
|
||||
}
|
||||
return Observable.of(new LoadAutoUpdateSettingsSuccessAction(settings));
|
||||
});
|
||||
|
||||
@Effect() saveAutoUpdateConfig$: Observable<Action> = this.actions$
|
||||
.ofType(ActionTypes.TOGGLE_CHECK_FOR_UPDATE_ON_STARTUP, ActionTypes.TOGGLE_PRE_RELEASE_FLAG)
|
||||
.withLatestFrom(this.store.select(getAutoUpdateSettings))
|
||||
.map(([action, config]) => {
|
||||
this.dataStorageRepository.saveAutoUpdateSettings(config);
|
||||
return new SaveAutoUpdateSettingsSuccessAction();
|
||||
});
|
||||
|
||||
@Effect() sendNotification$: Observable<Action> = this.actions$
|
||||
.ofType(ActionTypes.CHECK_FOR_UPDATE_FAILED, ActionTypes.CHECK_FOR_UPDATE_SUCCESS)
|
||||
.map(toPayload)
|
||||
.map((message: string) => {
|
||||
return new ShowNotificationAction({
|
||||
type: NotificationType.Info,
|
||||
message
|
||||
});
|
||||
});
|
||||
|
||||
constructor(private actions$: Actions,
|
||||
private dataStorageRepository: DataStorageRepositoryService,
|
||||
private store: Store<AppState>) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { Action } from '@ngrx/store';
|
||||
import { Actions, Effect, toPayload } from '@ngrx/effects';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
|
||||
import 'rxjs/add/operator/do';
|
||||
import 'rxjs/add/operator/map';
|
||||
import 'rxjs/add/operator/mergeMap';
|
||||
|
||||
import { NotificationType, IpcResponse } from 'uhk-common';
|
||||
import { ActionTypes, ConnectionStateChangedAction, PermissionStateChangedAction } from '../actions/device';
|
||||
import { DeviceRendererService } from '../../services/device-renderer.service';
|
||||
import { ShowNotificationAction } from '../actions/app';
|
||||
|
||||
@Injectable()
|
||||
export class DeviceEffects {
|
||||
@Effect({ dispatch: false })
|
||||
deviceConnectionStateChange$: Observable<Action> = this.actions$
|
||||
.ofType(ActionTypes.CONNECTION_STATE_CHANGED)
|
||||
.map(toPayload)
|
||||
.do((connected: boolean) => {
|
||||
if (connected) {
|
||||
this.router.navigate(['/']);
|
||||
}
|
||||
else {
|
||||
this.router.navigate(['/detection']);
|
||||
}
|
||||
});
|
||||
|
||||
@Effect({ dispatch: false })
|
||||
permissionStateChange$: Observable<Action> = this.actions$
|
||||
.ofType(ActionTypes.PERMISSION_STATE_CHANGED)
|
||||
.map(toPayload)
|
||||
.do((hasPermission: boolean) => {
|
||||
if (hasPermission) {
|
||||
this.router.navigate(['/detection']);
|
||||
}
|
||||
else {
|
||||
this.router.navigate(['/privilege']);
|
||||
}
|
||||
});
|
||||
|
||||
@Effect({ dispatch: false })
|
||||
setPrivilegeOnLinux$: Observable<Action> = this.actions$
|
||||
.ofType(ActionTypes.SET_PRIVILEGE_ON_LINUX)
|
||||
.do(() => {
|
||||
this.deviceRendererService.setPrivilegeOnLinux();
|
||||
});
|
||||
|
||||
@Effect()
|
||||
setPrivilegeOnLinuxReply$: Observable<Action> = this.actions$
|
||||
.ofType(ActionTypes.SET_PRIVILEGE_ON_LINUX_REPLY)
|
||||
.map(toPayload)
|
||||
.mergeMap((response: any) => {
|
||||
if (response.success) {
|
||||
return [
|
||||
new ConnectionStateChangedAction(true),
|
||||
new PermissionStateChangedAction(true)
|
||||
];
|
||||
}
|
||||
return [
|
||||
<any>new ShowNotificationAction({
|
||||
type: NotificationType.Error,
|
||||
message: response.error.message
|
||||
})
|
||||
];
|
||||
});
|
||||
|
||||
@Effect({ dispatch: false })
|
||||
saveConfiguration$: Observable<Action> = this.actions$
|
||||
.ofType(ActionTypes.SAVE_CONFIGURATION)
|
||||
.map(toPayload)
|
||||
.do((buffer: Buffer) => {
|
||||
this.deviceRendererService.saveUserConfiguration(buffer);
|
||||
});
|
||||
|
||||
@Effect()
|
||||
saveConfigurationReply$: Observable<Action> = this.actions$
|
||||
.ofType(ActionTypes.SAVE_CONFIGURATION_REPLY)
|
||||
.map(toPayload)
|
||||
.map((response: IpcResponse) => {
|
||||
if (response.success) {
|
||||
return new ShowNotificationAction({
|
||||
type: NotificationType.Success,
|
||||
message: 'Save configuration successful.'
|
||||
});
|
||||
}
|
||||
|
||||
return new ShowNotificationAction({
|
||||
type: NotificationType.Error,
|
||||
message: response.error.message
|
||||
});
|
||||
});
|
||||
|
||||
constructor(private actions$: Actions,
|
||||
private router: Router,
|
||||
private deviceRendererService: DeviceRendererService) {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export * from './keymap';
|
||||
export * from './macro';
|
||||
export * from './user-config';
|
||||
export * from './auto-update-settings';
|
||||
export * from './app';
|
||||
@@ -0,0 +1,68 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
import { Actions, Effect } from '@ngrx/effects';
|
||||
import { Action, Store } from '@ngrx/store';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
|
||||
import 'rxjs/add/operator/do';
|
||||
import 'rxjs/add/operator/map';
|
||||
import 'rxjs/add/operator/startWith';
|
||||
import 'rxjs/add/operator/switchMap';
|
||||
import 'rxjs/add/operator/withLatestFrom';
|
||||
import 'rxjs/add/observable/of';
|
||||
|
||||
import { KeymapActions } from '../actions';
|
||||
import { AppState } from '../index';
|
||||
|
||||
import { Keymap } from '../../config-serializer/config-items/keymap';
|
||||
|
||||
@Injectable()
|
||||
export class KeymapEffects {
|
||||
|
||||
@Effect() loadKeymaps$: Observable<Action> = this.actions$
|
||||
.ofType(KeymapActions.LOAD_KEYMAPS)
|
||||
.startWith(KeymapActions.loadKeymaps())
|
||||
.switchMap(() => {
|
||||
const presetsRequireContext = (<any>require).context('../../../res/presets', false, /.json$/);
|
||||
const uhkPresets = presetsRequireContext.keys().map(presetsRequireContext) // load the presets into an array
|
||||
.map((keymap: any) => new Keymap().fromJsonObject(keymap));
|
||||
|
||||
return Observable.of(KeymapActions.loadKeymapsSuccess(uhkPresets));
|
||||
});
|
||||
|
||||
@Effect({ dispatch: false }) addOrDuplicate$: any = this.actions$
|
||||
.ofType(KeymapActions.ADD, KeymapActions.DUPLICATE)
|
||||
.withLatestFrom(this.store)
|
||||
.map(latest => latest[1].userConfiguration.keymaps)
|
||||
.do(keymaps => {
|
||||
this.router.navigate(['/keymap', keymaps[keymaps.length - 1].abbreviation]);
|
||||
});
|
||||
|
||||
@Effect({ dispatch: false }) remove$: any = this.actions$
|
||||
.ofType(KeymapActions.REMOVE)
|
||||
.withLatestFrom(this.store)
|
||||
.map(latest => latest[1].userConfiguration.keymaps)
|
||||
.do(keymaps => {
|
||||
if (keymaps.length === 0) {
|
||||
this.router.navigate(['/keymap/add']);
|
||||
} else {
|
||||
const favourite: Keymap = keymaps.find(keymap => keymap.isDefault);
|
||||
this.router.navigate(['/keymap', favourite.abbreviation]);
|
||||
}
|
||||
});
|
||||
|
||||
@Effect({ dispatch: false }) editAbbr$: any = this.actions$
|
||||
.ofType(KeymapActions.EDIT_ABBR)
|
||||
.withLatestFrom(this.store)
|
||||
.do(([action, store]) => {
|
||||
for (const keymap of store.userConfiguration.keymaps) {
|
||||
if (keymap.name === action.payload.name && keymap.abbreviation === action.payload.newAbbr) {
|
||||
this.router.navigate(['/keymap', action.payload.newAbbr]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
constructor(private actions$: Actions, private router: Router, private store: Store<AppState>) { }
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
import { Actions, Effect } from '@ngrx/effects';
|
||||
import { Store } from '@ngrx/store';
|
||||
|
||||
import 'rxjs/add/operator/do';
|
||||
import 'rxjs/add/operator/map';
|
||||
import 'rxjs/add/operator/withLatestFrom';
|
||||
|
||||
import { KeymapActions, MacroActions } from '../actions';
|
||||
import { AppState } from '../index';
|
||||
|
||||
@Injectable()
|
||||
export class MacroEffects {
|
||||
|
||||
@Effect({ dispatch: false }) remove$: any = this.actions$
|
||||
.ofType(MacroActions.REMOVE)
|
||||
.map(action => this.store.dispatch(KeymapActions.checkMacro(action.payload)))
|
||||
.withLatestFrom(this.store)
|
||||
.map(([action, state]) => state.userConfiguration.macros)
|
||||
.do(macros => {
|
||||
if (macros.length === 0) {
|
||||
this.router.navigate(['/macro']);
|
||||
} else {
|
||||
this.router.navigate(['/macro', macros[0].id]);
|
||||
}
|
||||
});
|
||||
|
||||
@Effect({ dispatch: false }) add$: any = this.actions$
|
||||
.ofType(MacroActions.ADD)
|
||||
.withLatestFrom(this.store)
|
||||
.map(([action, state]) => state.userConfiguration.macros)
|
||||
.map(macros => macros[macros.length - 1])
|
||||
.do(lastMacro => {
|
||||
this.router.navigate(['/macro', lastMacro.id, 'new']);
|
||||
});
|
||||
|
||||
@Effect({ dispatch: false }) duplicate: any = this.actions$
|
||||
.ofType(MacroActions.DUPLICATE)
|
||||
.withLatestFrom(this.store)
|
||||
.map(([action, state]) => state.userConfiguration.macros)
|
||||
.map(macros => macros[macros.length - 1])
|
||||
.do(lastMacro => {
|
||||
this.router.navigate(['/macro', lastMacro.id]);
|
||||
});
|
||||
|
||||
constructor(private actions$: Actions, private router: Router, private store: Store<AppState>) {}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { go } from '@ngrx/router-store';
|
||||
import { Actions, Effect, toPayload } from '@ngrx/effects';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { Action, Store } from '@ngrx/store';
|
||||
|
||||
import 'rxjs/add/operator/map';
|
||||
import 'rxjs/add/operator/switchMap';
|
||||
import 'rxjs/add/operator/startWith';
|
||||
import 'rxjs/add/operator/withLatestFrom';
|
||||
import 'rxjs/add/operator/mergeMap';
|
||||
import 'rxjs/add/observable/of';
|
||||
|
||||
import { NotificationType } from 'uhk-common';
|
||||
|
||||
import {
|
||||
ActionTypes,
|
||||
LoadUserConfigAction,
|
||||
LoadUserConfigSuccessAction,
|
||||
SaveUserConfigSuccessAction
|
||||
} from '../actions/user-config';
|
||||
|
||||
import { UserConfiguration } from '../../config-serializer/config-items/user-configuration';
|
||||
import { DataStorageRepositoryService } from '../../services/datastorage-repository.service';
|
||||
import { DefaultUserConfigurationService } from '../../services/default-user-configuration.service';
|
||||
import { AppState, getPrevUserConfiguration, getUserConfiguration } from '../index';
|
||||
import { KeymapActions } from '../actions/keymap';
|
||||
import { MacroActions } from '../actions/macro';
|
||||
import { UndoUserConfigData } from '../../models/undo-user-config-data';
|
||||
import { ShowNotificationAction, DismissUndoNotificationAction } from '../actions/app';
|
||||
|
||||
@Injectable()
|
||||
export class UserConfigEffects {
|
||||
|
||||
@Effect() loadUserConfig$: Observable<Action> = this.actions$
|
||||
.ofType(ActionTypes.LOAD_USER_CONFIG)
|
||||
.startWith(new LoadUserConfigAction())
|
||||
.switchMap(() => Observable.of(new LoadUserConfigSuccessAction(this.getUserConfiguration())));
|
||||
|
||||
@Effect() saveUserConfig$: Observable<Action> = this.actions$
|
||||
.ofType(
|
||||
KeymapActions.ADD, KeymapActions.DUPLICATE, KeymapActions.EDIT_NAME, KeymapActions.EDIT_ABBR,
|
||||
KeymapActions.SET_DEFAULT, KeymapActions.REMOVE, KeymapActions.SAVE_KEY,
|
||||
MacroActions.ADD, MacroActions.DUPLICATE, MacroActions.EDIT_NAME, MacroActions.REMOVE, MacroActions.ADD_ACTION,
|
||||
MacroActions.SAVE_ACTION, MacroActions.DELETE_ACTION, MacroActions.REORDER_ACTION)
|
||||
.withLatestFrom(this.store.select(getUserConfiguration), this.store.select(getPrevUserConfiguration))
|
||||
.mergeMap(([action, config, prevUserConfiguration]) => {
|
||||
this.dataStorageRepository.saveConfig(config);
|
||||
|
||||
if (action.type === KeymapActions.REMOVE || action.type === MacroActions.REMOVE) {
|
||||
const text = action.type === KeymapActions.REMOVE ? 'Keymap' : 'Macro';
|
||||
const pathPrefix = action.type === KeymapActions.REMOVE ? 'keymap' : 'macro';
|
||||
const payload: UndoUserConfigData = {
|
||||
path: `/${pathPrefix}/${action.payload}`,
|
||||
config: prevUserConfiguration.toJsonObject()
|
||||
};
|
||||
|
||||
return [
|
||||
new SaveUserConfigSuccessAction(config),
|
||||
new ShowNotificationAction({
|
||||
type: NotificationType.Undoable,
|
||||
message: `${text} has been deleted`,
|
||||
extra: {
|
||||
payload,
|
||||
type: KeymapActions.UNDO_LAST_ACTION
|
||||
}
|
||||
})
|
||||
];
|
||||
}
|
||||
|
||||
return [new SaveUserConfigSuccessAction(config), new DismissUndoNotificationAction()];
|
||||
});
|
||||
|
||||
@Effect() undoUserConfig$: Observable<Action> = this.actions$
|
||||
.ofType(KeymapActions.UNDO_LAST_ACTION)
|
||||
.map(toPayload)
|
||||
.mergeMap((payload: UndoUserConfigData) => {
|
||||
const config = new UserConfiguration().fromJsonObject(payload.config);
|
||||
this.dataStorageRepository.saveConfig(config);
|
||||
return [new LoadUserConfigSuccessAction(config), go(payload.path)];
|
||||
});
|
||||
|
||||
constructor(private actions$: Actions,
|
||||
private dataStorageRepository: DataStorageRepositoryService,
|
||||
private store: Store<AppState>,
|
||||
private defaultUserConfigurationService: DefaultUserConfigurationService) {
|
||||
}
|
||||
|
||||
private getUserConfiguration() {
|
||||
const configJsonObject = this.dataStorageRepository.getConfig();
|
||||
let config: UserConfiguration;
|
||||
|
||||
if (configJsonObject) {
|
||||
if (configJsonObject.dataModelVersion === this.defaultUserConfigurationService.getDefault().dataModelVersion) {
|
||||
config = new UserConfiguration().fromJsonObject(configJsonObject);
|
||||
}
|
||||
}
|
||||
|
||||
if (!config) {
|
||||
config = this.defaultUserConfigurationService.getDefault();
|
||||
}
|
||||
|
||||
return config;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
import { createSelector } from 'reselect';
|
||||
import { compose } from '@ngrx/core/compose';
|
||||
import { ActionReducer, combineReducers } from '@ngrx/store';
|
||||
import { RouterState, routerReducer } from '@ngrx/router-store';
|
||||
import { storeFreeze } from 'ngrx-store-freeze';
|
||||
|
||||
import userConfigurationReducer from './reducers/user-configuration';
|
||||
import presetReducer from './reducers/preset';
|
||||
import { Keymap } from '../config-serializer/config-items/keymap';
|
||||
import { UserConfiguration } from '../config-serializer/config-items/user-configuration';
|
||||
import * as fromAppUpdate from './reducers/app-update.reducer';
|
||||
import * as autoUpdateSettings from './reducers/auto-update-settings';
|
||||
import * as fromApp from './reducers/app.reducer';
|
||||
import * as fromDevice from './reducers/device';
|
||||
|
||||
export const reducers = {
|
||||
userConfiguration: userConfigurationReducer,
|
||||
presetKeymaps: presetReducer,
|
||||
router: routerReducer,
|
||||
autoUpdateSettings: autoUpdateSettings.reducer,
|
||||
app: fromApp.reducer,
|
||||
appUpdate: fromAppUpdate.reducer,
|
||||
device: fromDevice.reducer
|
||||
};
|
||||
|
||||
// State interface for the application
|
||||
export interface AppState {
|
||||
userConfiguration: UserConfiguration;
|
||||
presetKeymaps: Keymap[];
|
||||
autoUpdateSettings: autoUpdateSettings.State;
|
||||
app: fromApp.State;
|
||||
router: RouterState;
|
||||
appUpdate: fromAppUpdate.State;
|
||||
device: fromDevice.State;
|
||||
}
|
||||
|
||||
const developmentReducer: ActionReducer<AppState> = compose(storeFreeze, combineReducers)(reducers);
|
||||
const productionReducer: ActionReducer<AppState> = combineReducers(reducers);
|
||||
|
||||
export function reducer(state: any, action: any) {
|
||||
// if (isDev) {
|
||||
// return developmentReducer(state, action);
|
||||
// } else {
|
||||
return productionReducer(state, action);
|
||||
// }
|
||||
}
|
||||
|
||||
export const getUserConfiguration = (state: AppState) => state.userConfiguration;
|
||||
|
||||
export const appState = (state: AppState) => state.app;
|
||||
export const showAddonMenu = createSelector(appState, fromApp.showAddonMenu);
|
||||
export const getUndoableNotification = createSelector(appState, fromApp.getUndoableNotification);
|
||||
export const getPrevUserConfiguration = createSelector(appState, fromApp.getPrevUserConfiguration);
|
||||
export const runningInElectron = createSelector(appState, fromApp.runningInElectron);
|
||||
|
||||
export const appUpdateState = (state: AppState) => state.appUpdate;
|
||||
export const getShowAppUpdateAvailable = createSelector(appUpdateState, fromAppUpdate.getShowAppUpdateAvailable);
|
||||
|
||||
export const appUpdateSettingsState = (state: AppState) => state.autoUpdateSettings;
|
||||
export const getAutoUpdateSettings = createSelector(appUpdateSettingsState, autoUpdateSettings.getUpdateSettings);
|
||||
export const getCheckingForUpdate = createSelector(appUpdateSettingsState, autoUpdateSettings.checkingForUpdate);
|
||||
|
||||
export const deviceState = (state: AppState) => state.device;
|
||||
export const isDeviceConnected = createSelector(deviceState, fromDevice.isDeviceConnected);
|
||||
export const deviceConnected = createSelector(runningInElectron, isDeviceConnected, (electron, connected) => {
|
||||
return !electron ? true : connected;
|
||||
});
|
||||
export const devicePermission = createSelector(deviceState, fromDevice.hasDevicePermission);
|
||||
export const hasDevicePermission = createSelector(runningInElectron, devicePermission, (electron, permission) => {
|
||||
return !electron ? true : permission;
|
||||
});
|
||||
@@ -0,0 +1,39 @@
|
||||
import { Actions, ActionTypes } from '../actions/app-update.action';
|
||||
|
||||
export interface State {
|
||||
updateAvailable: boolean;
|
||||
updateDownloaded: boolean;
|
||||
doNotUpdateApp: boolean;
|
||||
}
|
||||
|
||||
const initialState: State = {
|
||||
updateAvailable: false,
|
||||
updateDownloaded: false,
|
||||
doNotUpdateApp: false
|
||||
};
|
||||
|
||||
export function reducer(state = initialState, action: Actions) {
|
||||
switch (action.type) {
|
||||
case ActionTypes.UPDATE_AVAILABLE: {
|
||||
const newState = Object.assign({}, state);
|
||||
newState.updateAvailable = true;
|
||||
return newState;
|
||||
}
|
||||
|
||||
case ActionTypes.UPDATE_DOWNLOADED: {
|
||||
const newState = Object.assign({}, state);
|
||||
newState.updateDownloaded = true;
|
||||
return newState;
|
||||
}
|
||||
|
||||
case ActionTypes.DO_NOT_UPDATE_APP: {
|
||||
const newState = Object.assign({}, state);
|
||||
newState.doNotUpdateApp = true;
|
||||
return newState;
|
||||
}
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
export const getShowAppUpdateAvailable = (state: State) => state.updateDownloaded && !state.doNotUpdateApp;
|
||||
@@ -0,0 +1,91 @@
|
||||
import { routerActions } from '@ngrx/router-store';
|
||||
import { Action } from '@ngrx/store';
|
||||
|
||||
import { runInElectron, Notification, NotificationType } from 'uhk-common';
|
||||
import { ActionTypes, ShowNotificationAction } from '../actions/app';
|
||||
import { ActionTypes as UserConfigActionTypes } from '../actions/user-config';
|
||||
import { UserConfiguration } from '../../config-serializer/config-items/user-configuration';
|
||||
|
||||
export interface State {
|
||||
started: boolean;
|
||||
showAddonMenu: boolean;
|
||||
undoableNotification?: Notification;
|
||||
navigationCountAfterNotification: number;
|
||||
prevUserConfig?: UserConfiguration;
|
||||
runningInElectron: boolean;
|
||||
}
|
||||
|
||||
const initialState: State = {
|
||||
started: false,
|
||||
showAddonMenu: false,
|
||||
navigationCountAfterNotification: 0,
|
||||
runningInElectron: runInElectron()
|
||||
};
|
||||
|
||||
export function reducer(state = initialState, action: Action) {
|
||||
switch (action.type) {
|
||||
case ActionTypes.APP_STARTED: {
|
||||
return {
|
||||
...state,
|
||||
started: true
|
||||
};
|
||||
}
|
||||
|
||||
case ActionTypes.APP_TOGGLE_ADDON_MENU: {
|
||||
return {
|
||||
...state,
|
||||
showAddonMenu: action.payload
|
||||
};
|
||||
}
|
||||
|
||||
case ActionTypes.APP_SHOW_NOTIFICATION: {
|
||||
const currentAction = <ShowNotificationAction>action;
|
||||
if (currentAction.payload.type !== NotificationType.Undoable) {
|
||||
return state;
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
undoableNotification: currentAction.payload,
|
||||
navigationCountAfterNotification: 0
|
||||
};
|
||||
}
|
||||
|
||||
// Required to dismiss the undoNotification dialog, when user navigate in the app.
|
||||
// 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.
|
||||
case routerActions.UPDATE_LOCATION: {
|
||||
const newState = { ...state };
|
||||
newState.navigationCountAfterNotification++;
|
||||
|
||||
if (newState.navigationCountAfterNotification > 1) {
|
||||
newState.undoableNotification = null;
|
||||
}
|
||||
|
||||
return newState;
|
||||
}
|
||||
|
||||
case ActionTypes.UNDO_LAST_SUCCESS:
|
||||
case ActionTypes.DISMISS_UNDO_NOTIFICATION: {
|
||||
return {
|
||||
...state,
|
||||
undoableNotification: null
|
||||
};
|
||||
}
|
||||
|
||||
case UserConfigActionTypes.LOAD_USER_CONFIG_SUCCESS:
|
||||
case UserConfigActionTypes.SAVE_USER_CONFIG_SUCCESS: {
|
||||
return {
|
||||
...state,
|
||||
prevUserConfig: action.payload
|
||||
};
|
||||
}
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
export const showAddonMenu = (state: State) => state.showAddonMenu;
|
||||
export const getUndoableNotification = (state: State) => state.undoableNotification;
|
||||
export const getPrevUserConfiguration = (state: State) => state.prevUserConfig;
|
||||
export const runningInElectron = (state: State) => state.runningInElectron;
|
||||
@@ -0,0 +1,50 @@
|
||||
import { Action } from '@ngrx/store';
|
||||
import { ActionTypes } from '../actions/auto-update-settings';
|
||||
import { ActionTypes as UpdateActions } from '../actions/app-update.action';
|
||||
import { AutoUpdateSettings } from '../../models/auto-update-settings';
|
||||
|
||||
export interface State extends AutoUpdateSettings {
|
||||
checkingForUpdate: boolean;
|
||||
}
|
||||
|
||||
export const initialState: State = {
|
||||
checkForUpdateOnStartUp: false,
|
||||
usePreReleaseUpdate: false,
|
||||
checkingForUpdate: false
|
||||
};
|
||||
|
||||
export function reducer(state = initialState, action: Action): State {
|
||||
switch (action.type) {
|
||||
case ActionTypes.TOGGLE_CHECK_FOR_UPDATE_ON_STARTUP: {
|
||||
return Object.assign({}, state, { checkForUpdateOnStartUp: action.payload });
|
||||
}
|
||||
|
||||
case ActionTypes.TOGGLE_PRE_RELEASE_FLAG: {
|
||||
return Object.assign({}, state, { usePreReleaseUpdate: action.payload });
|
||||
}
|
||||
|
||||
case ActionTypes.LOAD_AUTO_UPDATE_SETTINGS_SUCCESS: {
|
||||
return Object.assign({}, action.payload);
|
||||
}
|
||||
|
||||
case ActionTypes.CHECK_FOR_UPDATE_NOW: {
|
||||
return Object.assign({}, state, { checkingForUpdate: true});
|
||||
}
|
||||
|
||||
case UpdateActions.UPDATE_ERROR:
|
||||
case ActionTypes.CHECK_FOR_UPDATE_SUCCESS:
|
||||
case ActionTypes.CHECK_FOR_UPDATE_FAILED: {
|
||||
return Object.assign({}, state, { checkingForUpdate: false });
|
||||
}
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
export const getUpdateSettings = (state: State) => ({
|
||||
checkForUpdateOnStartUp: state.checkForUpdateOnStartUp,
|
||||
usePreReleaseUpdate: state.usePreReleaseUpdate
|
||||
});
|
||||
|
||||
export const checkingForUpdate = (state: State) => state.checkingForUpdate;
|
||||
@@ -0,0 +1,35 @@
|
||||
import { Action } from '@ngrx/store';
|
||||
|
||||
import { ActionTypes } from '../actions/device';
|
||||
|
||||
export interface State {
|
||||
connected: boolean;
|
||||
hasPermission: boolean;
|
||||
}
|
||||
|
||||
const initialState: State = {
|
||||
connected: true,
|
||||
hasPermission: true
|
||||
};
|
||||
|
||||
export function reducer(state = initialState, action: Action) {
|
||||
switch (action.type) {
|
||||
case ActionTypes.CONNECTION_STATE_CHANGED:
|
||||
return {
|
||||
...state,
|
||||
connected: action.payload
|
||||
};
|
||||
|
||||
case ActionTypes.PERMISSION_STATE_CHANGED:
|
||||
return {
|
||||
...state,
|
||||
hasPermission: action.payload
|
||||
};
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
export const isDeviceConnected = (state: State) => state.connected;
|
||||
export const hasDevicePermission = (state: State) => state.hasPermission;
|
||||
@@ -0,0 +1,12 @@
|
||||
import { routerReducer } from '@ngrx/router-store';
|
||||
|
||||
import userConfigurationReducer from './user-configuration';
|
||||
import presetReducer from './preset';
|
||||
import { reducer as autoUpdateReducer } from './auto-update-settings';
|
||||
import { reducer as appReducer } from './app.reducer';
|
||||
import * as fromAppUpdate from './app-update.reducer';
|
||||
import * as fromDevice from './device';
|
||||
|
||||
export { userConfigurationReducer, presetReducer, autoUpdateReducer, appReducer };
|
||||
|
||||
// All reducers that are used in application
|
||||
@@ -0,0 +1,17 @@
|
||||
import { Action } from '@ngrx/store';
|
||||
|
||||
import { Keymap } from '../../config-serializer/config-items/keymap';
|
||||
import { KeymapActions } from '../actions/keymap';
|
||||
|
||||
const initialState: Keymap[] = [];
|
||||
|
||||
export default function(state = initialState, action: Action): Keymap[] {
|
||||
switch (action.type) {
|
||||
case KeymapActions.LOAD_KEYMAPS_SUCCESS: {
|
||||
return action.payload;
|
||||
}
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,364 @@
|
||||
import '@ngrx/core/add/operator/select';
|
||||
import { Action } from '@ngrx/store';
|
||||
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import 'rxjs/add/observable/of';
|
||||
import 'rxjs/add/operator/map';
|
||||
|
||||
import { Helper as KeyActionHelper } from '../../config-serializer/config-items/key-action';
|
||||
import { Keymap } from '../../config-serializer/config-items/keymap';
|
||||
import { Macro } from '../../config-serializer/config-items/macro';
|
||||
import { UserConfiguration } from '../../config-serializer/config-items/user-configuration';
|
||||
import { Layer } from '../../config-serializer/config-items/layer';
|
||||
import { Module } from '../../config-serializer/config-items/module';
|
||||
import { KeymapActions, MacroActions } from '../actions';
|
||||
import { AppState } from '../index';
|
||||
import { ActionTypes } from '../actions/user-config';
|
||||
|
||||
const initialState: UserConfiguration = new UserConfiguration();
|
||||
|
||||
export default function (state = initialState, action: Action): UserConfiguration {
|
||||
const changedUserConfiguration: UserConfiguration = Object.assign(new UserConfiguration(), state);
|
||||
|
||||
switch (action.type) {
|
||||
case ActionTypes.LOAD_USER_CONFIG_SUCCESS: {
|
||||
return Object.assign(changedUserConfiguration, action.payload);
|
||||
}
|
||||
|
||||
case KeymapActions.ADD:
|
||||
case KeymapActions.DUPLICATE: {
|
||||
const newKeymap: Keymap = new Keymap(action.payload);
|
||||
newKeymap.abbreviation = generateAbbr(state.keymaps, newKeymap.abbreviation);
|
||||
newKeymap.name = generateName(state.keymaps, newKeymap.name);
|
||||
newKeymap.isDefault = (state.keymaps.length === 0);
|
||||
|
||||
changedUserConfiguration.keymaps = state.keymaps.concat(newKeymap);
|
||||
break;
|
||||
}
|
||||
case KeymapActions.EDIT_NAME: {
|
||||
const name: string = action.payload.name.toUpperCase();
|
||||
|
||||
const duplicate = state.keymaps.some((keymap: Keymap) => {
|
||||
return keymap.name === name && keymap.abbreviation !== action.payload.abbr;
|
||||
});
|
||||
|
||||
changedUserConfiguration.keymaps = state.keymaps.map((keymap: Keymap) => {
|
||||
keymap = Object.assign(new Keymap(), keymap);
|
||||
|
||||
if (!duplicate && keymap.abbreviation === action.payload.abbr) {
|
||||
keymap.name = name;
|
||||
}
|
||||
return keymap;
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
case KeymapActions.EDIT_ABBR: {
|
||||
const abbr: string = action.payload.newAbbr.toUpperCase();
|
||||
|
||||
const duplicate = state.keymaps.some((keymap: Keymap) => {
|
||||
return keymap.name !== action.payload.name && keymap.abbreviation === abbr;
|
||||
});
|
||||
|
||||
changedUserConfiguration.keymaps = state.keymaps.map((keymap: Keymap) => {
|
||||
keymap = Object.assign(new Keymap(), keymap);
|
||||
if (!duplicate && keymap.abbreviation === action.payload.abbr) {
|
||||
keymap.abbreviation = abbr;
|
||||
} else {
|
||||
keymap = keymap.renameKeymap(action.payload.abbr, action.payload.newAbbr);
|
||||
}
|
||||
|
||||
return keymap;
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case KeymapActions.SET_DEFAULT:
|
||||
changedUserConfiguration.keymaps = state.keymaps.map((keymap: Keymap) => {
|
||||
if (keymap.abbreviation === action.payload || keymap.isDefault) {
|
||||
keymap = Object.assign(new Keymap(), keymap);
|
||||
keymap.isDefault = keymap.abbreviation === action.payload;
|
||||
}
|
||||
|
||||
return keymap;
|
||||
});
|
||||
break;
|
||||
case KeymapActions.REMOVE:
|
||||
let isDefault: boolean;
|
||||
|
||||
const filtered: Keymap[] = state.keymaps.filter((keymap: Keymap) => {
|
||||
if (keymap.abbreviation === action.payload) {
|
||||
isDefault = keymap.isDefault;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
// If deleted one is default set default keymap to the first on the list of keymaps
|
||||
if (isDefault && filtered.length > 0) {
|
||||
filtered[0] = Object.assign(new Keymap(), filtered[0], {
|
||||
isDefault: true
|
||||
});
|
||||
}
|
||||
|
||||
// Check for the deleted keymap in other keymaps
|
||||
changedUserConfiguration.keymaps = filtered.map(keymap => {
|
||||
keymap = Object.assign(new Keymap(), keymap);
|
||||
keymap.layers = checkExistence(keymap.layers, 'keymapAbbreviation', action.payload);
|
||||
|
||||
return keymap;
|
||||
});
|
||||
break;
|
||||
|
||||
case KeymapActions.SAVE_KEY: {
|
||||
const newKeymap: Keymap = Object.assign(new Keymap(), action.payload.keymap);
|
||||
newKeymap.layers = newKeymap.layers.slice();
|
||||
|
||||
const layerIndex: number = action.payload.layer;
|
||||
const newLayer: Layer = Object.assign(new Layer(), newKeymap.layers[layerIndex]);
|
||||
newKeymap.layers[layerIndex] = newLayer;
|
||||
|
||||
const moduleIndex: number = action.payload.module;
|
||||
const newModule: Module = Object.assign(new Module(), newLayer.modules[moduleIndex]);
|
||||
newLayer.modules = newLayer.modules.slice();
|
||||
newLayer.modules[moduleIndex] = newModule;
|
||||
|
||||
const keyIndex: number = action.payload.key;
|
||||
newModule.keyActions = newModule.keyActions.slice();
|
||||
newModule.keyActions[keyIndex] = KeyActionHelper.createKeyAction(action.payload.keyAction);
|
||||
|
||||
changedUserConfiguration.keymaps = state.keymaps.map(keymap => {
|
||||
if (keymap.abbreviation === newKeymap.abbreviation) {
|
||||
keymap = newKeymap;
|
||||
}
|
||||
|
||||
return keymap;
|
||||
});
|
||||
break;
|
||||
}
|
||||
case KeymapActions.CHECK_MACRO:
|
||||
changedUserConfiguration.keymaps = state.keymaps.map(keymap => {
|
||||
keymap = Object.assign(new Keymap(), keymap);
|
||||
keymap.layers = checkExistence(keymap.layers, '_macroId', action.payload);
|
||||
return keymap;
|
||||
});
|
||||
break;
|
||||
case MacroActions.ADD: {
|
||||
const newMacro = new Macro();
|
||||
newMacro.id = generateMacroId(state.macros);
|
||||
newMacro.name = generateName(state.macros, 'New macro');
|
||||
newMacro.isLooped = false;
|
||||
newMacro.isPrivate = true;
|
||||
newMacro.macroActions = [];
|
||||
|
||||
changedUserConfiguration.macros = state.macros.concat(newMacro);
|
||||
break;
|
||||
}
|
||||
case MacroActions.DUPLICATE: {
|
||||
const newMacro = new Macro(action.payload);
|
||||
newMacro.name = generateName(state.macros, newMacro.name);
|
||||
newMacro.id = generateMacroId(state.macros);
|
||||
|
||||
changedUserConfiguration.macros = state.macros.concat(newMacro);
|
||||
break;
|
||||
}
|
||||
case MacroActions.EDIT_NAME: {
|
||||
const name: string = action.payload.name;
|
||||
|
||||
const duplicate = state.macros.some((macro: Macro) => {
|
||||
return macro.id !== action.payload.id && macro.name === name;
|
||||
});
|
||||
|
||||
changedUserConfiguration.macros = state.macros.map((macro: Macro) => {
|
||||
macro = Object.assign(new Macro(), macro);
|
||||
if (!duplicate && macro.id === action.payload.id) {
|
||||
macro.name = name;
|
||||
}
|
||||
|
||||
return macro;
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
case MacroActions.REMOVE:
|
||||
changedUserConfiguration.macros = state.macros.filter((macro: Macro) => macro.id !== action.payload);
|
||||
break;
|
||||
case MacroActions.ADD_ACTION:
|
||||
changedUserConfiguration.macros = state.macros.map((macro: Macro) => {
|
||||
if (macro.id === action.payload.id) {
|
||||
macro = new Macro(macro);
|
||||
macro.macroActions.push(action.payload.action);
|
||||
}
|
||||
|
||||
return macro;
|
||||
});
|
||||
break;
|
||||
case MacroActions.SAVE_ACTION:
|
||||
changedUserConfiguration.macros = state.macros.map((macro: Macro) => {
|
||||
if (macro.id === action.payload.id) {
|
||||
macro = new Macro(macro);
|
||||
macro.macroActions[action.payload.index] = action.payload.action;
|
||||
}
|
||||
|
||||
return macro;
|
||||
});
|
||||
break;
|
||||
case MacroActions.DELETE_ACTION:
|
||||
changedUserConfiguration.macros = state.macros.map((macro: Macro) => {
|
||||
if (macro.id === action.payload.id) {
|
||||
macro = new Macro(macro);
|
||||
macro.macroActions.splice(action.payload.index, 1);
|
||||
}
|
||||
|
||||
return macro;
|
||||
});
|
||||
break;
|
||||
case MacroActions.REORDER_ACTION:
|
||||
changedUserConfiguration.macros = state.macros.map((macro: Macro) => {
|
||||
if (macro.id === action.payload.id) {
|
||||
let newIndex: number = action.payload.newIndex;
|
||||
|
||||
// We need to reduce the new index for one when we are moving action down
|
||||
if (newIndex > action.payload.oldIndex) {
|
||||
--newIndex;
|
||||
}
|
||||
|
||||
macro = new Macro(macro);
|
||||
macro.macroActions.splice(
|
||||
newIndex,
|
||||
0,
|
||||
macro.macroActions.splice(action.payload.oldIndex, 1)[0]
|
||||
);
|
||||
}
|
||||
|
||||
return macro;
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return changedUserConfiguration;
|
||||
}
|
||||
|
||||
export function getUserConfiguration(): (state$: Observable<AppState>) => Observable<UserConfiguration> {
|
||||
return (state$: Observable<AppState>) => state$
|
||||
.select(state => state.userConfiguration);
|
||||
}
|
||||
|
||||
export function getKeymaps(): (state$: Observable<AppState>) => Observable<Keymap[]> {
|
||||
return (state$: Observable<AppState>) => state$
|
||||
.select(state => state.userConfiguration.keymaps);
|
||||
}
|
||||
|
||||
export function getKeymap(abbr: string) {
|
||||
if (abbr === undefined) {
|
||||
return getDefaultKeymap();
|
||||
}
|
||||
|
||||
return (state$: Observable<AppState>) => getKeymaps()(state$)
|
||||
.map((keymaps: Keymap[]) =>
|
||||
keymaps.find((keymap: Keymap) => keymap.abbreviation === abbr)
|
||||
);
|
||||
}
|
||||
|
||||
export function getDefaultKeymap() {
|
||||
return (state$: Observable<AppState>) => getKeymaps()(state$)
|
||||
.map((keymaps: Keymap[]) =>
|
||||
keymaps.find((keymap: Keymap) => keymap.isDefault)
|
||||
);
|
||||
}
|
||||
|
||||
export function getMacros(): (state$: Observable<AppState>) => Observable<Macro[]> {
|
||||
return (state$: Observable<AppState>) => state$
|
||||
.select(state => state.userConfiguration.macros);
|
||||
}
|
||||
|
||||
export function getMacro(id: number) {
|
||||
if (isNaN(id)) {
|
||||
return () => Observable.of<Macro>(undefined);
|
||||
} else {
|
||||
return (state$: Observable<AppState>) => getMacros()(state$)
|
||||
.map((macros: Macro[]) => macros.find((macro: Macro) => macro.id === id));
|
||||
}
|
||||
}
|
||||
|
||||
function generateAbbr(keymaps: Keymap[], abbr: string): string {
|
||||
const chars: string[] = '23456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
|
||||
let position = 0;
|
||||
|
||||
while (keymaps.some((keymap: Keymap) => keymap.abbreviation === abbr)) {
|
||||
abbr = abbr.substring(0, abbr.length - 1) + chars[position];
|
||||
++position;
|
||||
}
|
||||
|
||||
return abbr;
|
||||
}
|
||||
|
||||
function generateName(items: { name: string }[], name: string) {
|
||||
let suffix = 1;
|
||||
const regexp = / \(\d+\)$/g;
|
||||
const matchName = name.replace(regexp, '');
|
||||
items.forEach(item => {
|
||||
if (item.name.replace(regexp, '') === matchName) {
|
||||
suffix++;
|
||||
}
|
||||
});
|
||||
return `${matchName} (${suffix})`;
|
||||
}
|
||||
|
||||
function generateMacroId(macros: Macro[]) {
|
||||
let newId = 0;
|
||||
|
||||
macros.forEach((macro: Macro) => {
|
||||
if (macro.id > newId) {
|
||||
newId = macro.id;
|
||||
}
|
||||
});
|
||||
|
||||
return newId + 1;
|
||||
}
|
||||
|
||||
function checkExistence(layers: Layer[], property: string, value: any): Layer[] {
|
||||
const keyActionsToClear: {
|
||||
layerIdx: number,
|
||||
moduleIdx: number,
|
||||
keyActionIdx: number
|
||||
}[] = [];
|
||||
for (let layerIdx = 0; layerIdx < layers.length; ++layerIdx) {
|
||||
const modules = layers[layerIdx].modules;
|
||||
for (let moduleIdx = 0; moduleIdx < modules.length; ++moduleIdx) {
|
||||
const keyActions = modules[moduleIdx].keyActions;
|
||||
for (let keyActionIdx = 0; keyActionIdx < keyActions.length; ++keyActionIdx) {
|
||||
const action = keyActions[keyActionIdx];
|
||||
if (action && action.hasOwnProperty(property) && action[property] === value) {
|
||||
keyActionsToClear.push({
|
||||
layerIdx,
|
||||
moduleIdx,
|
||||
keyActionIdx
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (keyActionsToClear.length === 0) {
|
||||
return layers;
|
||||
}
|
||||
|
||||
const newLayers = [...layers];
|
||||
for (const path of keyActionsToClear) {
|
||||
if (newLayers[path.layerIdx] === layers[path.layerIdx]) {
|
||||
newLayers[path.layerIdx] = Object.assign(new Layer(), newLayers[path.layerIdx]);
|
||||
newLayers[path.layerIdx].modules = [...newLayers[path.layerIdx].modules];
|
||||
}
|
||||
const newModules = newLayers[path.layerIdx].modules;
|
||||
if (newModules[path.moduleIdx] === layers[path.layerIdx].modules[path.moduleIdx]) {
|
||||
newModules[path.moduleIdx] = Object.assign(new Module(), newModules[path.moduleIdx]);
|
||||
newModules[path.moduleIdx].keyActions = [...newModules[path.moduleIdx].keyActions];
|
||||
}
|
||||
newModules[path.moduleIdx].keyActions[path.keyActionIdx] = undefined;
|
||||
}
|
||||
|
||||
return newLayers;
|
||||
}
|
||||
Reference in New Issue
Block a user