feat(config): Add deviceName to the user config (#474)

* add device name to configuration

* feat(config): Rename user configuration

* style: fix tslint error

* test: Fix unit tests

* test: Add UserConfiguration device name test

* set device name if faild the user-config read from device

* feat(device): Remove the first 0 from USB[W] dump
This commit is contained in:
Róbert Kiss
2017-10-28 20:16:59 +02:00
committed by László Monda
parent 9885439b10
commit cdc4a169de
13 changed files with 141 additions and 18 deletions

View File

@@ -4,6 +4,7 @@ describe('keymap', () => {
it('should normalize SwitchLayerAction if non base layer action is not SwitchLayerAction', () => {
const inputJsonConfig = {
dataModelVersion: 1,
deviceName: 'My UHK',
moduleConfigurations: [],
macros: [],
keymaps: [
@@ -63,6 +64,7 @@ describe('keymap', () => {
};
const expectedJsonConfig = {
dataModelVersion: 1,
deviceName: 'My UHK',
moduleConfigurations: [],
macros: [],
keymaps: [
@@ -131,6 +133,7 @@ describe('keymap', () => {
it('should normalize SwitchLayerAction if non base layer action is other SwitchLayerAction', () => {
const inputJsonConfig = {
dataModelVersion: 1,
deviceName: 'My UHK',
moduleConfigurations: [],
macros: [],
keymaps: [
@@ -190,6 +193,7 @@ describe('keymap', () => {
};
const expectedJsonConfig = {
dataModelVersion: 1,
deviceName: 'My UHK',
moduleConfigurations: [],
macros: [],
keymaps: [

View File

@@ -9,6 +9,7 @@ describe('user-configuration', () => {
it('should transform an empty config', () => {
jsonTester({
dataModelVersion: 1,
deviceName: 'My UHK',
moduleConfigurations: [],
macros: [],
keymaps: []
@@ -18,6 +19,7 @@ describe('user-configuration', () => {
it('should transform a null keyActionType ', () => {
jsonTester({
dataModelVersion: 1,
deviceName: 'My UHK',
moduleConfigurations: [],
macros: [],
keymaps: [
@@ -39,6 +41,21 @@ describe('user-configuration', () => {
]
});
});
it('Should set the device name to "My UHK" if not exists in the config', () => {
const original = {
dataModelVersion: 1,
moduleConfigurations: [],
macros: [],
keymaps: []
};
const config = new UserConfiguration();
config.fromJsonObject(original);
expect(config.deviceName).toEqual('My UHK');
});
});
function jsonTester(json: any): void {

View File

@@ -10,14 +10,22 @@ export class UserConfiguration {
@assertUInt16
dataModelVersion: number;
deviceName: string;
moduleConfigurations: ModuleConfiguration[] = [];
keymaps: Keymap[] = [];
macros: Macro[] = [];
constructor() {
this.setDefaultDeviceName();
}
fromJsonObject(jsonObject: any): UserConfiguration {
this.dataModelVersion = jsonObject.dataModelVersion;
this.deviceName = jsonObject.deviceName;
this.setDefaultDeviceName();
this.moduleConfigurations = jsonObject.moduleConfigurations.map((moduleConfiguration: any) => {
return new ModuleConfiguration().fromJsonObject(moduleConfiguration);
});
@@ -32,6 +40,8 @@ export class UserConfiguration {
fromBinary(buffer: UhkBuffer): UserConfiguration {
this.dataModelVersion = buffer.readUInt16();
this.deviceName = buffer.readString();
this.setDefaultDeviceName();
this.moduleConfigurations = buffer.readArray<ModuleConfiguration>(uhkBuffer => {
return new ModuleConfiguration().fromBinary(uhkBuffer);
});
@@ -48,6 +58,7 @@ export class UserConfiguration {
toJsonObject(): any {
return {
dataModelVersion: this.dataModelVersion,
deviceName: this.deviceName,
moduleConfigurations: this.moduleConfigurations.map(moduleConfiguration => moduleConfiguration.toJsonObject()),
keymaps: this.keymaps.map(keymap => keymap.toJsonObject(this.macros)),
macros: this.macros.map(macro => macro.toJsonObject())
@@ -56,6 +67,7 @@ export class UserConfiguration {
toBinary(buffer: UhkBuffer): void {
buffer.writeUInt16(this.dataModelVersion);
buffer.writeString(this.deviceName);
buffer.writeArray(this.moduleConfigurations);
buffer.writeArray(this.macros);
buffer.writeArray(this.keymaps, (uhkBuffer: UhkBuffer, keymap: Keymap) => {
@@ -75,4 +87,9 @@ export class UserConfiguration {
return this.macros.find(macro => macroId === macro.id);
}
private setDefaultDeviceName(): void {
if (!this.deviceName || this.deviceName.trim().length === 0) {
this.deviceName = 'My UHK';
}
}
}

View File

@@ -143,7 +143,7 @@ export class UhkHidDevice {
});
const sendData = UhkHidDevice.getTransferData(buffer);
this.logService.debug('[UhkHidDevice] USB[W]:', UhkHidDevice.bufferToString(sendData));
this.logService.debug('[UhkHidDevice] USB[W]:', UhkHidDevice.bufferToString(sendData).substr(3));
device.write(sendData);
});
}

View File

@@ -139,5 +139,5 @@ export class MacroMouseTabComponent extends MacroBaseComponent implements OnInit
default:
return true;
}
};
}
}

View File

@@ -1,7 +1,13 @@
<ul class="menu--top">
<li class="sidebar__level-0--item">
<div class="sidebar__level-0">
<i class="uhk-icon uhk-icon-0401-usb-stick rotate-right"></i> UHK 60
<i class="uhk-icon uhk-icon-0401-usb-stick rotate-right"></i>
<input #deviceName cancelable
class="pane-title__name"
type="text"
(change)="editDeviceName($event.target.value)"
(keyup.enter)="deviceName.blur()"
(keyup)="calculateHeaderTextWidth($event.target.value)">
<i class="fa fa-chevron-up pull-right" (click)="toggleHide($event, 'device')"></i>
</div>
<ul [@toggler]="animation['device']">

View File

@@ -34,7 +34,7 @@ ul {
padding: 0.5rem 1rem 0.5rem 2rem;
}
&__level-0 ,
&__level-0,
&__level-1 {
font-size: 2rem;
line-height: 3rem;
@@ -150,3 +150,22 @@ ul {
}
}
}
.pane-title {
margin-bottom: 1em;
&__name {
border: none;
border-bottom: 2px dotted #999;
padding: 0;
margin: 0 0.25rem;
text-overflow: ellipsis;
background-color: inherit;
&:focus {
box-shadow: 0 0 0 1px #ccc, 0 0 5px 0 #ccc;
border-color: transparent;
background-color: inherit;
}
}
}

View File

@@ -1,4 +1,4 @@
import { Component, Renderer } from '@angular/core';
import { AfterContentInit, Component, ElementRef, Renderer2, ViewChild } from '@angular/core';
import { animate, state, style, transition, trigger } from '@angular/animations';
import { Keymap, Macro } from 'uhk-common';
@@ -9,9 +9,11 @@ import 'rxjs/add/operator/do';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/let';
import { AppState, showAddonMenu, runningInElectron } from '../../store';
import { AppState, getDeviceName, showAddonMenu, runningInElectron } from '../../store';
import { MacroActions } from '../../store/actions';
import { getKeymaps, getMacros } from '../../store/reducers/user-configuration';
import * as util from '../../util';
import { RenameUserConfigurationAction } from '../../store/actions/user-config';
@Component({
animations: [
@@ -29,15 +31,18 @@ import { getKeymaps, getMacros } from '../../store/reducers/user-configuration';
templateUrl: './side-menu.component.html',
styleUrls: ['./side-menu.component.scss']
})
export class SideMenuComponent {
export class SideMenuComponent implements AfterContentInit {
showAddonMenu$: Observable<boolean>;
runInElectron$: Observable<boolean>;
deviceName$: Observable<string>;
keymaps$: Observable<Keymap[]>;
macros$: Observable<Macro[]>;
animation: { [key: string]: 'active' | 'inactive' };
deviceNameValue: string;
@ViewChild('deviceName') deviceName: ElementRef;
constructor(private store: Store<AppState>, private renderer: Renderer) {
constructor(private store: Store<AppState>, private renderer: Renderer2) {
this.animation = {
device: 'active',
configuration: 'active',
@@ -60,6 +65,15 @@ export class SideMenuComponent {
this.showAddonMenu$ = this.store.select(showAddonMenu);
this.runInElectron$ = this.store.select(runningInElectron);
this.deviceName$ = store.select(getDeviceName);
this.deviceName$.subscribe(name => {
this.deviceNameValue = name;
this.setDeviceName();
});
}
ngAfterContentInit(): void {
this.setDeviceName();
}
toggleHide(event: Event, type: string) {
@@ -73,11 +87,34 @@ export class SideMenuComponent {
this.animation[type] = 'inactive';
}
this.renderer.setElementClass(event.target, 'fa-chevron-up', show);
this.renderer.setElementClass(event.target, 'fa-chevron-down', !show);
if (show) {
this.renderer.addClass(event.target, 'fa-chevron-up');
this.renderer.removeClass(event.target, 'fa-chevron-down');
} else {
this.renderer.removeClass(event.target, 'fa-chevron-up');
this.renderer.addClass(event.target, 'fa-chevron-down');
}
}
addMacro() {
this.store.dispatch(MacroActions.addMacro());
}
editDeviceName(name): void {
this.store.dispatch(new RenameUserConfigurationAction(name));
}
calculateHeaderTextWidth(text): void {
const htmlInput = this.deviceName.nativeElement as HTMLInputElement;
const maxWidth = htmlInput.parentElement.offsetWidth * 0.66;
const textWidth = util.getContentWidth(window.getComputedStyle(htmlInput), text);
this.renderer.setStyle(htmlInput, 'width', Math.min(maxWidth, textWidth) + 'px');
}
private setDeviceName(): void {
if (this.deviceName) {
this.renderer.setProperty(this.deviceName.nativeElement, 'value', this.deviceNameValue);
this.calculateHeaderTextWidth(this.deviceName.nativeElement.value);
}
}
}

View File

@@ -1,5 +1,6 @@
{
"dataModelVersion": 4,
"deviceName": "My UHK",
"moduleConfigurations": [
{
"id": 1,

View File

@@ -12,7 +12,8 @@ export const ActionTypes = {
SAVE_USER_CONFIG_SUCCESS: type(PREFIX + 'Save User Config Success'),
SAVE_USER_CONFIG_IN_JSON_FILE: type(PREFIX + 'Save User Config in JSON file'),
SAVE_USER_CONFIG_IN_BIN_FILE: type(PREFIX + 'Save User Config in binary file'),
LOAD_RESET_USER_CONFIGURATION: type(PREFIX + 'Load reset user configuration')
LOAD_RESET_USER_CONFIGURATION: type(PREFIX + 'Load reset user configuration'),
RENAME_USER_CONFIGURATION: type(PREFIX + 'Rename user configuration')
};
export class LoadUserConfigAction implements Action {
@@ -26,19 +27,22 @@ export class LoadConfigFromDeviceAction implements Action {
export class LoadConfigFromDeviceReplyAction implements Action {
type = ActionTypes.LOAD_CONFIG_FROM_DEVICE_REPLY;
constructor(public payload: ConfigurationReply) { }
constructor(public payload: ConfigurationReply) {
}
}
export class LoadUserConfigSuccessAction implements Action {
type = ActionTypes.LOAD_USER_CONFIG_SUCCESS;
constructor(public payload: UserConfiguration) { }
constructor(public payload: UserConfiguration) {
}
}
export class SaveUserConfigSuccessAction implements Action {
type = ActionTypes.SAVE_USER_CONFIG_SUCCESS;
constructor(public payload: UserConfiguration) { }
constructor(public payload: UserConfiguration) {
}
}
export class SaveUserConfigInJsonFileAction implements Action {
@@ -52,7 +56,15 @@ export class SaveUserConfigInBinaryFileAction implements Action {
export class LoadResetUserConfigurationAction implements Action {
type = ActionTypes.LOAD_RESET_USER_CONFIGURATION;
constructor(public payload: UserConfiguration) { }
constructor(public payload: UserConfiguration) {
}
}
export class RenameUserConfigurationAction implements Action {
type = ActionTypes.RENAME_USER_CONFIGURATION;
constructor(public payload: string) {
}
}
export type Actions
@@ -64,4 +76,5 @@ export type Actions
| SaveUserConfigInJsonFileAction
| SaveUserConfigInBinaryFileAction
| LoadResetUserConfigurationAction
| RenameUserConfigurationAction
;

View File

@@ -25,6 +25,7 @@ import {
import {
ActionTypes,
LoadUserConfigSuccessAction,
RenameUserConfigurationAction,
SaveUserConfigSuccessAction
} from '../actions/user-config';
@@ -72,8 +73,9 @@ export class UserConfigEffects {
KeymapActions.ADD, KeymapActions.DUPLICATE, KeymapActions.EDIT_NAME, KeymapActions.EDIT_ABBR,
KeymapActions.SET_DEFAULT, KeymapActions.REMOVE, KeymapActions.SAVE_KEY,
MacroActions.ADD, MacroActions.DUPLICATE, MacroActions.EDIT_NAME, MacroActions.REMOVE, MacroActions.ADD_ACTION,
MacroActions.SAVE_ACTION, MacroActions.DELETE_ACTION, MacroActions.REORDER_ACTION) as
Observable<KeymapAction | MacroAction>)
MacroActions.SAVE_ACTION, MacroActions.DELETE_ACTION, MacroActions.REORDER_ACTION,
ActionTypes.RENAME_USER_CONFIGURATION) as
Observable<KeymapAction | MacroAction | RenameUserConfigurationAction>)
.withLatestFrom(this.store.select(getUserConfiguration), this.store.select(getPrevUserConfiguration))
.mergeMap(([action, config, prevUserConfiguration]) => {
this.dataStorageRepository.saveConfig(config);

View File

@@ -39,6 +39,7 @@ export const metaReducers: MetaReducer<AppState>[] = environment.production
: [storeFreeze];
export const getUserConfiguration = (state: AppState) => state.userConfiguration;
export const getDeviceName = (state: AppState) => state.userConfiguration.deviceName;
export const appState = (state: AppState) => state.app;
export const showAddonMenu = createSelector(appState, fromApp.showAddonMenu);

View File

@@ -126,7 +126,7 @@ export function reducer(state = initialState, action: Action & { payload?: any }
if (index - 1 === newKeyAction.layer) {
const clonedAction = KeyActionHelper.createKeyAction(action.payload.keyAction);
setKeyActionToLayer(newLayer, moduleIndex, keyIndex, clonedAction);
}else {
} else {
setKeyActionToLayer(newLayer, moduleIndex, keyIndex, null);
}
}
@@ -240,6 +240,12 @@ export function reducer(state = initialState, action: Action & { payload?: any }
return macro;
});
break;
case ActionTypes.RENAME_USER_CONFIGURATION: {
changedUserConfiguration.deviceName = action.payload;
break;
}
default:
break;
}