Keymap data layer (#95)
This commit is contained in:
committed by
József Farkas
parent
fb8cd163ec
commit
b78bc5850f
@@ -8,6 +8,8 @@
|
||||
},
|
||||
"license": "GPL-3.0",
|
||||
"devDependencies": {
|
||||
"@ngrx/store-devtools": "3.0.2",
|
||||
"@ngrx/store-log-monitor": "3.0.2",
|
||||
"@types/core-js": "^0.9.32",
|
||||
"@types/jquery": "1.10.31",
|
||||
"@types/node": "6.0.38",
|
||||
@@ -40,6 +42,9 @@
|
||||
"@angular/platform-browser": "2.0.0",
|
||||
"@angular/platform-browser-dynamic": "2.0.0",
|
||||
"@angular/router": "3.0.0",
|
||||
"@ngrx/core": "1.2.0",
|
||||
"@ngrx/effects": "2.0.0-beta.3",
|
||||
"@ngrx/store": "2.2.1",
|
||||
"bootstrap": "^3.3.7",
|
||||
"browser-stdout": "^1.3.0",
|
||||
"core-js": "2.4.1",
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { NgModule, ReflectiveInjector } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
|
||||
import { StoreModule } from '@ngrx/store';
|
||||
|
||||
import { DragulaModule } from 'ng2-dragula/ng2-dragula';
|
||||
import { Select2Component } from 'ng2-select2/ng2-select2';
|
||||
|
||||
import { ContenteditableDirective } from './directives/contenteditable';
|
||||
|
||||
import { KeymapAddComponent, KeymapComponent } from './components/keymap';
|
||||
import { KeymapAddComponent, KeymapComponent, KeymapHeaderComponent } from './components/keymap';
|
||||
import { LayersComponent } from './components/layers';
|
||||
import { LegacyLoaderComponent } from './components/legacy-loader';
|
||||
import {
|
||||
@@ -51,11 +53,30 @@ import { DataProviderService } from './services/data-provider.service';
|
||||
import { MapperService } from './services/mapper.service';
|
||||
import { UhkConfigurationService } from './services/uhk-configuration.service';
|
||||
|
||||
import { DataStorage } from './store/storage';
|
||||
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
|
||||
import { StoreLogMonitorModule, useLogMonitor } from '@ngrx/store-log-monitor';
|
||||
|
||||
import { keymapReducer, macroReducer, presetReducer } from './store/reducers';
|
||||
|
||||
// Create DataStorage dependency injection
|
||||
const storageProvider = ReflectiveInjector.resolve([DataStorage]);
|
||||
const storageInjector = ReflectiveInjector.fromResolvedProviders(storageProvider);
|
||||
const storageService: DataStorage = storageInjector.get(DataStorage);
|
||||
|
||||
// All reducers that are used in application
|
||||
const storeConfig = {
|
||||
keymaps: storageService.saveSate(keymapReducer),
|
||||
macros: storageService.saveSate(macroReducer),
|
||||
presetKeymaps: presetReducer
|
||||
};
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
Select2Component,
|
||||
MainAppComponent,
|
||||
KeymapComponent,
|
||||
KeymapHeaderComponent,
|
||||
LegacyLoaderComponent,
|
||||
NotificationComponent,
|
||||
SvgIconTextKeyComponent,
|
||||
@@ -95,7 +116,15 @@ import { UhkConfigurationService } from './services/uhk-configuration.service';
|
||||
BrowserModule,
|
||||
FormsModule,
|
||||
DragulaModule,
|
||||
routing
|
||||
routing,
|
||||
StoreModule.provideStore(storeConfig, storageService.initialState()),
|
||||
StoreDevtoolsModule.instrumentStore({
|
||||
monitor: useLogMonitor({
|
||||
visible: false,
|
||||
position: 'right'
|
||||
})
|
||||
}),
|
||||
StoreLogMonitorModule
|
||||
],
|
||||
providers: [
|
||||
DataProviderService,
|
||||
|
||||
@@ -10,23 +10,26 @@
|
||||
<input type="text" class="form-control" placeholder="Search ..." (input)="filterKeyboards($event.target.value)">
|
||||
</div>
|
||||
<div class="keymap__search_amount">
|
||||
{{ keymaps.length }} / {{ keymapsAll.length }} keymaps shown
|
||||
{{ (presets$ | async).length }} / {{ (presetsAll$ | async).length }} keymaps shown
|
||||
</div>
|
||||
</div>
|
||||
<div class="keymap__list">
|
||||
<div #keyboard class="keymap__list_item" *ngFor="let keymap of keymaps">
|
||||
<div #keyboard class="keymap__list_item" *ngFor="let keymap of presets$ | async">
|
||||
<h2>{{ keymap.name }}</h2>
|
||||
<p class="keymap__description">
|
||||
{{ keymap.description }}
|
||||
</p>
|
||||
<svg-keyboard-wrap
|
||||
[layers]="keymap.layers.elements"
|
||||
[keymap]="keymap"
|
||||
[popoverEnabled]="false"
|
||||
[tooltipEnabled]="true"
|
||||
>
|
||||
</svg-keyboard-wrap>
|
||||
<div class="btn-group btn-group-lg">
|
||||
<button class="btn btn-default">Add keymap</button>
|
||||
<button class="btn btn-default" (click)="addKeymap(keymap)">Add keymap</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="(presets$ | async).length === 0">
|
||||
Sorry, no keyboard found under this search query.
|
||||
</div>
|
||||
@@ -1,8 +1,13 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
|
||||
import 'rxjs/add/operator/publishReplay';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { ConnectableObservable } from 'rxjs/observable/ConnectableObservable';
|
||||
|
||||
import { Keymap } from '../../../config-serializer/config-items/Keymap';
|
||||
import { Keymaps } from '../../../config-serializer/config-items/Keymaps';
|
||||
import {DataProviderService} from '../../../services/data-provider.service';
|
||||
import { AppState } from '../../../store';
|
||||
import { KeymapActions } from '../../../store/actions';
|
||||
|
||||
@Component({
|
||||
selector: 'keymap-add',
|
||||
@@ -10,19 +15,32 @@ import {DataProviderService} from '../../../services/data-provider.service';
|
||||
styles: [require('./keymap-add.component.scss')]
|
||||
})
|
||||
export class KeymapAddComponent {
|
||||
private keymaps: Keymap[];
|
||||
private keymapsAll: Keymap[];
|
||||
private currentKeyboards: number;
|
||||
private presets$: Observable<Keymap[]>;
|
||||
private presetsAll$: Observable<Keymap[]>;
|
||||
|
||||
constructor(data: DataProviderService) {
|
||||
let json: any = data.getDefaultKeymaps();
|
||||
let all: Keymaps = new Keymaps().fromJsObject(json.keymaps);
|
||||
this.keymaps = all.elements;
|
||||
this.keymapsAll = this.keymaps.slice(0);
|
||||
this.currentKeyboards = this.keymaps.length;
|
||||
constructor(private store: Store<AppState>) {
|
||||
let presetConnectable: ConnectableObservable<Keymap[]> = store
|
||||
.select((appState: AppState) => appState.presetKeymaps)
|
||||
.publishReplay();
|
||||
|
||||
this.presets$ = presetConnectable;
|
||||
presetConnectable.connect();
|
||||
|
||||
this.presetsAll$ = store.select((appState: AppState) => appState.presetKeymaps);
|
||||
}
|
||||
|
||||
filterKeyboards(value: string) {
|
||||
this.keymaps = this.keymapsAll.filter((item: Keymap) => item.name.toLocaleLowerCase().indexOf(value) !== -1);
|
||||
let presetConnectable: ConnectableObservable<Keymap[]> = this.presetsAll$
|
||||
.map((keymaps: Keymap[]) => keymaps.filter(
|
||||
(keymap: Keymap) => keymap.name.toLocaleLowerCase().includes(value))
|
||||
)
|
||||
.publishReplay();
|
||||
|
||||
this.presets$ = presetConnectable;
|
||||
presetConnectable.connect();
|
||||
}
|
||||
|
||||
addKeymap(keymap: Keymap) {
|
||||
this.store.dispatch(KeymapActions.addKeymap(keymap));
|
||||
}
|
||||
}
|
||||
|
||||
30
src/components/keymap/header/keymap-header.component.html
Normal file
30
src/components/keymap/header/keymap-header.component.html
Normal file
@@ -0,0 +1,30 @@
|
||||
<div class="row">
|
||||
<h1 class="col-xs-12 pane-title">
|
||||
<i class="fa fa-keyboard-o"></i>
|
||||
<input class="keymap__name pane-title__name"
|
||||
value="{{ keymap.name }}"
|
||||
(change)="editKeymapName($event.target.value)"
|
||||
/> keymap
|
||||
(<input class="keymap__abbrev pane-title__abbrev"
|
||||
value="{{ keymap.abbreviation }}"
|
||||
(change)="editKeymapAbbr($event.target.value)"
|
||||
[attr.maxLength]="3"
|
||||
/>)
|
||||
<i class="fa keymap__is-default"
|
||||
[ngClass]="{'fa-star-o': !keymap.isDefault, 'fa-star': keymap.isDefault}"
|
||||
(click)="setDefault()"
|
||||
></i>
|
||||
<i class="glyphicon glyphicon-trash keymap__remove pull-right" title=""
|
||||
data-toggle="tooltip"
|
||||
data-placement="left"
|
||||
data-original-title="Remove keymap"
|
||||
(click)="removeKeymap()"
|
||||
></i>
|
||||
<i class="fa fa-files-o keymap__duplicate pull-right" title=""
|
||||
data-toggle="tooltip"
|
||||
data-placement="left"
|
||||
data-original-title="Duplicate keymap"
|
||||
(click)="duplicateKeymap()"
|
||||
></i>
|
||||
</h1>
|
||||
</div>
|
||||
61
src/components/keymap/header/keymap-header.component.scss
Normal file
61
src/components/keymap/header/keymap-header.component.scss
Normal file
@@ -0,0 +1,61 @@
|
||||
.keymap {
|
||||
&__is-default {
|
||||
|
||||
&.fa-star-o {
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: #b9b6b6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__remove {
|
||||
font-size: 0.75em;
|
||||
top: 8px;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
color: #900;
|
||||
}
|
||||
}
|
||||
|
||||
&__duplicate {
|
||||
font-size: 0.75em;
|
||||
top: 7px;
|
||||
margin-right: 15px;
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
color: #900;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pane-title {
|
||||
margin-bottom: 1em;
|
||||
|
||||
&__name,
|
||||
&__abbrev {
|
||||
border: none;
|
||||
border-bottom: 2px dotted #999;
|
||||
padding: 0;
|
||||
margin: 0 0.25rem;
|
||||
|
||||
&:focus {
|
||||
box-shadow: 0 0 0 1px #ccc, 0 0 5px 0 #ccc;
|
||||
border-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
&__name {
|
||||
width: 290px;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
&__abbrev {
|
||||
width: 90px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
44
src/components/keymap/header/keymap-header.component.ts
Normal file
44
src/components/keymap/header/keymap-header.component.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
|
||||
import { Store } from '@ngrx/store';
|
||||
|
||||
import { Keymap } from '../../../config-serializer/config-items/Keymap';
|
||||
|
||||
import { AppState } from '../../../store';
|
||||
import { KeymapActions } from '../../../store/actions';
|
||||
|
||||
@Component({
|
||||
selector: 'keymap-header',
|
||||
template: require('./keymap-header.component.html'),
|
||||
styles: [require('./keymap-header.component.scss')]
|
||||
})
|
||||
export class KeymapHeaderComponent {
|
||||
@Input() keymap: Keymap;
|
||||
|
||||
constructor(
|
||||
private store: Store<AppState>
|
||||
) { }
|
||||
|
||||
setDefault() {
|
||||
if (!this.keymap.isDefault) {
|
||||
this.store.dispatch(KeymapActions.setDefault(this.keymap.abbreviation));
|
||||
}
|
||||
}
|
||||
|
||||
removeKeymap() {
|
||||
this.store.dispatch(KeymapActions.removeKeymap(this.keymap.abbreviation));
|
||||
}
|
||||
|
||||
duplicateKeymap() {
|
||||
this.store.dispatch(KeymapActions.duplicateKeymap(this.keymap));
|
||||
}
|
||||
|
||||
editKeymapName(name: string) {
|
||||
this.store.dispatch(KeymapActions.editKeymapName(this.keymap.abbreviation, name));
|
||||
}
|
||||
|
||||
editKeymapAbbr(newAbbr: string) {
|
||||
newAbbr = newAbbr.toUpperCase();
|
||||
this.store.dispatch(KeymapActions.editKeymapAbbr(this.keymap.abbreviation, newAbbr));
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './keymap.component';
|
||||
export * from './keymap.routes';
|
||||
export * from './add/keymap-add.component';
|
||||
export * from './header/keymap-header.component';
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
<template [ngIf]="keymap">
|
||||
<div class="row">
|
||||
<h1 class="col-xs-12 pane-title">
|
||||
<i class="fa fa-keyboard-o"></i>
|
||||
<span class="keymap__name pane-title__name" contenteditable="true">{{keymap.name}}</span> keymap
|
||||
(<span class="keymap__abbrev pane-title__abbrev" contenteditable="true">{{keymap.abbreviation}}</span>)
|
||||
<i class="fa fa-star-o fa-star keymap__is-default"></i>
|
||||
<i class="glyphicon glyphicon-trash keymap__remove pull-right" title=""
|
||||
data-toggle="tooltip" data-placement="left" data-original-title="Remove keymap"></i>
|
||||
</h1>
|
||||
</div>
|
||||
<svg-keyboard-wrap [layers]="layers.elements"></svg-keyboard-wrap>
|
||||
</template>
|
||||
<template [ngIf]="keymap$ | async">
|
||||
<keymap-header [keymap]="keymap$ | async"></keymap-header>
|
||||
<svg-keyboard-wrap [keymap]="keymap$ | async"></svg-keyboard-wrap>
|
||||
</template>
|
||||
|
||||
<div *ngIf="!(keymap$ | async)" class="not-found">
|
||||
Sorry, there is no keymap with this abbreviation.
|
||||
</div>
|
||||
@@ -4,48 +4,9 @@
|
||||
display: block;
|
||||
}
|
||||
|
||||
.keymap {
|
||||
&__is-default {
|
||||
&.fa-star {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
&.fa-star-o {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: #555;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
&__remove {
|
||||
font-size: 0.75em;
|
||||
top: 0.3em;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
color: #900;
|
||||
}
|
||||
}
|
||||
.not-found {
|
||||
margin-top: 30px;
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.pane-title {
|
||||
margin-bottom: 1em;
|
||||
|
||||
&__name,
|
||||
&__abbrev {
|
||||
&[contenteditable=true] {
|
||||
border: none;
|
||||
border-bottom: 2px dotted #999;
|
||||
padding: 0 0.5rem;
|
||||
margin: 0 0.25rem;
|
||||
|
||||
&.active {
|
||||
box-shadow: 0 0 0 1px #ccc, 0 0 5px 0 #ccc;
|
||||
border-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,42 +1,38 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { Subscription } from 'rxjs/Subscription';
|
||||
|
||||
import '@ngrx/core/add/operator/select';
|
||||
import { Store } from '@ngrx/store';
|
||||
|
||||
import 'rxjs/add/operator/let';
|
||||
import 'rxjs/add/operator/publishReplay';
|
||||
import 'rxjs/add/operator/switchMap';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { ConnectableObservable } from 'rxjs/observable/ConnectableObservable';
|
||||
|
||||
import { Keymap } from '../../config-serializer/config-items/Keymap';
|
||||
import { Layers } from '../../config-serializer/config-items/Layers';
|
||||
import { UhkConfigurationService } from '../../services/uhk-configuration.service';
|
||||
import { AppState } from '../../store';
|
||||
import { getKeymap } from '../../store/reducers/keymap';
|
||||
|
||||
@Component({
|
||||
selector: 'keymap',
|
||||
template: require('./keymap.component.html'),
|
||||
styles: [require('./keymap.component.scss')]
|
||||
})
|
||||
export class KeymapComponent implements OnInit {
|
||||
private keymapId: number = 0;
|
||||
private layers: Layers;
|
||||
private keymap: Keymap;
|
||||
private subParams: Subscription;
|
||||
export class KeymapComponent {
|
||||
private keymap$: Observable<Keymap>;
|
||||
|
||||
constructor(
|
||||
private uhkConfigurationService: UhkConfigurationService,
|
||||
private store: Store<AppState>,
|
||||
private route: ActivatedRoute
|
||||
) {
|
||||
}
|
||||
let keymapConnectable: ConnectableObservable<Keymap> = route
|
||||
.params
|
||||
.select<string>('abbr')
|
||||
.switchMap((abbr: string) => store.let(getKeymap(abbr)))
|
||||
.publishReplay();
|
||||
|
||||
ngOnInit() {
|
||||
this.subParams = this.route.params.subscribe((params: { id: string }) => {
|
||||
let id: number = +params.id;
|
||||
|
||||
if (!isNaN(id)) {
|
||||
this.keymapId = id;
|
||||
}
|
||||
|
||||
this.keymap = this.uhkConfigurationService.getUhkConfiguration().keymaps.elements[this.keymapId];
|
||||
this.layers = this.keymap.layers;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.subParams.unsubscribe();
|
||||
this.keymap$ = keymapConnectable;
|
||||
keymapConnectable.connect();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ export const keymapRoutes: Routes = [
|
||||
component: KeymapAddComponent
|
||||
},
|
||||
{
|
||||
path: 'keymap/:id',
|
||||
path: 'keymap/:abbr',
|
||||
component: KeymapComponent
|
||||
}
|
||||
];
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
<layer-tab #tab *ngSwitchCase="TabName.Layer" class="popover-content" [defaultKeyAction]="defaultKeyAction"></layer-tab>
|
||||
<mouse-tab #tab *ngSwitchCase="TabName.Mouse" class="popover-content" [defaultKeyAction]="defaultKeyAction"></mouse-tab>
|
||||
<macro-tab #tab *ngSwitchCase="TabName.Macro" class="popover-content" [defaultKeyAction]="defaultKeyAction"></macro-tab>
|
||||
<keymap-tab #tab *ngSwitchCase="TabName.Keymap" class="popover-content" [defaultKeyAction]="defaultKeyAction"></keymap-tab>
|
||||
<keymap-tab #tab *ngSwitchCase="TabName.Keymap" class="popover-content" [defaultKeyAction]="defaultKeyAction" [keymaps]="keymaps$ | async"></keymap-tab>
|
||||
<none-tab #tab *ngSwitchCase="TabName.None" class="popover-content"></none-tab>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import {Component, EventEmitter, Input, OnInit, Output, ViewChild} from '@angular/core';
|
||||
import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
|
||||
|
||||
import { Store } from '@ngrx/store';
|
||||
|
||||
import {
|
||||
KeyAction,
|
||||
@@ -8,7 +10,12 @@ import {
|
||||
SwitchKeymapAction,
|
||||
SwitchLayerAction
|
||||
} from '../../config-serializer/config-items/key-action';
|
||||
import {Tab} from './tab/tab';
|
||||
import { Keymap } from '../../config-serializer/config-items/Keymap';
|
||||
|
||||
import { Tab } from './tab/tab';
|
||||
|
||||
import { AppState } from '../../store';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
|
||||
enum TabName {
|
||||
Keypress,
|
||||
@@ -38,11 +45,15 @@ export class PopoverComponent implements OnInit {
|
||||
private TabName = TabName;
|
||||
/* tslint:enable:no-unused-variable tslint:enable:variable-name */
|
||||
private activeTab: TabName;
|
||||
private keymaps$: Observable<Keymap[]>;
|
||||
|
||||
constructor() { }
|
||||
constructor(private store: Store<AppState>) {
|
||||
this.keymaps$ = store.select((appState: AppState) => appState.keymaps);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
let tab: TabName;
|
||||
|
||||
if (this.defaultKeyAction instanceof KeystrokeAction) {
|
||||
tab = TabName.Keypress;
|
||||
} else if (this.defaultKeyAction instanceof SwitchLayerAction) {
|
||||
@@ -56,6 +67,7 @@ export class PopoverComponent implements OnInit {
|
||||
} else {
|
||||
tab = TabName.None;
|
||||
}
|
||||
|
||||
this.selectTab(tab);
|
||||
}
|
||||
|
||||
@@ -76,5 +88,4 @@ export class PopoverComponent implements OnInit {
|
||||
selectTab(tab: TabName): void {
|
||||
this.activeTab = tab;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
<div>
|
||||
<b>Switch to keymap:</b>
|
||||
<select2 [data]="keymapOptions" [value]="keymapOptions[selectedKeymapIndex + 1].id" (valueChanged)="onChange($event)" [width]="'100%'"></select2>
|
||||
<select2
|
||||
[data]="keymapOptions"
|
||||
[value]="selectedKeymap?.abbreviation"
|
||||
(valueChanged)="onChange($event)"
|
||||
[width]="'100%'"
|
||||
></select2>
|
||||
</div>
|
||||
<div>
|
||||
<div *ngIf="selectedKeymapIndex === -1">
|
||||
<div *ngIf="!selectedKeymap?.abbreviation">
|
||||
<img src="./images/base-layer--blank.svg">
|
||||
</div>
|
||||
<svg-keyboard *ngIf="selectedKeymapIndex >= 0"
|
||||
[moduleConfig]="keymaps[selectedKeymapIndex].layers.elements[0].modules.elements">
|
||||
<svg-keyboard *ngIf="selectedKeymap?.abbreviation"
|
||||
[moduleConfig]="selectedKeymap.layers.elements[0].modules.elements">
|
||||
</svg-keyboard>
|
||||
</div>
|
||||
@@ -1,56 +1,55 @@
|
||||
import {Component, Input, OnInit } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
|
||||
|
||||
import {Select2OptionData} from 'ng2-select2/ng2-select2';
|
||||
import { Select2OptionData } from 'ng2-select2/ng2-select2';
|
||||
|
||||
import {KeyAction, SwitchKeymapAction} from '../../../../config-serializer/config-items/key-action';
|
||||
import {Keymap} from '../../../../config-serializer/config-items/Keymap';
|
||||
import {Tab} from '../tab';
|
||||
|
||||
import {UhkConfigurationService} from '../../../../services/uhk-configuration.service';
|
||||
import { KeyAction, SwitchKeymapAction } from '../../../../config-serializer/config-items/key-action';
|
||||
import { Keymap } from '../../../../config-serializer/config-items/Keymap';
|
||||
import { Tab } from '../tab';
|
||||
|
||||
@Component({
|
||||
selector: 'keymap-tab',
|
||||
template: require('./keymap-tab.component.html'),
|
||||
styles: [require('./keymap-tab.component.scss')]
|
||||
styles: [require('./keymap-tab.component.scss')],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class KeymapTabComponent implements OnInit, Tab {
|
||||
@Input() defaultKeyAction: KeyAction;
|
||||
@Input() keymaps: Keymap[];
|
||||
|
||||
private keymaps: Keymap[];
|
||||
private keymapOptions: Array<Select2OptionData>;
|
||||
private selectedKeymapIndex: number;
|
||||
private selectedKeymap: Keymap;
|
||||
|
||||
constructor(private uhkConfigurationService: UhkConfigurationService) {
|
||||
this.keymaps = [];
|
||||
constructor() {
|
||||
this.keymapOptions = [];
|
||||
this.selectedKeymapIndex = -1;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.keymaps = this.uhkConfigurationService.getUhkConfiguration().keymaps.elements;
|
||||
|
||||
this.keymapOptions.push({
|
||||
id: '-1',
|
||||
text: 'Switch to keymap'
|
||||
});
|
||||
|
||||
this.keymapOptions = this.keymapOptions.concat(this.keymaps.map(function (keymap: Keymap): Select2OptionData {
|
||||
this.keymapOptions = this.keymaps.map((keymap: Keymap): Select2OptionData => {
|
||||
return {
|
||||
id: keymap.id.toString(),
|
||||
id: keymap.abbreviation,
|
||||
text: keymap.name
|
||||
};
|
||||
}));
|
||||
});
|
||||
|
||||
this.fromKeyAction(this.defaultKeyAction);
|
||||
}
|
||||
|
||||
// TODO: change to the correct type when the wrapper has added it.
|
||||
onChange(event: any) {
|
||||
this.selectedKeymapIndex = +event.value;
|
||||
if (event.value === '-1') {
|
||||
this.selectedKeymap = undefined;
|
||||
} else {
|
||||
this.selectedKeymap = this.keymaps.find((keymap: Keymap) => keymap.abbreviation === event.value);
|
||||
}
|
||||
}
|
||||
|
||||
keyActionValid(): boolean {
|
||||
return this.selectedKeymapIndex >= 0;
|
||||
return !!this.selectedKeymap;
|
||||
}
|
||||
|
||||
fromKeyAction(keyAction: KeyAction): boolean {
|
||||
@@ -58,16 +57,17 @@ export class KeymapTabComponent implements OnInit, Tab {
|
||||
return false;
|
||||
}
|
||||
let switchKeymapAction: SwitchKeymapAction = <SwitchKeymapAction>keyAction;
|
||||
this.selectedKeymapIndex = this.keymaps.findIndex(keymap => switchKeymapAction.keymapId === keymap.id);
|
||||
return true;
|
||||
this.selectedKeymap = this.keymaps
|
||||
.find((keymap: Keymap) => keymap.abbreviation === switchKeymapAction.keymapAbbreviation);
|
||||
}
|
||||
|
||||
toKeyAction(): SwitchKeymapAction {
|
||||
if (!this.keyActionValid()) {
|
||||
throw new Error('KeyAction is not valid. No selected keymap!');
|
||||
}
|
||||
|
||||
let keymapAction = new SwitchKeymapAction();
|
||||
keymapAction.keymapId = this.keymaps[this.selectedKeymapIndex].id;
|
||||
keymapAction.keymapAbbreviation = this.selectedKeymap.abbreviation;
|
||||
return keymapAction;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
<i class="fa fa-chevron-up pull-right" (click)="toggleHide($event, 'keymap')"></i>
|
||||
</div>
|
||||
<ul [@toggler]="animation.keymap">
|
||||
<li *ngFor="let keymap of keymaps" class="sidebar__level-2--item">
|
||||
<li *ngFor="let keymap of keymaps$ | async" class="sidebar__level-2--item">
|
||||
<div class="sidebar__level-2">
|
||||
<a [routerLink]="['/keymap', keymap.id]">{{keymap.name}}</a>
|
||||
<a [routerLink]="['/keymap', keymap.abbreviation]">{{keymap.name}}</a>
|
||||
<i *ngIf="keymap.isDefault" class="fa fa-star sidebar__fav"></i>
|
||||
</div>
|
||||
</li>
|
||||
@@ -25,7 +25,7 @@
|
||||
<i class="fa fa-chevron-up pull-right" (click)="toggleHide($event, 'macro')"></i>
|
||||
</div>
|
||||
<ul [@toggler]="animation.macro">
|
||||
<li *ngFor="let macro of macros" class="sidebar__level-2--item">
|
||||
<li *ngFor="let macro of macros$ | async" class="sidebar__level-2--item">
|
||||
<div class="sidebar__level-2">
|
||||
<a [routerLink]="['/macro', macro.id]">{{macro.name}}</a>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { Component, OnInit, Renderer, animate, state, style, transition, trigger } from '@angular/core';
|
||||
import { Component, Renderer, animate, state, style, transition, trigger } from '@angular/core';
|
||||
|
||||
import { Keymap } from '../../config-serializer/config-items/Keymap';
|
||||
import { Macro } from '../../config-serializer/config-items/Macro';
|
||||
|
||||
import { UhkConfigurationService } from '../../services/uhk-configuration.service';
|
||||
import { AppState } from '../../store';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
|
||||
@Component({
|
||||
animations: [
|
||||
@@ -21,22 +23,20 @@ import { UhkConfigurationService } from '../../services/uhk-configuration.servic
|
||||
template: require('./side-menu.component.html'),
|
||||
styles: [require('./side-menu.component.scss')]
|
||||
})
|
||||
export class SideMenuComponent implements OnInit {
|
||||
private keymaps: Keymap[];
|
||||
private macros: Macro[];
|
||||
export class SideMenuComponent {
|
||||
private keymaps$: Observable<Keymap[]>;
|
||||
private macros$: Observable<Macro[]>;
|
||||
private animation: {[key: string]: 'active' | 'inactive'};
|
||||
|
||||
constructor(private uhkConfigurationService: UhkConfigurationService, private renderer: Renderer) {
|
||||
constructor(private store: Store<AppState>, private renderer: Renderer) {
|
||||
this.animation = {
|
||||
keymap: 'active',
|
||||
macro: 'active',
|
||||
addon: 'active'
|
||||
};
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.keymaps = this.uhkConfigurationService.getUhkConfiguration().keymaps.elements;
|
||||
this.macros = this.uhkConfigurationService.getUhkConfiguration().macros.elements;
|
||||
this.keymaps$ = store.select(appState => appState.keymaps);
|
||||
this.macros$ = store.select(appState => appState.macros);
|
||||
}
|
||||
|
||||
toggleHide(event: Event, type: string) {
|
||||
|
||||
@@ -145,8 +145,7 @@ export class SvgKeyboardKeyComponent implements OnInit, OnChanges {
|
||||
} else if (this.keyAction instanceof SwitchKeymapAction) {
|
||||
let keyAction: SwitchKeymapAction = this.keyAction as SwitchKeymapAction;
|
||||
this.labelType = LabelTypes.SwitchKeymap;
|
||||
let uhkConfiguration: UhkConfiguration = this.uhkConfigurationService.getUhkConfiguration();
|
||||
this.labelSource = uhkConfiguration.getKeymap(keyAction.keymapId).abbreviation;
|
||||
this.labelSource = keyAction.keymapAbbreviation;
|
||||
} else if (this.keyAction instanceof PlayMacroAction) {
|
||||
let keyAction: PlayMacroAction = this.keyAction as PlayMacroAction;
|
||||
this.labelType = LabelTypes.IconText;
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
import {
|
||||
Component, Input, OnChanges, OnInit, animate,
|
||||
Component, Input, OnChanges, SimpleChanges, animate,
|
||||
state, style, transition, trigger
|
||||
} from '@angular/core';
|
||||
|
||||
import { Store } from '@ngrx/store';
|
||||
|
||||
import { KeyAction, NoneAction } from '../../../config-serializer/config-items/key-action';
|
||||
import { Keymap } from '../../../config-serializer/config-items/Keymap';
|
||||
import { Layer } from '../../../config-serializer/config-items/Layer';
|
||||
|
||||
import { AppState } from '../../../store';
|
||||
import { KeymapActions } from '../../../store/actions';
|
||||
|
||||
@Component({
|
||||
selector: 'svg-keyboard-wrap',
|
||||
template: require('./svg-keyboard-wrap.component.html'),
|
||||
@@ -74,8 +80,8 @@ import { Layer } from '../../../config-serializer/config-items/Layer';
|
||||
])
|
||||
]
|
||||
})
|
||||
export class SvgKeyboardWrapComponent implements OnInit, OnChanges {
|
||||
@Input() layers: Layer[];
|
||||
export class SvgKeyboardWrapComponent implements OnChanges {
|
||||
@Input() keymap: Keymap;
|
||||
@Input() popoverEnabled: boolean = true;
|
||||
@Input() tooltipEnabled: boolean = false;
|
||||
|
||||
@@ -84,8 +90,11 @@ export class SvgKeyboardWrapComponent implements OnInit, OnChanges {
|
||||
private popoverInitKeyAction: KeyAction;
|
||||
private currentLayer: number = 0;
|
||||
private tooltipData: { posTop: number, posLeft: number, content: {name: string, value: string}[], shown: boolean };
|
||||
private layers: Layer[];
|
||||
|
||||
constructor() {
|
||||
constructor(
|
||||
private store: Store<AppState>
|
||||
) {
|
||||
this.keyEditConfig = {
|
||||
keyActions: undefined,
|
||||
keyId: undefined
|
||||
@@ -99,15 +108,15 @@ export class SvgKeyboardWrapComponent implements OnInit, OnChanges {
|
||||
};
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.layers[0].animation = 'leftIn';
|
||||
}
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes['keymap'].previousValue.abbreviation !== changes['keymap'].currentValue.abbreviation) {
|
||||
this.layers = this.keymap.layers.elements;
|
||||
this.currentLayer = 0;
|
||||
|
||||
ngOnChanges() {
|
||||
this.currentLayer = 0;
|
||||
if (this.layers.length > 0) {
|
||||
this.layers.forEach(element => element.animation = 'none');
|
||||
this.layers[0].animation = 'leftIn';
|
||||
if (this.layers.length > 0) {
|
||||
this.layers.forEach(element => element.animation = 'none');
|
||||
this.layers[0].animation = 'leftIn';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,6 +146,7 @@ export class SvgKeyboardWrapComponent implements OnInit, OnChanges {
|
||||
|
||||
onRemap(keyAction: KeyAction): void {
|
||||
this.changeKeyAction(keyAction);
|
||||
this.store.dispatch(KeymapActions.saveKey(this.keymap));
|
||||
this.hidePopover();
|
||||
}
|
||||
|
||||
|
||||
@@ -5,9 +5,6 @@ import { Layers } from './Layers';
|
||||
|
||||
export class Keymap extends Serializable<Keymap> {
|
||||
|
||||
@assertUInt8
|
||||
id: number;
|
||||
|
||||
name: string;
|
||||
|
||||
description: string;
|
||||
@@ -23,7 +20,7 @@ export class Keymap extends Serializable<Keymap> {
|
||||
if (!keymap) {
|
||||
return;
|
||||
}
|
||||
this.id = keymap.id;
|
||||
|
||||
this.name = keymap.name;
|
||||
this.description = keymap.description;
|
||||
this.abbreviation = keymap.abbreviation;
|
||||
@@ -32,7 +29,6 @@ export class Keymap extends Serializable<Keymap> {
|
||||
}
|
||||
|
||||
_fromJsObject(jsObject: any): Keymap {
|
||||
this.id = jsObject.id;
|
||||
this.isDefault = jsObject.isDefault;
|
||||
this.abbreviation = jsObject.abbreviation;
|
||||
this.name = jsObject.name;
|
||||
@@ -42,7 +38,6 @@ export class Keymap extends Serializable<Keymap> {
|
||||
}
|
||||
|
||||
_fromBinary(buffer: UhkBuffer): Keymap {
|
||||
this.id = buffer.readUInt8();
|
||||
this.isDefault = buffer.readBoolean();
|
||||
this.abbreviation = buffer.readString();
|
||||
this.name = buffer.readString();
|
||||
@@ -53,7 +48,6 @@ export class Keymap extends Serializable<Keymap> {
|
||||
|
||||
_toJsObject(): any {
|
||||
return {
|
||||
id: this.id,
|
||||
isDefault: this.isDefault,
|
||||
abbreviation: this.abbreviation,
|
||||
name: this.name,
|
||||
@@ -63,7 +57,6 @@ export class Keymap extends Serializable<Keymap> {
|
||||
}
|
||||
|
||||
_toBinary(buffer: UhkBuffer): void {
|
||||
buffer.writeUInt8(this.id);
|
||||
buffer.writeBoolean(this.isDefault);
|
||||
buffer.writeString(this.abbreviation);
|
||||
buffer.writeString(this.name);
|
||||
@@ -72,6 +65,6 @@ export class Keymap extends Serializable<Keymap> {
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `<Keymap id="${this.id}" name="${this.name}">`;
|
||||
return `<Keymap abbreviation="${this.abbreviation}" name="${this.name}">`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,10 +88,10 @@ export class UhkConfiguration extends Serializable<UhkConfiguration> {
|
||||
return `<UhkConfiguration signature="${this.signature}">`;
|
||||
}
|
||||
|
||||
getKeymap(keymapId: number): Keymap {
|
||||
getKeymap(keymapAbbreviation: string): Keymap {
|
||||
let keymaps: Keymap[] = this.keymaps.elements;
|
||||
for (let i = 0; i < keymaps.length; ++i) {
|
||||
if (keymapId === keymaps[i].id) {
|
||||
if (keymapAbbreviation === keymaps[i].abbreviation) {
|
||||
return keymaps[i];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,45 +1,43 @@
|
||||
import { assertUInt8 } from '../../assert';
|
||||
import { UhkBuffer } from '../../UhkBuffer';
|
||||
import { KeyAction, KeyActionId, keyActionType } from './KeyAction';
|
||||
|
||||
export class SwitchKeymapAction extends KeyAction {
|
||||
|
||||
@assertUInt8
|
||||
keymapId: number;
|
||||
keymapAbbreviation: string;
|
||||
|
||||
constructor(other?: SwitchKeymapAction) {
|
||||
super();
|
||||
if (!other) {
|
||||
return;
|
||||
}
|
||||
this.keymapId = other.keymapId;
|
||||
this.keymapAbbreviation = other.keymapAbbreviation;
|
||||
}
|
||||
|
||||
_fromJsObject(jsObject: any): SwitchKeymapAction {
|
||||
this.assertKeyActionType(jsObject);
|
||||
this.keymapId = jsObject.keymapId;
|
||||
this.keymapAbbreviation = jsObject.keymapAbbreviation;
|
||||
return this;
|
||||
}
|
||||
|
||||
_fromBinary(buffer: UhkBuffer): SwitchKeymapAction {
|
||||
this.readAndAssertKeyActionId(buffer);
|
||||
this.keymapId = buffer.readUInt8();
|
||||
this.keymapAbbreviation = buffer.readString();
|
||||
return this;
|
||||
}
|
||||
|
||||
_toJsObject(): any {
|
||||
return {
|
||||
keyActionType: keyActionType.SwitchKeymapAction,
|
||||
keymapId: this.keymapId
|
||||
keymapAbbreviation: this.keymapAbbreviation
|
||||
};
|
||||
}
|
||||
|
||||
_toBinary(buffer: UhkBuffer) {
|
||||
buffer.writeUInt8(KeyActionId.SwitchKeymapAction);
|
||||
buffer.writeUInt8(this.keymapId);
|
||||
buffer.writeString(this.keymapAbbreviation);
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `<SwitchKeymapAction keymapId="${this.keymapId}">`;
|
||||
return `<SwitchKeymapAction keymapAbbreviation="${this.keymapAbbreviation}">`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
{
|
||||
"keymaps": [
|
||||
{
|
||||
"id": 0,
|
||||
"isDefault": true,
|
||||
"isDefault": false,
|
||||
"abbreviation": "QTY",
|
||||
"name": "QWERTY",
|
||||
"description": "Maecenas sem dui, ullamcorper consequat pellentesque ut, mattis at velit. Duis scelerisque eleifend gravida. Aenean at mauris rhoncus, dictum mi vitae, semper eros. Quisque maximus est elit, at condimentum ligula consectetur vel. Aenean lorem felis, molestie id ex suscipit, sagittis mollis dui. Phasellus in felis in libero bibendum ornare. Duis vestibulum dolor sed diam tempor vulputate. Curabitur scelerisque pretium ipsum. Phasellus non orci vestibulum, vehicula lectus sit amet, lacinia velit. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In diam lacus, cursus at pretium vel, ullamcorper at ante.",
|
||||
@@ -381,7 +380,7 @@
|
||||
},
|
||||
{
|
||||
"keyActionType": "switchKeymap",
|
||||
"keymapId": 2
|
||||
"keymapAbbreviation": "VIM"
|
||||
},
|
||||
{
|
||||
"keyActionType": "none"
|
||||
@@ -791,7 +790,6 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"isDefault": false,
|
||||
"abbreviation": "VIM",
|
||||
"name": "VIM",
|
||||
@@ -813,7 +811,7 @@
|
||||
},
|
||||
{
|
||||
"keyActionType": "switchKeymap",
|
||||
"keymapId": 1
|
||||
"keymapAbbreviation": "QTY"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -879,7 +877,6 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"isDefault": false,
|
||||
"abbreviation": "DVR",
|
||||
"name": "DVR",
|
||||
@@ -14,7 +14,6 @@
|
||||
],
|
||||
"keymaps": [
|
||||
{
|
||||
"id": 0,
|
||||
"isDefault": true,
|
||||
"abbreviation": "QTY",
|
||||
"name": "QWERTY",
|
||||
@@ -394,7 +393,7 @@
|
||||
},
|
||||
{
|
||||
"keyActionType": "switchKeymap",
|
||||
"keymapId": 2
|
||||
"keymapAbbreviation": "VIM"
|
||||
},
|
||||
{
|
||||
"keyActionType": "none"
|
||||
@@ -809,7 +808,6 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"isDefault": false,
|
||||
"abbreviation": "VIM",
|
||||
"name": "VIM",
|
||||
@@ -831,7 +829,7 @@
|
||||
},
|
||||
{
|
||||
"keyActionType": "switchKeymap",
|
||||
"keymapId": 1
|
||||
"keymapAbbreviation": "QTY"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -912,7 +910,6 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"isDefault": false,
|
||||
"abbreviation": "DVR",
|
||||
"name": "DVR",
|
||||
|
||||
@@ -27,7 +27,6 @@ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
|
||||
<script src="vendor/bootstrap/js/bootstrap.min.js"></script> <!-- TODO remove in near future -->
|
||||
<script src="vendor/sortablejs/Sortable.min.js"></script>
|
||||
<script src="vendor/select2/js/select2.min.js"></script>
|
||||
<script src="app.js"></script> <!-- TODO move to typescript and components -->
|
||||
<script src="uhk.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -5,4 +5,5 @@
|
||||
</div>
|
||||
<div class="github-fork-ribbon">
|
||||
<a class="" href="https://github.com/UltimateHackingKeyboard/agent" title="Fork me on GitHub">Fork me on GitHub</a>
|
||||
</div>
|
||||
</div>
|
||||
<ngrx-store-log-monitor toggleCommand="alt-t"></ngrx-store-log-monitor>
|
||||
|
||||
@@ -12,7 +12,7 @@ export class DataProviderService {
|
||||
}
|
||||
|
||||
getDefaultKeymaps(): any {
|
||||
return require('json!../config-serializer/default-keymaps.json');
|
||||
return require('json!../config-serializer/preset-keymaps.json');
|
||||
}
|
||||
|
||||
getKeyboardSvgAttributes(): { viewBox: string, transform: string, fill: string } {
|
||||
|
||||
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