feat: show macro usage count (#1030)
* feat: show macro usage count * feat: show macro reference count only when ALT key hold down * fix: the macro reference help text
This commit is contained in:
committed by
László Monda
parent
9844645409
commit
fef24613e4
@@ -16,6 +16,7 @@ import {
|
|||||||
} from './store';
|
} from './store';
|
||||||
import { ProgressButtonState } from './store/reducers/progress-button-state';
|
import { ProgressButtonState } from './store/reducers/progress-button-state';
|
||||||
import { UpdateInfo } from './models/update-info';
|
import { UpdateInfo } from './models/update-info';
|
||||||
|
import { KeyUpAction, KeyDownAction } from './store/actions/app';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'main-app',
|
selector: 'main-app',
|
||||||
@@ -95,6 +96,13 @@ export class MainAppComponent implements OnDestroy {
|
|||||||
this.enableUsbStackTest();
|
this.enableUsbStackTest();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.store.dispatch(new KeyDownAction(event));
|
||||||
|
}
|
||||||
|
|
||||||
|
@HostListener('document:keyup', ['$event'])
|
||||||
|
onKeyUp(event: KeyboardEvent) {
|
||||||
|
this.store.dispatch(new KeyUpAction(event));
|
||||||
}
|
}
|
||||||
|
|
||||||
updateApp() {
|
updateApp() {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
<li>Right click on a key: Capture key</li>
|
<li>Right click on a key: Capture key</li>
|
||||||
<li>Hold Shift while clicking on a key: Remap on all keymaps</li>
|
<li>Hold Shift while clicking on a key: Remap on all keymaps</li>
|
||||||
<li>Hold Alt while clicking on a key: Remap on all layers</li>
|
<li>Hold Alt while clicking on a key: Remap on all layers</li>
|
||||||
|
<li>Hold Alt to see macro reference counts in the side menu</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -91,6 +91,12 @@
|
|||||||
<div class="sidebar__level-2" [routerLinkActive]="['active']">
|
<div class="sidebar__level-2" [routerLinkActive]="['active']">
|
||||||
<a [routerLink]="['/macro', macro.id]"
|
<a [routerLink]="['/macro', macro.id]"
|
||||||
[class.disabled]="state.updatingFirmware">{{macro.name}}</a>
|
[class.disabled]="state.updatingFirmware">{{macro.name}}</a>
|
||||||
|
<span *ngIf="state.macroUsageCountVisible"
|
||||||
|
class="sidebar__macro_count badge"
|
||||||
|
title="This is the number of times the macro is used across all keymaps."
|
||||||
|
data-toggle="tooltip"
|
||||||
|
data-placement="bottom"
|
||||||
|
data-container="body">{{ macro.usageCount }}</span>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -148,6 +148,12 @@ ul {
|
|||||||
right: 19px;
|
right: 19px;
|
||||||
top: 3px;
|
top: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__macro_count {
|
||||||
|
position: absolute;
|
||||||
|
right: 11px;
|
||||||
|
top: 1px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu--bottom {
|
.menu--bottom {
|
||||||
|
|||||||
@@ -1 +1,3 @@
|
|||||||
export * from './last-edited-key';
|
export * from './last-edited-key';
|
||||||
|
export * from './macro-menu-item';
|
||||||
|
export * from './side-menu-page-state';
|
||||||
|
|||||||
5
packages/uhk-web/src/app/models/macro-menu-item.ts
Normal file
5
packages/uhk-web/src/app/models/macro-menu-item.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export interface MacroMenuItem {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
usageCount: number;
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Keymap, Macro } from 'uhk-common';
|
import { Keymap, Macro } from 'uhk-common';
|
||||||
|
import { MacroMenuItem } from './macro-menu-item';
|
||||||
|
|
||||||
export interface SideMenuPageState {
|
export interface SideMenuPageState {
|
||||||
showAddonMenu: boolean;
|
showAddonMenu: boolean;
|
||||||
@@ -6,6 +7,7 @@ export interface SideMenuPageState {
|
|||||||
updatingFirmware: boolean;
|
updatingFirmware: boolean;
|
||||||
deviceName: string;
|
deviceName: string;
|
||||||
keymaps: Keymap[];
|
keymaps: Keymap[];
|
||||||
macros: Macro[];
|
macros: MacroMenuItem[];
|
||||||
restoreUserConfiguration: boolean;
|
restoreUserConfiguration: boolean;
|
||||||
|
macroUsageCountVisible: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,9 @@ export enum ActionTypes {
|
|||||||
SetupPermissionError = '[app] Setup permission error',
|
SetupPermissionError = '[app] Setup permission error',
|
||||||
LoadAppStartInfo = '[app] Load app start info',
|
LoadAppStartInfo = '[app] Load app start info',
|
||||||
StartKeypressCapturing = '[app] Start keypress capturing',
|
StartKeypressCapturing = '[app] Start keypress capturing',
|
||||||
StopKeypressCapturing = '[app] Stop keypress capturing'
|
StopKeypressCapturing = '[app] Stop keypress capturing',
|
||||||
|
KeyDown = '[app] Key down',
|
||||||
|
KeyUp = '[app] Key up'
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AppBootstrappedAction implements Action {
|
export class AppBootstrappedAction implements Action {
|
||||||
@@ -110,6 +112,18 @@ export class StopKeypressCapturingAction implements Action {
|
|||||||
type = ActionTypes.StopKeypressCapturing;
|
type = ActionTypes.StopKeypressCapturing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class KeyDownAction implements Action {
|
||||||
|
readonly type = ActionTypes.KeyDown;
|
||||||
|
|
||||||
|
constructor(public payload: KeyboardEvent) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class KeyUpAction implements Action {
|
||||||
|
readonly type = ActionTypes.KeyUp;
|
||||||
|
|
||||||
|
constructor(public payload: KeyboardEvent) {}
|
||||||
|
}
|
||||||
|
|
||||||
export type Actions
|
export type Actions
|
||||||
= AppStartedAction
|
= AppStartedAction
|
||||||
| AppBootstrappedAction
|
| AppBootstrappedAction
|
||||||
@@ -127,4 +141,6 @@ export type Actions
|
|||||||
| LoadAppStartInfoAction
|
| LoadAppStartInfoAction
|
||||||
| StartKeypressCapturingAction
|
| StartKeypressCapturingAction
|
||||||
| StopKeypressCapturingAction
|
| StopKeypressCapturingAction
|
||||||
|
| KeyDownAction
|
||||||
|
| KeyUpAction
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ActionReducerMap, createSelector, MetaReducer } from '@ngrx/store';
|
import { ActionReducerMap, createSelector, MetaReducer } from '@ngrx/store';
|
||||||
import { routerReducer, RouterReducerState } from '@ngrx/router-store';
|
import { routerReducer, RouterReducerState } from '@ngrx/router-store';
|
||||||
import { storeFreeze } from 'ngrx-store-freeze';
|
import { storeFreeze } from 'ngrx-store-freeze';
|
||||||
import { HardwareModules, Keymap, UserConfiguration } from 'uhk-common';
|
import { HardwareModules, Keymap, UserConfiguration, PlayMacroAction } from 'uhk-common';
|
||||||
|
|
||||||
import * as fromUserConfig from './reducers/user-configuration';
|
import * as fromUserConfig from './reducers/user-configuration';
|
||||||
import * as fromPreset from './reducers/preset';
|
import * as fromPreset from './reducers/preset';
|
||||||
@@ -16,6 +16,7 @@ import { environment } from '../../environments/environment';
|
|||||||
import { RouterStateUrl } from './router-util';
|
import { RouterStateUrl } from './router-util';
|
||||||
import { PrivilagePageSate } from '../models/privilage-page-sate';
|
import { PrivilagePageSate } from '../models/privilage-page-sate';
|
||||||
import { isVersionGte } from '../util';
|
import { isVersionGte } from '../util';
|
||||||
|
import { SideMenuPageState, MacroMenuItem } from '../models';
|
||||||
|
|
||||||
// State interface for the application
|
// State interface for the application
|
||||||
export interface AppState {
|
export interface AppState {
|
||||||
@@ -67,6 +68,7 @@ export const deviceConfigurationLoaded = createSelector(appState, fromApp.device
|
|||||||
export const getAgentVersionInfo = createSelector(appState, fromApp.getAgentVersionInfo);
|
export const getAgentVersionInfo = createSelector(appState, fromApp.getAgentVersionInfo);
|
||||||
export const getOperatingSystem = createSelector(appState, fromSelectors.getOperatingSystem);
|
export const getOperatingSystem = createSelector(appState, fromSelectors.getOperatingSystem);
|
||||||
export const keypressCapturing = createSelector(appState, fromApp.keypressCapturing);
|
export const keypressCapturing = createSelector(appState, fromApp.keypressCapturing);
|
||||||
|
export const getMacroUsageCountVisible = createSelector(appState, fromApp.macroUsageCountVisible);
|
||||||
export const runningOnNotSupportedWindows = createSelector(appState, fromApp.runningOnNotSupportedWindows);
|
export const runningOnNotSupportedWindows = createSelector(appState, fromApp.runningOnNotSupportedWindows);
|
||||||
export const contributors = (state: AppState) => state.contributors;
|
export const contributors = (state: AppState) => state.contributors;
|
||||||
export const firmwareUpgradeAllowed = createSelector(runningOnNotSupportedWindows, notSupportedOs => !notSupportedOs);
|
export const firmwareUpgradeAllowed = createSelector(runningOnNotSupportedWindows, notSupportedOs => !notSupportedOs);
|
||||||
@@ -123,25 +125,57 @@ export const getPrivilegePageState = createSelector(appState, getUpdateUdevRules
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const getMacroMenuItems = (userConfiguration: UserConfiguration): MacroMenuItem[] => {
|
||||||
|
const macroMap = userConfiguration.macros.reduce((map, macro) => {
|
||||||
|
return map.set(macro.id, {
|
||||||
|
id: macro.id,
|
||||||
|
name: macro.name,
|
||||||
|
usageCount: 0
|
||||||
|
});
|
||||||
|
}, new Map<number, MacroMenuItem>());
|
||||||
|
|
||||||
|
for (const keymap of userConfiguration.keymaps) {
|
||||||
|
for (const layer of keymap.layers) {
|
||||||
|
for (const module of layer.modules) {
|
||||||
|
for (const keyAction of module.keyActions) {
|
||||||
|
if (!(keyAction instanceof PlayMacroAction)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const menuItem = macroMap.get(keyAction.macroId);
|
||||||
|
menuItem.usageCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Array
|
||||||
|
.from(macroMap.values())
|
||||||
|
.sort((first: MacroMenuItem, second: MacroMenuItem) => first.name.localeCompare(second.name));
|
||||||
|
};
|
||||||
|
|
||||||
export const getSideMenuPageState = createSelector(
|
export const getSideMenuPageState = createSelector(
|
||||||
showAddonMenu,
|
showAddonMenu,
|
||||||
runningInElectron,
|
runningInElectron,
|
||||||
updatingFirmware,
|
updatingFirmware,
|
||||||
getUserConfiguration,
|
getUserConfiguration,
|
||||||
getRestoreUserConfiguration,
|
getRestoreUserConfiguration,
|
||||||
|
getMacroUsageCountVisible,
|
||||||
(showAddonMenuValue: boolean,
|
(showAddonMenuValue: boolean,
|
||||||
runningInElectronValue: boolean,
|
runningInElectronValue: boolean,
|
||||||
updatingFirmwareValue: boolean,
|
updatingFirmwareValue: boolean,
|
||||||
userConfiguration: UserConfiguration,
|
userConfiguration: UserConfiguration,
|
||||||
restoreUserConfiguration: boolean) => {
|
restoreUserConfiguration: boolean,
|
||||||
|
macroUsageCountVisible): SideMenuPageState => {
|
||||||
return {
|
return {
|
||||||
showAddonMenu: showAddonMenuValue,
|
showAddonMenu: showAddonMenuValue,
|
||||||
runInElectron: runningInElectronValue,
|
runInElectron: runningInElectronValue,
|
||||||
updatingFirmware: updatingFirmwareValue,
|
updatingFirmware: updatingFirmwareValue,
|
||||||
deviceName: userConfiguration.deviceName,
|
deviceName: userConfiguration.deviceName,
|
||||||
keymaps: userConfiguration.keymaps,
|
keymaps: userConfiguration.keymaps,
|
||||||
macros: userConfiguration.macros,
|
macros: getMacroMenuItems(userConfiguration),
|
||||||
restoreUserConfiguration
|
restoreUserConfiguration,
|
||||||
|
macroUsageCountVisible
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ export interface State {
|
|||||||
platform?: string;
|
platform?: string;
|
||||||
osVersion?: string;
|
osVersion?: string;
|
||||||
keypressCapturing: boolean;
|
keypressCapturing: boolean;
|
||||||
|
macroUsageCountVisible: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const initialState: State = {
|
export const initialState: State = {
|
||||||
@@ -40,7 +41,8 @@ export const initialState: State = {
|
|||||||
configLoading: true,
|
configLoading: true,
|
||||||
agentVersionInfo: getVersions(),
|
agentVersionInfo: getVersions(),
|
||||||
privilegeWhatWillThisDoClicked: false,
|
privilegeWhatWillThisDoClicked: false,
|
||||||
keypressCapturing: false
|
keypressCapturing: false,
|
||||||
|
macroUsageCountVisible: false
|
||||||
};
|
};
|
||||||
|
|
||||||
export function reducer(
|
export function reducer(
|
||||||
@@ -156,7 +158,8 @@ export function reducer(
|
|||||||
case App.ActionTypes.StartKeypressCapturing:
|
case App.ActionTypes.StartKeypressCapturing:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
keypressCapturing: true
|
keypressCapturing: true,
|
||||||
|
macroUsageCountVisible: false
|
||||||
};
|
};
|
||||||
|
|
||||||
case App.ActionTypes.StopKeypressCapturing:
|
case App.ActionTypes.StopKeypressCapturing:
|
||||||
@@ -165,6 +168,24 @@ export function reducer(
|
|||||||
keypressCapturing: false
|
keypressCapturing: false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
case App.ActionTypes.KeyDown: {
|
||||||
|
const event = (action as App.KeyDownAction).payload;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
macroUsageCountVisible: !state.keypressCapturing && !event.defaultPrevented && event.altKey
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
case App.ActionTypes.KeyUp: {
|
||||||
|
const event = (action as App.KeyDownAction).payload;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
macroUsageCountVisible: event.altKey
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
@@ -197,3 +218,4 @@ export const runningOnNotSupportedWindows = (state: State): boolean => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const keypressCapturing = (state: State): boolean => state.keypressCapturing;
|
export const keypressCapturing = (state: State): boolean => state.keypressCapturing;
|
||||||
|
export const macroUsageCountVisible = (state: State): boolean => state.macroUsageCountVisible;
|
||||||
|
|||||||
Reference in New Issue
Block a user