9 Commits

Author SHA1 Message Date
László Monda
547ab738c2 Update package.json and changelog to version 1.0.3 2017-12-28 01:31:38 +01:00
László Monda
3de9e9aa84 Downgrade to firmware 8.0.0 because the left I2C watchdog of firmware 8.0.1 is not proven yet and might make things worse. 2017-12-28 01:09:01 +01:00
László Monda
01ac4c1e8b Note that macro playback is not implemented yet. 2017-12-27 23:30:08 +01:00
László Monda
a0c8849f13 Comment out the add keymap button because the add keymap page is practically useless now. It'll be reimplemented. 2017-12-27 23:06:58 +01:00
László Monda
2a3dfcb0d0 Improve firmware update messages. 2017-12-27 22:47:53 +01:00
László Monda
2b3462c33f Display retry firmware update messages with regular color because they're not errors. 2017-12-27 22:38:07 +01:00
László Monda
a0b838b2e9 Remove the secondary scroll bar that appears on the LED brightness page. 2017-12-27 20:43:25 +01:00
Mikko Lakomaa
90f56c350e LED brightness UI (#520)
* Add nouislider

* Add LEDBrightnessComponent

* Move LEDBrightnessComponent to correct folder

* Add LED brightness page to side menu and device routes

* Add LEDBrightnessComponent to device index file

* Add LEDBrightnessComponent and NouisliderModule to shared module

* Remove ngModelChange from LEDBrightnessComponent until onChange is implemented

* Fix stylelint issue in led brightness component

* Add nouislider files to webpack.config.js

* Add adjusting LED brightness sliders with arrow keys

* Various tweaks to LEDBrightnessComponent

* Fix linting issues in LEDBrightnessComponent

* Allow "::ng-deep" pseudo element in stylelint config

* Add reading LED brightness settings from user configuration

* led-brightness save

* Move slider to its own wrapper component, add debounce for slider change events

* Small fixes to imports and exports of SliderWrapperComponent

* Fix slide component making change event when initial value is set

* Export SliderPips interface

* Fix LED Brightness slider pips

* Add support for value unit in SliderWrapperComponent

* Add a bit of space before LED brightness sliders so the slider handle doesn't go beyond the page in the min position

* Implement onDestroy, fix slider pip values and imports in LEDBrightnessComponent

* Fix imports, implement onDestroy in SliderWrapperComponent

* Move fix for slider pip value style to global styles file

* Reorder stylelint rules
2017-12-27 20:10:55 +01:00
József Farkas
5ceca41e0f feat(renderer): show icon when possible even if the keystroke action has modifier (#533)
Closes #513
2017-12-26 23:23:32 +01:00
30 changed files with 2144 additions and 579 deletions

View File

@@ -4,6 +4,17 @@ All notable changes to this project will be documented in this file.
The format is loosely based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). The format is loosely based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
## [1.0.3] - 2017-12-28
Firmware: [8.0.**0**](https://github.com/UltimateHackingKeyboard/firmware/releases/tag/8.0.**0**) | Device Protocol: 4.0.0 | User Config: 4.0.0 | Hardware Config: 1.0.0
- Add LED brightness settings.
- Some key actions, for example Left Arrow were displayed as text with modifiers and as icon without modifires. Now, they're always displayed as icons.
- Clean up firmware update console messages a bit.
- Remove the add keymap button because this feature is not only useless but confusing until it gets reimplemented.
- Explicitly mention on the macro tab of the key action popover that macro playback is not implemented yet.
- Downgrade to firmware 8.0.0 because the left I2C watchdog of firmware 8.0.1 is not proven yet.
## [1.0.2] - 2017-12-25 ## [1.0.2] - 2017-12-25
Firmware: [**8.0.1**](https://github.com/UltimateHackingKeyboard/firmware/releases/tag/8.0.1) | Device Protocol: 4.0.0 | User Config: 4.0.0 | Hardware Config: 1.0.0 Firmware: [**8.0.1**](https://github.com/UltimateHackingKeyboard/firmware/releases/tag/8.0.1) | Device Protocol: 4.0.0 | User Config: 4.0.0 | Hardware Config: 1.0.0

2
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{ {
"name": "uhk-agent", "name": "uhk-agent",
"version": "1.0.1", "version": "1.0.2",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {

View File

@@ -3,7 +3,7 @@
"private": true, "private": true,
"author": "Ultimate Gadget Laboratories", "author": "Ultimate Gadget Laboratories",
"main": "electron/dist/electron-main.js", "main": "electron/dist/electron-main.js",
"version": "1.0.2", "version": "1.0.3",
"description": "Agent is the configuration application of the Ultimate Hacking Keyboard.", "description": "Agent is the configuration application of the Ultimate Hacking Keyboard.",
"repository": { "repository": {
"type": "git", "type": "git",

View File

@@ -16,7 +16,7 @@
"dependencies": { "dependencies": {
"node-hid": "0.5.7" "node-hid": "0.5.7"
}, },
"firmwareVersion": "8.0.1", "firmwareVersion": "8.0.0",
"deviceProtocolVersion": "4.0.0", "deviceProtocolVersion": "4.0.0",
"userConfigVersion": "4.0.0", "userConfigVersion": "4.0.0",
"hardwareConfigVersion": "1.0.0" "hardwareConfigVersion": "1.0.0"

View File

@@ -26,7 +26,7 @@ export class UhkOperations {
await this.blhost.runBlhostCommand([...prefix, 'flash-erase-region', '0xc000', '475136']); await this.blhost.runBlhostCommand([...prefix, 'flash-erase-region', '0xc000', '475136']);
await this.blhost.runBlhostCommand([...prefix, 'flash-image', `"${firmwarePath}"`]); await this.blhost.runBlhostCommand([...prefix, 'flash-image', `"${firmwarePath}"`]);
await this.blhost.runBlhostCommand([...prefix, 'reset']); await this.blhost.runBlhostCommand([...prefix, 'reset']);
this.logService.debug('[UhkOperations] End flashing right firmware'); this.logService.debug('[UhkOperations] Right firmware successfully flashed');
} }
public async updateLeftModule(firmwarePath = this.getLeftModuleFirmwarePath()) { public async updateLeftModule(firmwarePath = this.getLeftModuleFirmwarePath()) {
@@ -58,7 +58,8 @@ export class UhkOperations {
await this.device.sendKbootCommandToModule(ModuleSlotToI2cAddress.leftHalf, KbootCommands.idle); await this.device.sendKbootCommandToModule(ModuleSlotToI2cAddress.leftHalf, KbootCommands.idle);
this.device.close(); this.device.close();
this.logService.debug('[UhkOperations] End flashing left module firmware'); this.logService.debug('[UhkOperations] Left firmware successfully flashed');
this.logService.debug('[UhkOperations] Both left and right firmwares successfully flashed');
} }
/** /**

View File

@@ -89,7 +89,7 @@ export async function retry(command: Function, maxTry = 3, logService?: LogServi
throw err; throw err;
} else { } else {
if (logService) { if (logService) {
logService.error(`[retry] failed, but try run FUNCTION:\n ${command}, \n retry: ${retryCount}`); logService.info(`[retry] failed, but try run FUNCTION:\n ${command}, \n retry: ${retryCount}`);
} }
} }
} }

View File

@@ -21,11 +21,13 @@
"prefix": "app", "prefix": "app",
"styles": [ "styles": [
"../node_modules/bootstrap/dist/css/bootstrap.min.css", "../node_modules/bootstrap/dist/css/bootstrap.min.css",
"../node_modules/nouislider/distribute/nouislider.min.css",
"styles.scss" "styles.scss"
], ],
"scripts": [ "scripts": [
"../node_modules/bootstrap/dist/js/bootstrap.js", "../node_modules/bootstrap/dist/js/bootstrap.js",
"../node_modules/select2/dist/js/select2.full.js" "../node_modules/select2/dist/js/select2.full.js",
"../node_modules/nouislider/distribute/nouislider.js"
], ],
"environmentSource": "environments/environment.ts", "environmentSource": "environments/environment.ts",
"environments": { "environments": {

File diff suppressed because it is too large Load Diff

View File

@@ -69,9 +69,11 @@
"less-loader": "4.0.5", "less-loader": "4.0.5",
"lodash": "4.17.4", "lodash": "4.17.4",
"ng2-dragula": "1.5.0", "ng2-dragula": "1.5.0",
"ng2-nouislider": "^1.7.6",
"ng2-select2": "1.0.0-beta.10", "ng2-select2": "1.0.0-beta.10",
"ngrx-store-freeze": "0.1.9", "ngrx-store-freeze": "0.1.9",
"node-hid": "0.5.4", "node-hid": "0.5.4",
"nouislider": "^10.1.0",
"postcss-loader": "1.3.3", "postcss-loader": "1.3.3",
"postcss-url": "5.1.2", "postcss-url": "5.1.2",
"protractor": "5.1.2", "protractor": "5.1.2",

View File

@@ -3,6 +3,7 @@ import { Routes } from '@angular/router';
import { DeviceConfigurationComponent } from './configuration/device-configuration.component'; import { DeviceConfigurationComponent } from './configuration/device-configuration.component';
import { DeviceFirmwareComponent } from './firmware/device-firmware.component'; import { DeviceFirmwareComponent } from './firmware/device-firmware.component';
import { MouseSpeedComponent } from './mouse-speed/mouse-speed.component'; import { MouseSpeedComponent } from './mouse-speed/mouse-speed.component';
import { LEDBrightnessComponent } from './led-brightness/led-brightness.component';
export const deviceRoutes: Routes = [ export const deviceRoutes: Routes = [
{ {
@@ -21,6 +22,10 @@ export const deviceRoutes: Routes = [
path: 'mouse-speed', path: 'mouse-speed',
component: MouseSpeedComponent component: MouseSpeedComponent
}, },
{
path: 'led-brightness',
component: LEDBrightnessComponent
},
{ {
path: 'firmware', path: 'firmware',
component: DeviceFirmwareComponent component: DeviceFirmwareComponent

View File

@@ -1,4 +1,5 @@
export * from './configuration/device-configuration.component'; export * from './configuration/device-configuration.component';
export * from './firmware/device-firmware.component'; export * from './firmware/device-firmware.component';
export * from './mouse-speed/mouse-speed.component'; export * from './mouse-speed/mouse-speed.component';
export * from './led-brightness/led-brightness.component';
export * from './device.routes'; export * from './device.routes';

View File

@@ -0,0 +1,47 @@
<h1>
<i class="fa fa-sliders"></i>
<span>LED brightness</span>
</h1>
<div class="row led-setting">
<div class="col-xs-12 col-md-6">
<label>LED display icon and layer texts brightness</label>
<div class="slider-wrapper-container">
<slider-wrapper
[min]="0"
[max]="255"
[step]="1"
[pips]="sliderPips"
[(ngModel)]="iconsAndLayerTextsBrightness"
(ngModelChange)="onSetPropertyValue('iconsAndLayerTextsBrightness', $event)"></slider-wrapper>
</div>
</div>
</div>
<div class="row led-setting">
<div class="col-xs-12 col-md-6">
<label>LED display alphanumeric segments brightness</label>
<div class="slider-wrapper-container">
<slider-wrapper
[min]="0"
[max]="255"
[step]="1"
[pips]="sliderPips"
[(ngModel)]="alphanumericSegmentsBrightness"
(ngModelChange)="onSetPropertyValue('alphanumericSegmentsBrightness', $event)"></slider-wrapper>
</div>
</div>
</div>
<div class="row led-setting">
<div class="col-xs-12 col-md-6">
<label>Key backlight brightness</label>
<div class="slider-wrapper-container">
<slider-wrapper
[min]="0"
[max]="255"
[step]="1"
[pips]="sliderPips"
[(ngModel)]="keyBacklightBrightness"
(ngModelChange)="onSetPropertyValue('keyBacklightBrightness', $event)"></slider-wrapper>
</div>
</div>
</div>

View File

@@ -0,0 +1,19 @@
:host {
overflow-y: auto;
display: block;
height: 100%;
width: 100%;
label {
display: block;
font-weight: normal;
}
.led-setting {
margin-bottom: 6rem;
}
.slider-wrapper-container {
margin-left: 1.6rem;
}
}

View File

@@ -0,0 +1,53 @@
import { AfterViewInit, Component, OnInit, OnDestroy, ViewChildren, QueryList } from '@angular/core';
import { Store } from '@ngrx/store';
import { AppState, getUserConfiguration } from '../../../store';
import { SetUserConfigurationValueAction } from '../../../store/actions/user-config';
import { SliderPips } from '../../slider-wrapper/slider-wrapper.component';
import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription';
import { UserConfiguration } from 'uhk-common';
@Component({
selector: 'device-led-brightness',
templateUrl: './led-brightness.component.html',
styleUrls: ['./led-brightness.component.scss'],
host: {
'class': 'container-fluid'
}
})
export class LEDBrightnessComponent implements OnInit, OnDestroy {
public iconsAndLayerTextsBrightness: number = 0;
public alphanumericSegmentsBrightness: number = 0;
public keyBacklightBrightness: number = 0;
public sliderPips: SliderPips = {
mode: 'positions',
values: [0, 50, 100],
density: 6,
stepped: true
};
private userConfig$: Store<UserConfiguration>;
private userConfigSubscription: Subscription;
constructor(private store: Store<AppState>) {}
ngOnInit() {
this.userConfig$ = this.store.select(getUserConfiguration);
this.userConfigSubscription = this.userConfig$.subscribe(config => {
this.iconsAndLayerTextsBrightness = config.iconsAndLayerTextsBrightness;
this.alphanumericSegmentsBrightness = config.alphanumericSegmentsBrightness;
this.keyBacklightBrightness = config.keyBacklightBrightness;
});
}
ngOnDestroy() {
this.userConfigSubscription.unsubscribe();
}
onSetPropertyValue(propertyName: string, value: number): void {
this.store.dispatch(new SetUserConfigurationValueAction({
propertyName,
value
}));
}
}

View File

@@ -2,6 +2,7 @@
<span> No macros are available to choose from. Create a macro first! </span> <span> No macros are available to choose from. Create a macro first! </span>
</ng-template> </ng-template>
<ng-template [ngIf]="macroOptions.length > 0"> <ng-template [ngIf]="macroOptions.length > 0">
<p><i>Please note that macro playback is not implemented yet. You can bind macros, but they don't have any effect.</i></p>
<div class="macro-selector"> <div class="macro-selector">
<b> Play macro: </b> <b> Play macro: </b>
<select2 [data]="macroOptions" [value]="macroOptions[selectedMacroIndex].id" (valueChanged)="onChange($event)" [width]="'100%'"></select2> <select2 [data]="macroOptions" [value]="macroOptions[selectedMacroIndex].id" (valueChanged)="onChange($event)" [width]="'100%'"></select2>

View File

@@ -23,6 +23,12 @@
[class.disabled]="updatingFirmware$ | async">Mouse speed</a> [class.disabled]="updatingFirmware$ | async">Mouse speed</a>
</div> </div>
</li> </li>
<li class="sidebar__level-2--item">
<div class="sidebar__level-2" [routerLinkActive]="['active']">
<a [routerLink]="['/device/led-brightness']"
[class.disabled]="updatingFirmware$ | async">LED brightness</a>
</div>
</li>
<li class="sidebar__level-2--item"> <li class="sidebar__level-2--item">
<div class="sidebar__level-2" [routerLinkActive]="['active']"> <div class="sidebar__level-2" [routerLinkActive]="['active']">
<a [routerLink]="['/device/configuration']" <a [routerLink]="['/device/configuration']"
@@ -40,11 +46,11 @@
<li class="sidebar__level-1--item"> <li class="sidebar__level-1--item">
<div class="sidebar__level-1"> <div class="sidebar__level-1">
<i class="fa fa-keyboard-o"></i> Keymaps <i class="fa fa-keyboard-o"></i> Keymaps
<a [routerLink]="['/keymap/add']" <!--a [routerLink]="['/keymap/add']"
class="btn btn-default pull-right btn-sm" class="btn btn-default pull-right btn-sm"
[class.disabled]="updatingFirmware$ | async"> [class.disabled]="updatingFirmware$ | async">
<i class="fa fa-plus"></i> <i class="fa fa-plus"></i>
</a> </a-->
<i class="fa fa-chevron-up pull-right" <i class="fa fa-chevron-up pull-right"
(click)="toggleHide($event, 'keymap')"></i> (click)="toggleHide($event, 'keymap')"></i>
</div> </div>

View File

@@ -0,0 +1,13 @@
<div class="slider-container">
<nouislider
[min]="min"
[max]="max"
[step]="step"
[keyboard]="true"
[tooltips]="true"
[(ngModel)]="value"
(ngModelChange)="onSliderChange($event)"></nouislider>
</div>
<div class="slider-value">
<div class="value-indicator">{{value}} {{valueUnit}}</div>
</div>

View File

@@ -0,0 +1,17 @@
:host {
display: flex;
flex-direction: row;
.slider-container {
width: 80%;
}
.slider-value {
width: 20%;
}
.value-indicator {
margin: 1rem 1rem 1rem 3rem;
vertical-align: middle;
}
}

View File

@@ -0,0 +1,83 @@
import { AfterViewInit, Component, EventEmitter, forwardRef, Input, Output, OnDestroy, ViewChild } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { NouisliderComponent } from 'ng2-nouislider/src/nouislider';
import { Observable } from 'rxjs/Observable';
import { Observer } from 'rxjs/Observer';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged';
export interface SliderPips {
mode: string;
values: number[];
density: number;
stepped?: boolean;
}
@Component({
selector: 'slider-wrapper',
templateUrl: './slider-wrapper.component.html',
styleUrls: ['./slider-wrapper.component.scss'],
providers: [
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SliderWrapperComponent), multi: true }
]
})
export class SliderWrapperComponent implements AfterViewInit, ControlValueAccessor, OnDestroy {
@ViewChild(NouisliderComponent) slider: NouisliderComponent;
@Input() min: number;
@Input() max: number;
@Input() step: number;
@Input() pips: SliderPips;
@Input() valueUnit: string;
@Output() onChange = new EventEmitter<number>();
public value: number;
private changeObserver$: Observer<number>;
private changeDebounceTime: number = 300;
ngAfterViewInit(): void {
if (this.pips) {
this.slider.slider.pips(this.pips);
}
// Hide tooltips and show them when dragging slider handle
this.slider.slider.target.querySelector('.noUi-tooltip').style.display = 'none';
this.slider.slider.on('start', function() {
this.target.querySelector('.noUi-tooltip').style.display = 'block';
});
this.slider.slider.on('end', function() {
this.target.querySelector('.noUi-tooltip').style.display = 'none';
});
}
ngOnDestroy() {
if (this.changeObserver$) {
this.changeObserver$.complete();
}
}
writeValue(value: number): void {
this.value = value || this.min;
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
registerOnTouched() {}
onSliderChange(value: number): void {
if (!this.changeObserver$) {
Observable.create(observer => {
this.changeObserver$ = observer;
}).debounceTime(this.changeDebounceTime)
.distinctUntilChanged()
.subscribe(this.propagateChange);
return; // No change event on first change as the value is just being set
}
this.changeObserver$.next(value);
}
private propagateChange: any = () => {};
}

View File

@@ -1,5 +1,10 @@
<svg [attr.viewBox]="viewBox" [attr.width]="textContainer.width" [attr.height]="textContainer.height" <svg [attr.viewBox]="viewBox" [attr.width]="textContainer.width" [attr.height]="textContainer.height"
[attr.x]="textContainer.x" [attr.y]="textContainer.y" [ngSwitch]="labelType"> [attr.x]="textContainer.x" [attr.y]="textContainer.y" [ngSwitch]="labelType">
<svg:g svg-single-icon-key *ngSwitchCase="'icon'"
[height]="height"
[width]="width"
[icon]="labelSource">
</svg:g>
<svg:g svg-one-line-text-key *ngSwitchCase="'one-line'" <svg:g svg-one-line-text-key *ngSwitchCase="'one-line'"
[height]="height" [height]="height"
[width]="width" [width]="width"

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -127,21 +127,23 @@ export class SvgKeystrokeKeyComponent implements OnInit, OnChanges {
} }
ngOnChanges() { ngOnChanges() {
let newLabelSource: string[];
if (this.keystrokeAction.hasScancode()) { if (this.keystrokeAction.hasScancode()) {
const scancode: number = this.keystrokeAction.scancode; const scancode: number = this.keystrokeAction.scancode;
newLabelSource = this.mapper.scanCodeToText(scancode, this.keystrokeAction.type); this.labelSource = this.mapper.scanCodeToSvgImagePath(scancode, this.keystrokeAction.type);
if (newLabelSource) { if (this.labelSource) {
if (newLabelSource.length === 1) {
this.labelSource = newLabelSource[0];
this.labelType = 'one-line';
} else {
this.labelSource = newLabelSource;
this.labelType = 'two-line';
}
} else {
this.labelSource = this.mapper.scanCodeToSvgImagePath(scancode, this.keystrokeAction.type);
this.labelType = 'icon'; this.labelType = 'icon';
} else {
let newLabelSource: string[];
newLabelSource = this.mapper.scanCodeToText(scancode, this.keystrokeAction.type);
if (newLabelSource) {
if (newLabelSource.length === 1) {
this.labelSource = newLabelSource[0];
this.labelType = 'one-line';
} else {
this.labelSource = newLabelSource;
this.labelType = 'two-line';
}
}
} }
} else { } else {
this.labelType = 'empty'; this.labelType = 'empty';

View File

@@ -0,0 +1,4 @@
export interface UserConfigurationValue {
propertyName: string;
value: number;
}

View File

@@ -3,7 +3,7 @@ import { Component } from '@angular/core';
@Component({ @Component({
selector: 'main-page', selector: 'main-page',
templateUrl: './main.page.html', templateUrl: './main.page.html',
styles: [':host{height:100%; display: inline-block; width: 100%}'] styles: [':host{height:100%; width:100%}']
}) })
export class MainPage { export class MainPage {

View File

@@ -71,7 +71,11 @@ export class MapperService {
default: default:
return undefined; return undefined;
} }
return 'assets/compiled_sprite.svg#' + map.get(scanCode); const id = map.get(scanCode);
if (!id) {
return undefined;
}
return `assets/compiled_sprite.svg#${id}`;
} }
public getIcon(iconName: string): string { public getIcon(iconName: string): string {

View File

@@ -7,13 +7,15 @@ import { ConfirmationPopoverModule } from 'angular-confirmation-popover';
import { DragulaModule } from 'ng2-dragula/ng2-dragula'; import { DragulaModule } from 'ng2-dragula/ng2-dragula';
import { Select2Module } from 'ng2-select2/ng2-select2'; import { Select2Module } from 'ng2-select2/ng2-select2';
import { NouisliderModule } from 'ng2-nouislider';
import { AddOnComponent } from './components/add-on'; import { AddOnComponent } from './components/add-on';
import { KeyboardSliderComponent } from './components/keyboard/slider'; import { KeyboardSliderComponent } from './components/keyboard/slider';
import { import {
DeviceConfigurationComponent, DeviceConfigurationComponent,
DeviceFirmwareComponent, DeviceFirmwareComponent,
MouseSpeedComponent MouseSpeedComponent,
LEDBrightnessComponent
} from './components/device'; } from './components/device';
import { KeymapAddComponent, KeymapEditComponent, KeymapHeaderComponent } from './components/keymap'; import { KeymapAddComponent, KeymapEditComponent, KeymapHeaderComponent } from './components/keymap';
import { LayersComponent } from './components/layers'; import { LayersComponent } from './components/layers';
@@ -98,6 +100,7 @@ import { LoadingDevicePageComponent } from './pages/loading-page/loading-device.
import { UhkDeviceLoadingGuard } from './services/uhk-device-loading.guard'; import { UhkDeviceLoadingGuard } from './services/uhk-device-loading.guard';
import { UhkDeviceLoadedGuard } from './services/uhk-device-loaded.guard'; import { UhkDeviceLoadedGuard } from './services/uhk-device-loaded.guard';
import { XtermComponent } from './components/xterm/xterm.component'; import { XtermComponent } from './components/xterm/xterm.component';
import { SliderWrapperComponent } from './components/slider-wrapper/slider-wrapper.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
@@ -105,6 +108,7 @@ import { XtermComponent } from './components/xterm/xterm.component';
DeviceConfigurationComponent, DeviceConfigurationComponent,
DeviceFirmwareComponent, DeviceFirmwareComponent,
MouseSpeedComponent, MouseSpeedComponent,
LEDBrightnessComponent,
KeymapEditComponent, KeymapEditComponent,
KeymapHeaderComponent, KeymapHeaderComponent,
NotificationComponent, NotificationComponent,
@@ -163,7 +167,8 @@ import { XtermComponent } from './components/xterm/xterm.component';
MainPage, MainPage,
ProgressButtonComponent, ProgressButtonComponent,
LoadingDevicePageComponent, LoadingDevicePageComponent,
XtermComponent XtermComponent,
SliderWrapperComponent
], ],
imports: [ imports: [
CommonModule, CommonModule,
@@ -172,6 +177,7 @@ import { XtermComponent } from './components/xterm/xterm.component';
DragulaModule, DragulaModule,
routing, routing,
Select2Module, Select2Module,
NouisliderModule,
NotifierModule.withConfig(angularNotifierConfig), NotifierModule.withConfig(angularNotifierConfig),
ConfirmationPopoverModule.forRoot({ ConfirmationPopoverModule.forRoot({
confirmButtonType: 'danger' // set defaults here confirmButtonType: 'danger' // set defaults here

View File

@@ -1,5 +1,6 @@
import { Action } from '@ngrx/store'; import { Action } from '@ngrx/store';
import { type, UserConfiguration, ConfigurationReply } from 'uhk-common'; import { type, UserConfiguration, ConfigurationReply } from 'uhk-common';
import { UserConfigurationValue } from '../../models/user-configuration-value';
const PREFIX = '[user-config] '; const PREFIX = '[user-config] ';
@@ -13,7 +14,8 @@ export const ActionTypes = {
SAVE_USER_CONFIG_IN_JSON_FILE: type(PREFIX + 'Save User Config in JSON file'), 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'), 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') RENAME_USER_CONFIGURATION: type(PREFIX + 'Rename user configuration'),
SET_USER_CONFIGURATION_VALUE: type(PREFIX + 'Set user configuration value')
}; };
export class LoadUserConfigAction implements Action { export class LoadUserConfigAction implements Action {
@@ -67,6 +69,13 @@ export class RenameUserConfigurationAction implements Action {
} }
} }
export class SetUserConfigurationValueAction implements Action {
type = ActionTypes.SET_USER_CONFIGURATION_VALUE;
constructor(public payload: UserConfigurationValue) {
}
}
export type Actions export type Actions
= LoadUserConfigAction = LoadUserConfigAction
| LoadUserConfigSuccessAction | LoadUserConfigSuccessAction
@@ -77,4 +86,5 @@ export type Actions
| SaveUserConfigInBinaryFileAction | SaveUserConfigInBinaryFileAction
| LoadResetUserConfigurationAction | LoadResetUserConfigurationAction
| RenameUserConfigurationAction | RenameUserConfigurationAction
| SetUserConfigurationValueAction
; ;

View File

@@ -72,7 +72,7 @@ export class UserConfigEffects {
KeymapActions.SET_DEFAULT, KeymapActions.REMOVE, KeymapActions.SAVE_KEY, KeymapActions.SET_DEFAULT, KeymapActions.REMOVE, KeymapActions.SAVE_KEY,
MacroActions.ADD, MacroActions.DUPLICATE, MacroActions.EDIT_NAME, MacroActions.REMOVE, MacroActions.ADD_ACTION, MacroActions.ADD, MacroActions.DUPLICATE, MacroActions.EDIT_NAME, MacroActions.REMOVE, MacroActions.ADD_ACTION,
MacroActions.SAVE_ACTION, MacroActions.DELETE_ACTION, MacroActions.REORDER_ACTION, MacroActions.SAVE_ACTION, MacroActions.DELETE_ACTION, MacroActions.REORDER_ACTION,
ActionTypes.RENAME_USER_CONFIGURATION) as ActionTypes.RENAME_USER_CONFIGURATION, ActionTypes.SET_USER_CONFIGURATION_VALUE) as
Observable<KeymapAction | MacroAction | RenameUserConfigurationAction>) Observable<KeymapAction | MacroAction | RenameUserConfigurationAction>)
.withLatestFrom(this.store.select(getUserConfiguration), this.store.select(getPrevUserConfiguration)) .withLatestFrom(this.store.select(getUserConfiguration), this.store.select(getPrevUserConfiguration))
.mergeMap(([action, config, prevUserConfiguration]) => { .mergeMap(([action, config, prevUserConfiguration]) => {

View File

@@ -246,6 +246,11 @@ export function reducer(state = initialState, action: Action & { payload?: any }
break; break;
} }
case ActionTypes.SET_USER_CONFIGURATION_VALUE: {
changedUserConfiguration[action.payload.propertyName] = action.payload.value;
break;
}
default: default:
break; break;
} }

View File

@@ -90,3 +90,7 @@ a.disabled {
width: 100%; width: 100%;
display: inline-block; display: inline-block;
} }
.noUi-value {
top: 2rem;
}

View File

@@ -85,10 +85,12 @@ module.exports = {
], ],
"scripts": [ "scripts": [
"script-loader!./node_modules/bootstrap/dist/js/bootstrap.js", "script-loader!./node_modules/bootstrap/dist/js/bootstrap.js",
"script-loader!./node_modules/select2/dist/js/select2.full.js" "script-loader!./node_modules/select2/dist/js/select2.full.js",
"script-loader!./node_modules/nouislider/distribute/nouislider.js"
], ],
"styles": [ "styles": [
"./node_modules/bootstrap/dist/css/bootstrap.min.css", "./node_modules/bootstrap/dist/css/bootstrap.min.css",
"./node_modules/nouislider/distribute/nouislider.min.css",
"./src/styles.scss" "./src/styles.scss"
] ]
}, },
@@ -126,6 +128,7 @@ module.exports = {
{ {
"exclude": [ "exclude": [
path.join(process.cwd(), "node_modules/bootstrap/dist/css/bootstrap.min.css"), path.join(process.cwd(), "node_modules/bootstrap/dist/css/bootstrap.min.css"),
path.join(process.cwd(), "node_modules/nouislider/distribute/nouislider.min.css"),
path.join(process.cwd(), "src/styles.scss") path.join(process.cwd(), "src/styles.scss")
], ],
"test": /\.css$/, "test": /\.css$/,
@@ -150,6 +153,7 @@ module.exports = {
{ {
"exclude": [ "exclude": [
path.join(process.cwd(), "node_modules/bootstrap/dist/css/bootstrap.min.css"), path.join(process.cwd(), "node_modules/bootstrap/dist/css/bootstrap.min.css"),
path.join(process.cwd(), "node_modules/nouislider/distribute/nouislider.min.css"),
path.join(process.cwd(), "src/styles.scss") path.join(process.cwd(), "src/styles.scss")
], ],
"test": /\.scss$|\.sass$/, "test": /\.scss$|\.sass$/,
@@ -182,6 +186,7 @@ module.exports = {
{ {
"exclude": [ "exclude": [
path.join(process.cwd(), "node_modules/bootstrap/dist/css/bootstrap.min.css"), path.join(process.cwd(), "node_modules/bootstrap/dist/css/bootstrap.min.css"),
path.join(process.cwd(), "node_modules/nouislider/distribute/nouislider.min.css"),
path.join(process.cwd(), "src/styles.scss") path.join(process.cwd(), "src/styles.scss")
], ],
"test": /\.less$/, "test": /\.less$/,
@@ -212,6 +217,7 @@ module.exports = {
{ {
"exclude": [ "exclude": [
path.join(process.cwd(), "node_modules/bootstrap/dist/css/bootstrap.min.css"), path.join(process.cwd(), "node_modules/bootstrap/dist/css/bootstrap.min.css"),
path.join(process.cwd(), "node_modules/nouislider/distribute/nouislider.min.css"),
path.join(process.cwd(), "src/styles.scss") path.join(process.cwd(), "src/styles.scss")
], ],
"test": /\.styl$/, "test": /\.styl$/,
@@ -243,6 +249,7 @@ module.exports = {
{ {
"include": [ "include": [
path.join(process.cwd(), "node_modules/bootstrap/dist/css/bootstrap.min.css"), path.join(process.cwd(), "node_modules/bootstrap/dist/css/bootstrap.min.css"),
path.join(process.cwd(), "node_modules/nouislider/distribute/nouislider.min.css"),
path.join(process.cwd(), "src/styles.scss") path.join(process.cwd(), "src/styles.scss")
], ],
"test": /\.css$/, "test": /\.css$/,
@@ -267,6 +274,7 @@ module.exports = {
{ {
"include": [ "include": [
path.join(process.cwd(), "node_modules/bootstrap/dist/css/bootstrap.min.css"), path.join(process.cwd(), "node_modules/bootstrap/dist/css/bootstrap.min.css"),
path.join(process.cwd(), "node_modules/nouislider/distribute/nouislider.min.css"),
path.join(process.cwd(), "src/styles.scss") path.join(process.cwd(), "src/styles.scss")
], ],
"test": /\.scss$|\.sass$/, "test": /\.scss$|\.sass$/,
@@ -299,6 +307,7 @@ module.exports = {
{ {
"include": [ "include": [
path.join(process.cwd(), "node_modules/bootstrap/dist/css/bootstrap.min.css"), path.join(process.cwd(), "node_modules/bootstrap/dist/css/bootstrap.min.css"),
path.join(process.cwd(), "node_modules/nouislider/distribute/nouislider.min.css"),
path.join(process.cwd(), "src/styles.scss") path.join(process.cwd(), "src/styles.scss")
], ],
"test": /\.less$/, "test": /\.less$/,
@@ -329,6 +338,7 @@ module.exports = {
{ {
"include": [ "include": [
path.join(process.cwd(), "node_modules/bootstrap/dist/css/bootstrap.min.css"), path.join(process.cwd(), "node_modules/bootstrap/dist/css/bootstrap.min.css"),
path.join(process.cwd(), "node_modules/nouislider/distribute/nouislider.min.css"),
path.join(process.cwd(), "src/styles.scss") path.join(process.cwd(), "src/styles.scss")
], ],
"test": /\.styl$/, "test": /\.styl$/,