Keymap data layer (#95)
This commit is contained in:
committed by
József Farkas
parent
fb8cd163ec
commit
b78bc5850f
2
src/store/actions/index.ts
Normal file
2
src/store/actions/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './keymap';
|
||||
export * from './macro';
|
||||
69
src/store/actions/keymap.ts
Normal file
69
src/store/actions/keymap.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import { Action } from '@ngrx/store';
|
||||
|
||||
import { Keymap } from '../../config-serializer/config-items/Keymap';
|
||||
|
||||
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 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(abbr: string, newAbbr: string): Action {
|
||||
return {
|
||||
type: KeymapActions.EDIT_ABBR,
|
||||
payload: {
|
||||
abbr: abbr,
|
||||
newAbbr: newAbbr
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function saveKey(keymap: Keymap): Action {
|
||||
return {
|
||||
type: KeymapActions.SAVE_KEY,
|
||||
payload: keymap
|
||||
};
|
||||
}
|
||||
}
|
||||
12
src/store/actions/macro.ts
Normal file
12
src/store/actions/macro.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Action } from '@ngrx/store';
|
||||
|
||||
export namespace MacroActions {
|
||||
export const PREFIX = '[Macro] ';
|
||||
export const GET_ALL = MacroActions.PREFIX + 'Get all macros';
|
||||
|
||||
export function getAll(): Action {
|
||||
return {
|
||||
type: MacroActions.GET_ALL
|
||||
};
|
||||
}
|
||||
}
|
||||
32
src/store/effects/keymap.ts
Normal file
32
src/store/effects/keymap.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { Actions, Effect } from '@ngrx/effects';
|
||||
|
||||
import 'rxjs/add/operator/map';
|
||||
|
||||
import { KeymapActions } from '../actions/keymap';
|
||||
|
||||
@Injectable()
|
||||
export class KeymapEffects {
|
||||
|
||||
@Effect()remove$: any = this.actions$
|
||||
.ofType(KeymapActions.REMOVE)
|
||||
.map(() => {
|
||||
// TODO: Waiting for the fix: https://github.com/angular/angular/issues/10770
|
||||
// If state is empty router.navigate(['/keymap']);
|
||||
// Else router.navigate(['/keymap']);
|
||||
});
|
||||
|
||||
@Effect() editAbbr$: any = this.actions$
|
||||
.ofType(KeymapActions.EDIT_ABBR)
|
||||
.map<string>(action => action.payload.abbr)
|
||||
.map((abbr: string) => {
|
||||
console.log(abbr);
|
||||
// TODO: Waiting for the fix: https://github.com/angular/angular/issues/10770
|
||||
// // router.navigate(['/keymap', abbr]);
|
||||
});
|
||||
|
||||
constructor(
|
||||
private actions$: Actions
|
||||
) {}
|
||||
}
|
||||
9
src/store/index.ts
Normal file
9
src/store/index.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { Keymap } from '../config-serializer/config-items/Keymap';
|
||||
import { Macro } from '../config-serializer/config-items/Macro';
|
||||
|
||||
// State interface for the application
|
||||
export interface AppState {
|
||||
keymaps: Keymap[];
|
||||
macros: Macro[];
|
||||
presetKeymaps: Keymap[];
|
||||
}
|
||||
5
src/store/reducers/index.ts
Normal file
5
src/store/reducers/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import keymapReducer from './keymap';
|
||||
import macroReducer from './macro';
|
||||
import presetReducer from './preset';
|
||||
|
||||
export { keymapReducer, macroReducer, presetReducer };
|
||||
134
src/store/reducers/keymap.ts
Normal file
134
src/store/reducers/keymap.ts
Normal file
@@ -0,0 +1,134 @@
|
||||
import '@ngrx/core/add/operator/select';
|
||||
import { Action } from '@ngrx/store';
|
||||
|
||||
import 'rxjs/add/operator/map';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
|
||||
import { Keymap } from '../../config-serializer/config-items/Keymap';
|
||||
import { KeymapActions } from '../actions';
|
||||
import { AppState } from '../index';
|
||||
|
||||
const initialState: Keymap[] = [];
|
||||
|
||||
export default function(state = initialState, action: Action): Keymap[] {
|
||||
switch (action.type) {
|
||||
case KeymapActions.ADD:
|
||||
case KeymapActions.DUPLICATE:
|
||||
|
||||
let newKeymap: Keymap = new Keymap(action.payload);
|
||||
|
||||
newKeymap.abbreviation = generateAbbr(state, newKeymap.abbreviation);
|
||||
newKeymap.name = generateName(state, newKeymap.name);
|
||||
newKeymap.isDefault = false;
|
||||
|
||||
return [...state, newKeymap];
|
||||
|
||||
case KeymapActions.EDIT_NAME:
|
||||
let name: string = generateName(state, action.payload.name);
|
||||
|
||||
return state.map((keymap: Keymap) => {
|
||||
if (keymap.abbreviation === action.payload.abbr) {
|
||||
keymap.name = name;
|
||||
}
|
||||
|
||||
return keymap;
|
||||
});
|
||||
|
||||
case KeymapActions.EDIT_ABBR:
|
||||
let abbr: string = generateAbbr(state, action.payload.newAbbr);
|
||||
|
||||
return state.map((keymap: Keymap) => {
|
||||
if (keymap.abbreviation === action.payload.abbr) {
|
||||
keymap.abbreviation = abbr;
|
||||
}
|
||||
|
||||
return keymap;
|
||||
});
|
||||
|
||||
case KeymapActions.SET_DEFAULT:
|
||||
return state.map((keymap: Keymap) => {
|
||||
keymap.isDefault = (keymap.abbreviation === action.payload);
|
||||
|
||||
return keymap;
|
||||
});
|
||||
|
||||
case KeymapActions.REMOVE:
|
||||
let isDefault: boolean;
|
||||
|
||||
let filtered: Keymap[] = state.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].isDefault = true;
|
||||
}
|
||||
|
||||
return filtered;
|
||||
|
||||
case KeymapActions.SAVE_KEY:
|
||||
let changedKeymap: Keymap = new Keymap;
|
||||
|
||||
return state.map((keymap: Keymap) => {
|
||||
if (keymap.abbreviation === action.payload.abbreviation) {
|
||||
keymap = Object.assign(changedKeymap, action.payload);
|
||||
}
|
||||
|
||||
return keymap;
|
||||
});
|
||||
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getKeymap(abbr: string) {
|
||||
if (abbr === undefined) {
|
||||
return getDefault();
|
||||
}
|
||||
|
||||
return (state$: Observable<AppState>) => state$
|
||||
.select(appState => appState.keymaps)
|
||||
.map((keymaps: Keymap[]) =>
|
||||
keymaps.find((keymap: Keymap) => keymap.abbreviation === abbr)
|
||||
);
|
||||
}
|
||||
|
||||
export function getDefault() {
|
||||
return (state$: Observable<AppState>) => state$
|
||||
.select(appState => appState.keymaps)
|
||||
.map((keymaps: Keymap[]) =>
|
||||
keymaps.find((keymap: Keymap) => keymap.isDefault)
|
||||
);
|
||||
}
|
||||
|
||||
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(keymaps: Keymap[], name: string) {
|
||||
let suffix = 2;
|
||||
const oldName: string = name;
|
||||
|
||||
while (keymaps.some((keymap: Keymap) => keymap.name === name)) {
|
||||
name = oldName + ` (${suffix})`;
|
||||
++suffix;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
16
src/store/reducers/macro.ts
Normal file
16
src/store/reducers/macro.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Action } from '@ngrx/store';
|
||||
|
||||
import { Macro } from '../../config-serializer/config-items/Macro';
|
||||
import { MacroActions } from '../actions';
|
||||
|
||||
const initialState: Macro[] = [];
|
||||
|
||||
export default function(state = initialState, action: Action): Macro[] {
|
||||
switch (action.type) {
|
||||
case MacroActions.GET_ALL:
|
||||
break;
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
}
|
||||
7
src/store/reducers/preset.ts
Normal file
7
src/store/reducers/preset.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { Keymap } from '../../config-serializer/config-items/Keymap';
|
||||
|
||||
const initialState: Keymap[] = [];
|
||||
|
||||
export default function(state = initialState): Keymap[] {
|
||||
return state;
|
||||
}
|
||||
10
src/store/storage/electron.ts
Normal file
10
src/store/storage/electron.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export class Electron {
|
||||
initialState() {
|
||||
// TODO implement load logic
|
||||
}
|
||||
|
||||
/* tslint:disable:no-unused-variable */
|
||||
saveSate(reducer: any): any {
|
||||
// TODO implement save logic
|
||||
}
|
||||
}
|
||||
37
src/store/storage/index.ts
Normal file
37
src/store/storage/index.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { Action } from '@ngrx/store';
|
||||
|
||||
import { AppState } from '../index';
|
||||
import { Electron } from './electron';
|
||||
import { Local } from './local';
|
||||
|
||||
@Injectable()
|
||||
export class DataStorage {
|
||||
|
||||
private _environment: Local | Electron;
|
||||
|
||||
constructor() {
|
||||
this.detectEnvironment();
|
||||
}
|
||||
|
||||
initialState() {
|
||||
return this._environment.initialState();
|
||||
}
|
||||
|
||||
detectEnvironment() {
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
|
||||
saveSate(reducer: any): (state: AppState, action: Action) => AppState {
|
||||
return this._environment.saveSate(reducer);
|
||||
}
|
||||
}
|
||||
67
src/store/storage/local.ts
Normal file
67
src/store/storage/local.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { Action } from '@ngrx/store';
|
||||
|
||||
import { Keymap } from '../../config-serializer/config-items/Keymap';
|
||||
import { Keymaps } from '../../config-serializer/config-items/Keymaps';
|
||||
import { Macro } from '../../config-serializer/config-items/Macro';
|
||||
import { UhkConfiguration } from '../../config-serializer/config-items/UhkConfiguration';
|
||||
|
||||
import { KeymapActions, MacroActions } from '../actions';
|
||||
import { AppState } from '../index';
|
||||
|
||||
export class Local {
|
||||
initialState(): AppState {
|
||||
let config: UhkConfiguration;
|
||||
let presetAll: Keymaps;
|
||||
|
||||
// Load data from json
|
||||
if (!localStorage.getItem('config')) {
|
||||
const jsonUser: JSON = require('json!../../config-serializer/uhk-config.json');
|
||||
const jsonPreset: any = require('json!../../config-serializer/preset-keymaps.json');
|
||||
config = new UhkConfiguration().fromJsObject(jsonUser);
|
||||
presetAll = new Keymaps().fromJsObject(jsonPreset.keymaps);
|
||||
|
||||
// Save to local storage
|
||||
localStorage.setItem('config', JSON.stringify(config.toJsObject()));
|
||||
localStorage.setItem('preset', JSON.stringify(presetAll.toJsObject()));
|
||||
}
|
||||
// Load data from local storage
|
||||
else {
|
||||
config = new UhkConfiguration().fromJsObject(
|
||||
JSON.parse(localStorage.getItem('config'))
|
||||
);
|
||||
presetAll = new Keymaps().fromJsObject(
|
||||
JSON.parse(localStorage.getItem('preset'))
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
keymaps: config.keymaps.elements,
|
||||
macros: config.macros.elements,
|
||||
presetKeymaps: presetAll.elements
|
||||
};
|
||||
}
|
||||
|
||||
saveSate(reducer: any): (state: any, action: Action) => AppState {
|
||||
return function (state: any, action: Action) {
|
||||
let nextState = reducer(state, action);
|
||||
let config: UhkConfiguration;
|
||||
|
||||
// Save elements to the UhkConfiguration
|
||||
if (action.type.startsWith(KeymapActions.PREFIX) && state.length && state[0] instanceof Keymap) {
|
||||
config = new UhkConfiguration().fromJsObject(
|
||||
JSON.parse(localStorage.getItem('config'))
|
||||
);
|
||||
config.keymaps.elements = Object.values(nextState);
|
||||
localStorage.setItem('config', JSON.stringify(config.toJsObject()));
|
||||
} else if (action.type.startsWith(MacroActions.PREFIX) && state.length && state[0] instanceof Macro) {
|
||||
config = new UhkConfiguration().fromJsObject(
|
||||
JSON.parse(localStorage.getItem('config'))
|
||||
);
|
||||
config.macros.elements = Object.values(nextState);
|
||||
localStorage.setItem('config', JSON.stringify(config.toJsObject()));
|
||||
}
|
||||
|
||||
return nextState;
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user