refactor(store): Refactor reducer initialisation (#298)
* refactor(store): Refactor reducer initialization Refactored the ngrx/store reducer initialization, because hard to extend the original solution. Bad practise the object initialization inside the components / services. The new solution use angular DI everywhere. Separated the web and electron configuration store. * Media key support (#294) * Introduce type for KeystrokeAction * Increment dataModelVersion New property 'type' for KeystrokeAction * Mapping for media keys * Media key selecting support for KeypressTab * refactor: Use more meaningful name (selectedScancodeOption) * Store the keystroke type in key action type instead of a new field * Fix NoneAction validation Fixes #301 * Update electron version It fixes electron build. The types are part of the electron package itself. * Fix keystroke selection when additional field is given but no scancode (#306) * Additional media keys with icons (#307) * Add missing scancodes for media keystrokes * Use icons for media keys * Fix media scancodes. * Create README.md * build: upgrade electron and typescript version Electron contains the typings files. * refactor(store): Refactor reducer initialization Refactored the ngrx/store reducer initialization, because hard to extend the original solution. Bad practise the object initialization inside the components / services. The new solution use angular DI everywhere. Separated the web and electron configuration store. * build: upgrade electron and typescript version Electron contains the typings files. * fix(store): Remove the I prefix from IDataStorageRepositoryService * fix(store): fix observer operator import * fix(store): Add missing rxjs imports to user-config effect * fix(store): Add missing rxjs imports to keymap effect
This commit is contained in:
committed by
László Monda
parent
679e20d915
commit
367bc42457
+14
-18
@@ -1,4 +1,4 @@
|
|||||||
import { NgModule, ReflectiveInjector } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
@@ -7,6 +7,7 @@ import { EffectsModule } from '@ngrx/effects';
|
|||||||
import { StoreModule } from '@ngrx/store';
|
import { StoreModule } from '@ngrx/store';
|
||||||
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
|
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
|
||||||
import { StoreLogMonitorModule, useLogMonitor } from '@ngrx/store-log-monitor';
|
import { StoreLogMonitorModule, useLogMonitor } from '@ngrx/store-log-monitor';
|
||||||
|
import { RouterStoreModule } from '@ngrx/router-store';
|
||||||
|
|
||||||
import { DragulaModule } from 'ng2-dragula/ng2-dragula';
|
import { DragulaModule } from 'ng2-dragula/ng2-dragula';
|
||||||
import { Select2Module } from 'ng2-select2/ng2-select2';
|
import { Select2Module } from 'ng2-select2/ng2-select2';
|
||||||
@@ -73,9 +74,7 @@ import { CaptureService } from './shared/services/capture.service';
|
|||||||
import { MapperService } from './shared/services/mapper.service';
|
import { MapperService } from './shared/services/mapper.service';
|
||||||
import { UhkDeviceService } from './services/uhk-device.service';
|
import { UhkDeviceService } from './services/uhk-device.service';
|
||||||
|
|
||||||
import { KeymapEffects, MacroEffects } from './shared/store/effects';
|
import { KeymapEffects, MacroEffects, UserConfigEffects} from './shared/store/effects';
|
||||||
import { userConfigurationReducer, presetReducer } from './shared/store/reducers';
|
|
||||||
import { DataStorage } from './shared/store/storage';
|
|
||||||
|
|
||||||
import { KeymapEditGuard } from './shared/components/keymap/edit';
|
import { KeymapEditGuard } from './shared/components/keymap/edit';
|
||||||
import { MacroNotFoundGuard } from './shared/components/macro/not-found';
|
import { MacroNotFoundGuard } from './shared/components/macro/not-found';
|
||||||
@@ -84,17 +83,10 @@ 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 { UhkDeviceInitializedGuard } from './services/uhk-device-initialized.guard';
|
import { UhkDeviceInitializedGuard } from './services/uhk-device-initialized.guard';
|
||||||
import { UhkDeviceUninitializedGuard } from './services/uhk-device-uninitialized.guard';
|
import { UhkDeviceUninitializedGuard } from './services/uhk-device-uninitialized.guard';
|
||||||
|
import { DATA_STORAGE_REPOSITORY } from './shared/services/datastorage-repository.service';
|
||||||
// Create DataStorage dependency injection
|
import { ElectronDataStorageRepositoryService } from './services/electron-datastorage-repository.service';
|
||||||
const storageProvider = ReflectiveInjector.resolve([DataStorage]);
|
import { DefaultUserConfigurationService } from './shared/services/default-user-configuration.service';
|
||||||
const storageInjector = ReflectiveInjector.fromResolvedProviders(storageProvider);
|
import { reducer } from '../../shared/src/store/reducers/index';
|
||||||
const storageService: DataStorage = storageInjector.get(DataStorage);
|
|
||||||
|
|
||||||
// All reducers that are used in application
|
|
||||||
const storeConfig = {
|
|
||||||
userConfiguration: storageService.saveState(userConfigurationReducer),
|
|
||||||
presetKeymaps: presetReducer
|
|
||||||
};
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@@ -156,7 +148,8 @@ const storeConfig = {
|
|||||||
FormsModule,
|
FormsModule,
|
||||||
DragulaModule,
|
DragulaModule,
|
||||||
routing,
|
routing,
|
||||||
StoreModule.provideStore(storeConfig, storageService.initialState()),
|
StoreModule.provideStore(reducer),
|
||||||
|
RouterStoreModule.connectRouter(),
|
||||||
StoreDevtoolsModule.instrumentStore({
|
StoreDevtoolsModule.instrumentStore({
|
||||||
monitor: useLogMonitor({
|
monitor: useLogMonitor({
|
||||||
visible: false,
|
visible: false,
|
||||||
@@ -166,7 +159,8 @@ const storeConfig = {
|
|||||||
StoreLogMonitorModule,
|
StoreLogMonitorModule,
|
||||||
Select2Module,
|
Select2Module,
|
||||||
EffectsModule.runAfterBootstrap(KeymapEffects),
|
EffectsModule.runAfterBootstrap(KeymapEffects),
|
||||||
EffectsModule.runAfterBootstrap(MacroEffects)
|
EffectsModule.runAfterBootstrap(MacroEffects),
|
||||||
|
EffectsModule.runAfterBootstrap(UserConfigEffects)
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
UhkDeviceConnectedGuard,
|
UhkDeviceConnectedGuard,
|
||||||
@@ -178,7 +172,9 @@ const storeConfig = {
|
|||||||
KeymapEditGuard,
|
KeymapEditGuard,
|
||||||
MacroNotFoundGuard,
|
MacroNotFoundGuard,
|
||||||
CaptureService,
|
CaptureService,
|
||||||
UhkDeviceService
|
UhkDeviceService,
|
||||||
|
{provide: DATA_STORAGE_REPOSITORY, useClass: ElectronDataStorageRepositoryService},
|
||||||
|
DefaultUserConfigurationService
|
||||||
],
|
],
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
})
|
})
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
import { UserConfiguration } from '../../config-serializer/config-items/UserConfiguration';
|
import { UserConfiguration } from '../shared/config-serializer/config-items/UserConfiguration';
|
||||||
|
|
||||||
export class Electron {
|
export class ElectronDataStorageRepositoryService {
|
||||||
getConfig(): UserConfiguration {
|
getConfig(): UserConfiguration {
|
||||||
// TODO implement load logic
|
// TODO implement load logic
|
||||||
return;
|
return;
|
||||||
+2
-1
@@ -51,6 +51,7 @@
|
|||||||
"@angular/router": "4.0.3",
|
"@angular/router": "4.0.3",
|
||||||
"@ngrx/core": "1.2.0",
|
"@ngrx/core": "1.2.0",
|
||||||
"@ngrx/effects": "2.0.3",
|
"@ngrx/effects": "2.0.3",
|
||||||
|
"@ngrx/router-store": "^1.2.6",
|
||||||
"@ngrx/store": "2.2.2",
|
"@ngrx/store": "2.2.2",
|
||||||
"bootstrap": "^3.3.7",
|
"bootstrap": "^3.3.7",
|
||||||
"browser-stdout": "^1.3.0",
|
"browser-stdout": "^1.3.0",
|
||||||
@@ -66,7 +67,7 @@
|
|||||||
"rxjs": "5.3.0",
|
"rxjs": "5.3.0",
|
||||||
"select2": "^4.0.3",
|
"select2": "^4.0.3",
|
||||||
"sudo-prompt": "^7.0.0",
|
"sudo-prompt": "^7.0.0",
|
||||||
"typescript": "2.2.2",
|
"typescript": "2.3.4",
|
||||||
"usb": "git+https://github.com/aktary/node-usb.git",
|
"usb": "git+https://github.com/aktary/node-usb.git",
|
||||||
"xml-loader": "1.2.1",
|
"xml-loader": "1.2.1",
|
||||||
"zone.js": "0.8.5"
|
"zone.js": "0.8.5"
|
||||||
|
|||||||
@@ -24,7 +24,9 @@ export class KeymapEditGuard implements CanActivate {
|
|||||||
.let(getKeymaps())
|
.let(getKeymaps())
|
||||||
.do((keymaps: Keymap[]) => {
|
.do((keymaps: Keymap[]) => {
|
||||||
const defaultKeymap = keymaps.find(keymap => keymap.isDefault);
|
const defaultKeymap = keymaps.find(keymap => keymap.isDefault);
|
||||||
this.router.navigate(['/keymap', defaultKeymap.abbreviation]);
|
if (defaultKeymap) {
|
||||||
|
this.router.navigate(['/keymap', defaultKeymap.abbreviation]);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.switchMap(() => Observable.of(false));
|
.switchMap(() => Observable.of(false));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ export class UserConfiguration {
|
|||||||
@assertUInt16
|
@assertUInt16
|
||||||
dataModelVersion: number;
|
dataModelVersion: number;
|
||||||
|
|
||||||
moduleConfigurations: ModuleConfiguration[];
|
moduleConfigurations: ModuleConfiguration[] = [];
|
||||||
|
|
||||||
keymaps: Keymap[];
|
keymaps: Keymap[] = [];
|
||||||
|
|
||||||
macros: Macro[];
|
macros: Macro[] = [];
|
||||||
|
|
||||||
fromJsonObject(jsonObject: any): UserConfiguration {
|
fromJsonObject(jsonObject: any): UserConfiguration {
|
||||||
this.dataModelVersion = jsonObject.dataModelVersion;
|
this.dataModelVersion = jsonObject.dataModelVersion;
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { InjectionToken } from '@angular/core';
|
||||||
|
|
||||||
|
import { UserConfiguration } from '../config-serializer/config-items/UserConfiguration';
|
||||||
|
|
||||||
|
export interface DataStorageRepositoryService {
|
||||||
|
|
||||||
|
getConfig(): UserConfiguration;
|
||||||
|
|
||||||
|
saveConfig(config: UserConfiguration): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export let DATA_STORAGE_REPOSITORY = new InjectionToken('dataStorage-repository');
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { UserConfiguration } from '../config-serializer/config-items/UserConfiguration';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class DefaultUserConfigurationService {
|
||||||
|
private _defaultConfig: UserConfiguration;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this._defaultConfig = new UserConfiguration()
|
||||||
|
.fromJsonObject(require('json-loader!../config-serializer/user-config.json'));
|
||||||
|
}
|
||||||
|
|
||||||
|
getDefault(): UserConfiguration {
|
||||||
|
return this._defaultConfig;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { UserConfiguration } from '../config-serializer/config-items/UserConfiguration';
|
||||||
|
import { DataStorageRepositoryService } from './datastorage-repository.service';
|
||||||
|
import { DefaultUserConfigurationService } from './default-user-configuration.service';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class LocalDataStorageRepositoryService implements DataStorageRepositoryService {
|
||||||
|
constructor(private defaultUserConfigurationService: DefaultUserConfigurationService) { }
|
||||||
|
|
||||||
|
getConfig(): UserConfiguration {
|
||||||
|
const configJsonString = localStorage.getItem('config');
|
||||||
|
let config: UserConfiguration;
|
||||||
|
|
||||||
|
if (configJsonString) {
|
||||||
|
const configJsonObject = JSON.parse(configJsonString);
|
||||||
|
if (configJsonObject.dataModelVersion === this.defaultUserConfigurationService.getDefault().dataModelVersion) {
|
||||||
|
config = new UserConfiguration().fromJsonObject(configJsonObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
saveConfig(config: UserConfiguration): void {
|
||||||
|
localStorage.setItem('config', JSON.stringify(config.toJsonObject()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,6 +14,21 @@ export namespace KeymapActions {
|
|||||||
export const SET_DEFAULT = KeymapActions.PREFIX + 'Set default option';
|
export const SET_DEFAULT = KeymapActions.PREFIX + 'Set default option';
|
||||||
export const REMOVE = KeymapActions.PREFIX + 'Remove keymap';
|
export const REMOVE = KeymapActions.PREFIX + 'Remove keymap';
|
||||||
export const CHECK_MACRO = KeymapActions.PREFIX + 'Check deleted macro';
|
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 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 {
|
export function addKeymap(item: Keymap): Action {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { Action } from '@ngrx/store';
|
||||||
|
|
||||||
|
import { type } from '../../util';
|
||||||
|
import { UserConfiguration } from '../../config-serializer/config-items/UserConfiguration';
|
||||||
|
|
||||||
|
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')
|
||||||
|
};
|
||||||
|
|
||||||
|
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 type Actions
|
||||||
|
= LoadUserConfigAction
|
||||||
|
| LoadUserConfigSuccessAction;
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
export * from './keymap';
|
export * from './keymap';
|
||||||
export * from './macro';
|
export * from './macro';
|
||||||
|
export * from './user-config';
|
||||||
|
|||||||
@@ -2,11 +2,15 @@ import { Injectable } from '@angular/core';
|
|||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
import { Actions, Effect } from '@ngrx/effects';
|
import { Actions, Effect } from '@ngrx/effects';
|
||||||
import { Store } from '@ngrx/store';
|
import { Action, Store } from '@ngrx/store';
|
||||||
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
|
||||||
import 'rxjs/add/operator/do';
|
import 'rxjs/add/operator/do';
|
||||||
import 'rxjs/add/operator/map';
|
import 'rxjs/add/operator/map';
|
||||||
|
import 'rxjs/add/operator/startWith';
|
||||||
|
import 'rxjs/add/operator/switchMap';
|
||||||
import 'rxjs/add/operator/withLatestFrom';
|
import 'rxjs/add/operator/withLatestFrom';
|
||||||
|
import 'rxjs/add/observable/of';
|
||||||
|
|
||||||
import { KeymapActions } from '../actions';
|
import { KeymapActions } from '../actions';
|
||||||
import { AppState } from '../index';
|
import { AppState } from '../index';
|
||||||
@@ -16,6 +20,17 @@ import { Keymap } from '../../config-serializer/config-items/Keymap';
|
|||||||
@Injectable()
|
@Injectable()
|
||||||
export class KeymapEffects {
|
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$
|
@Effect({ dispatch: false }) addOrDuplicate$: any = this.actions$
|
||||||
.ofType(KeymapActions.ADD, KeymapActions.DUPLICATE)
|
.ofType(KeymapActions.ADD, KeymapActions.DUPLICATE)
|
||||||
.withLatestFrom(this.store)
|
.withLatestFrom(this.store)
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { Injectable, Inject } from '@angular/core';
|
||||||
|
import { Effect, Actions } from '@ngrx/effects';
|
||||||
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
import { Action } from '@ngrx/store';
|
||||||
|
|
||||||
|
import 'rxjs/add/operator/switchMap';
|
||||||
|
import 'rxjs/add/operator/startWith';
|
||||||
|
import 'rxjs/add/observable/of';
|
||||||
|
|
||||||
|
import { ActionTypes, LoadUserConfigAction, LoadUserConfigSuccessAction } from '../actions/user-config';
|
||||||
|
import { UserConfiguration } from '../../config-serializer/config-items/UserConfiguration';
|
||||||
|
import { DataStorageRepositoryService, DATA_STORAGE_REPOSITORY } from '../../services/datastorage-repository.service';
|
||||||
|
import { DefaultUserConfigurationService } from '../../services/default-user-configuration.service';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class UserConfigEffects {
|
||||||
|
|
||||||
|
@Effect() loadUserConfig$: Observable<Action> = this.actions$
|
||||||
|
.ofType(ActionTypes.LOAD_USER_CONFIG)
|
||||||
|
.startWith(new LoadUserConfigAction())
|
||||||
|
.switchMap(() => {
|
||||||
|
let config: UserConfiguration = this.dataStorageRepository.getConfig();
|
||||||
|
if (!config) {
|
||||||
|
config = this.defaultUserConfigurationService.getDefault();
|
||||||
|
}
|
||||||
|
return Observable.of(new LoadUserConfigSuccessAction(config));
|
||||||
|
});
|
||||||
|
|
||||||
|
constructor(private actions$: Actions,
|
||||||
|
@Inject(DATA_STORAGE_REPOSITORY)private dataStorageRepository: DataStorageRepositoryService,
|
||||||
|
private defaultUserConfigurationService: DefaultUserConfigurationService) { }
|
||||||
|
}
|
||||||
@@ -1,4 +1,11 @@
|
|||||||
import userConfigurationReducer, { getUserConfiguration } from './user-configuration';
|
import { routerReducer } from '@ngrx/router-store';
|
||||||
|
|
||||||
|
import userConfigurationReducer from './user-configuration';
|
||||||
import presetReducer from './preset';
|
import presetReducer from './preset';
|
||||||
|
|
||||||
export { userConfigurationReducer, presetReducer, getUserConfiguration };
|
// All reducers that are used in application
|
||||||
|
export const reducer = {
|
||||||
|
userConfiguration: userConfigurationReducer,
|
||||||
|
presetKeymaps: presetReducer,
|
||||||
|
router: routerReducer
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,7 +1,17 @@
|
|||||||
|
import { Action } from '@ngrx/store';
|
||||||
|
|
||||||
import { Keymap } from '../../config-serializer/config-items/Keymap';
|
import { Keymap } from '../../config-serializer/config-items/Keymap';
|
||||||
|
import { KeymapActions } from '../actions/keymap';
|
||||||
|
|
||||||
const initialState: Keymap[] = [];
|
const initialState: Keymap[] = [];
|
||||||
|
|
||||||
export default function(state = initialState): Keymap[] {
|
export default function(state = initialState, action: Action): Keymap[] {
|
||||||
return state;
|
switch (action.type) {
|
||||||
|
case KeymapActions.LOAD_KEYMAPS_SUCCESS: {
|
||||||
|
return Object.assign(state, action.payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { Layer } from '../../config-serializer/config-items/Layer';
|
|||||||
import { Module } from '../../config-serializer/config-items/Module';
|
import { Module } from '../../config-serializer/config-items/Module';
|
||||||
import { KeymapActions, MacroActions } from '../actions';
|
import { KeymapActions, MacroActions } from '../actions';
|
||||||
import { AppState } from '../index';
|
import { AppState } from '../index';
|
||||||
|
import { ActionTypes } from '../actions/user-config';
|
||||||
|
|
||||||
const initialState: UserConfiguration = new UserConfiguration();
|
const initialState: UserConfiguration = new UserConfiguration();
|
||||||
|
|
||||||
@@ -23,6 +24,10 @@ export default function (state = initialState, action: Action): UserConfiguratio
|
|||||||
const changedUserConfiguration: UserConfiguration = Object.assign(new UserConfiguration(), state);
|
const changedUserConfiguration: UserConfiguration = Object.assign(new UserConfiguration(), state);
|
||||||
|
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
case ActionTypes.LOAD_USER_CONFIG_SUCCESS: {
|
||||||
|
return Object.assign(changedUserConfiguration, action.payload);
|
||||||
|
}
|
||||||
|
|
||||||
case KeymapActions.ADD:
|
case KeymapActions.ADD:
|
||||||
case KeymapActions.DUPLICATE:
|
case KeymapActions.DUPLICATE:
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,69 +0,0 @@
|
|||||||
import { Injectable } from '@angular/core';
|
|
||||||
|
|
||||||
import { Action } from '@ngrx/store';
|
|
||||||
|
|
||||||
import { Keymap } from '../../config-serializer/config-items/Keymap';
|
|
||||||
import { UserConfiguration } from '../../config-serializer/config-items/UserConfiguration';
|
|
||||||
|
|
||||||
import { AppState } from '../index';
|
|
||||||
import { Electron } from './electron';
|
|
||||||
import { Local } from './local';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class DataStorage {
|
|
||||||
|
|
||||||
private _environment: Local | Electron;
|
|
||||||
private defaultUserConfiguration: UserConfiguration;
|
|
||||||
private uhkPresets: Keymap[];
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.initUHKJson();
|
|
||||||
this.detectEnvironment();
|
|
||||||
}
|
|
||||||
|
|
||||||
initialState(): AppState {
|
|
||||||
const config: UserConfiguration = this.getConfiguration();
|
|
||||||
return {
|
|
||||||
userConfiguration: config,
|
|
||||||
presetKeymaps: this.uhkPresets
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
detectEnvironment(): void {
|
|
||||||
// Electron
|
|
||||||
// TODO check if we can remove <any> when electron will be implemented (maybe use process.versions['electron'])
|
|
||||||
if (typeof window !== 'undefined' && (<any>window).process && (<any>window).process.type === 'renderer') {
|
|
||||||
this._environment = new Electron();
|
|
||||||
}
|
|
||||||
// Local storage
|
|
||||||
else {
|
|
||||||
this._environment = new Local(this.defaultUserConfiguration.dataModelVersion);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Add type for state
|
|
||||||
saveState(reducer: any): (state: any, action: Action) => AppState {
|
|
||||||
return (state: any, action: Action) => {
|
|
||||||
const nextState = reducer(state, action);
|
|
||||||
this._environment.saveConfig(nextState);
|
|
||||||
return nextState;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
initUHKJson() {
|
|
||||||
this.defaultUserConfiguration = new UserConfiguration()
|
|
||||||
.fromJsonObject(require('json-loader!../../config-serializer/user-config.json'));
|
|
||||||
|
|
||||||
const presetsRequireContext = (<any>require).context('../../../res/presets', false, /.json$/);
|
|
||||||
this.uhkPresets = presetsRequireContext.keys().map(presetsRequireContext) // load the presets into an array
|
|
||||||
.map((keymap: any) => new Keymap().fromJsonObject(keymap));
|
|
||||||
}
|
|
||||||
|
|
||||||
getConfiguration(): UserConfiguration {
|
|
||||||
let config: UserConfiguration = this._environment.getConfig();
|
|
||||||
if (!config) {
|
|
||||||
config = this.defaultUserConfiguration;
|
|
||||||
}
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
import { UserConfiguration } from '../../config-serializer/config-items/UserConfiguration';
|
|
||||||
|
|
||||||
export class Local {
|
|
||||||
|
|
||||||
constructor(private dataModelVersion: number) { }
|
|
||||||
|
|
||||||
getConfig(): UserConfiguration {
|
|
||||||
const configJsonString = localStorage.getItem('config');
|
|
||||||
let config: UserConfiguration;
|
|
||||||
|
|
||||||
if (configJsonString) {
|
|
||||||
const configJsonObject = JSON.parse(configJsonString);
|
|
||||||
if (configJsonObject.dataModelVersion === this.dataModelVersion) {
|
|
||||||
config = new UserConfiguration().fromJsonObject(configJsonObject);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
saveConfig(config: UserConfiguration): void {
|
|
||||||
localStorage.setItem('config', JSON.stringify(config.toJsonObject()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,3 +8,24 @@ export function camelCaseToSentence(camelCasedText: string): string {
|
|||||||
export function capitalizeFirstLetter(text: string): string {
|
export function capitalizeFirstLetter(text: string): string {
|
||||||
return text.charAt(0).toUpperCase() + text.slice(1);
|
return text.charAt(0).toUpperCase() + text.slice(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function coerces a string into a string literal type.
|
||||||
|
* Using tagged union types in TypeScript 2.0, this enables
|
||||||
|
* powerful typechecking of our reducers.
|
||||||
|
*
|
||||||
|
* Since every action label passes through this function it
|
||||||
|
* is a good place to ensure all of our action labels
|
||||||
|
* are unique.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const typeCache: { [label: string]: boolean } = {};
|
||||||
|
export function type<T>(label: T | ''): T {
|
||||||
|
if (typeCache[<string>label]) {
|
||||||
|
throw new Error(`Action type "${label}" is not unique"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
typeCache[<string>label] = true;
|
||||||
|
|
||||||
|
return <T>label;
|
||||||
|
}
|
||||||
|
|||||||
+14
-18
@@ -1,4 +1,4 @@
|
|||||||
import { NgModule, ReflectiveInjector } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
@@ -7,6 +7,7 @@ import { EffectsModule } from '@ngrx/effects';
|
|||||||
import { StoreModule } from '@ngrx/store';
|
import { StoreModule } from '@ngrx/store';
|
||||||
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
|
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
|
||||||
import { StoreLogMonitorModule, useLogMonitor } from '@ngrx/store-log-monitor';
|
import { StoreLogMonitorModule, useLogMonitor } from '@ngrx/store-log-monitor';
|
||||||
|
import { RouterStoreModule } from '@ngrx/router-store';
|
||||||
|
|
||||||
import { DragulaModule } from 'ng2-dragula/ng2-dragula';
|
import { DragulaModule } from 'ng2-dragula/ng2-dragula';
|
||||||
import { Select2Module } from 'ng2-select2/ng2-select2';
|
import { Select2Module } from 'ng2-select2/ng2-select2';
|
||||||
@@ -66,23 +67,14 @@ import { CancelableDirective } from './shared/directives';
|
|||||||
import { CaptureService } from './shared/services/capture.service';
|
import { CaptureService } from './shared/services/capture.service';
|
||||||
import { MapperService } from './shared/services/mapper.service';
|
import { MapperService } from './shared/services/mapper.service';
|
||||||
|
|
||||||
import { KeymapEffects, MacroEffects } from './shared/store/effects';
|
import { KeymapEffects, MacroEffects, UserConfigEffects } from './shared/store/effects';
|
||||||
import { userConfigurationReducer, presetReducer } from './shared/store/reducers';
|
|
||||||
import { DataStorage } from './shared/store/storage';
|
|
||||||
|
|
||||||
import { KeymapEditGuard } from './shared/components/keymap/edit';
|
import { KeymapEditGuard } from './shared/components/keymap/edit';
|
||||||
import { MacroNotFoundGuard } from './shared/components/macro/not-found';
|
import { MacroNotFoundGuard } from './shared/components/macro/not-found';
|
||||||
|
import { DATA_STORAGE_REPOSITORY } from './shared/services/datastorage-repository.service';
|
||||||
// Create DataStorage dependency injection
|
import { LocalDataStorageRepositoryService } from './shared/services/local-datastorage-repository.service';
|
||||||
const storageProvider = ReflectiveInjector.resolve([DataStorage]);
|
import { DefaultUserConfigurationService } from './shared/services/default-user-configuration.service';
|
||||||
const storageInjector = ReflectiveInjector.fromResolvedProviders(storageProvider);
|
import { reducer } from '../../shared/src/store/reducers/index';
|
||||||
const storageService: DataStorage = storageInjector.get(DataStorage);
|
|
||||||
|
|
||||||
// All reducers that are used in application
|
|
||||||
const storeConfig = {
|
|
||||||
userConfiguration: storageService.saveState(userConfigurationReducer),
|
|
||||||
presetKeymaps: presetReducer
|
|
||||||
};
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@@ -140,7 +132,8 @@ const storeConfig = {
|
|||||||
FormsModule,
|
FormsModule,
|
||||||
DragulaModule,
|
DragulaModule,
|
||||||
routing,
|
routing,
|
||||||
StoreModule.provideStore(storeConfig, storageService.initialState()),
|
StoreModule.provideStore(reducer),
|
||||||
|
RouterStoreModule.connectRouter(),
|
||||||
StoreDevtoolsModule.instrumentStore({
|
StoreDevtoolsModule.instrumentStore({
|
||||||
monitor: useLogMonitor({
|
monitor: useLogMonitor({
|
||||||
visible: false,
|
visible: false,
|
||||||
@@ -150,14 +143,17 @@ const storeConfig = {
|
|||||||
StoreLogMonitorModule,
|
StoreLogMonitorModule,
|
||||||
Select2Module,
|
Select2Module,
|
||||||
EffectsModule.runAfterBootstrap(KeymapEffects),
|
EffectsModule.runAfterBootstrap(KeymapEffects),
|
||||||
EffectsModule.runAfterBootstrap(MacroEffects)
|
EffectsModule.runAfterBootstrap(MacroEffects),
|
||||||
|
EffectsModule.runAfterBootstrap(UserConfigEffects)
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
MapperService,
|
MapperService,
|
||||||
appRoutingProviders,
|
appRoutingProviders,
|
||||||
KeymapEditGuard,
|
KeymapEditGuard,
|
||||||
MacroNotFoundGuard,
|
MacroNotFoundGuard,
|
||||||
CaptureService
|
CaptureService,
|
||||||
|
{provide: DATA_STORAGE_REPOSITORY, useClass: LocalDataStorageRepositoryService},
|
||||||
|
DefaultUserConfigurationService
|
||||||
],
|
],
|
||||||
bootstrap: [MainAppComponent]
|
bootstrap: [MainAppComponent]
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user