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:
committed by
László Monda
parent
9885439b10
commit
cdc4a169de
@@ -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: [
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -139,5 +139,5 @@ export class MacroMouseTabComponent extends MacroBaseComponent implements OnInit
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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']">
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"dataModelVersion": 4,
|
||||
"deviceName": "My UHK",
|
||||
"moduleConfigurations": [
|
||||
{
|
||||
"id": 1,
|
||||
|
||||
@@ -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
|
||||
;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user