Mark duplicate hotkeys

This commit is contained in:
Benjamin Brandmeier 2022-12-18 13:34:06 +01:00 committed by Eugene
parent bc243a2741
commit 72bc58332d
7 changed files with 77 additions and 28 deletions

View file

@ -3,6 +3,11 @@ export interface HotkeyDescription {
name: string
}
export interface Hotkey {
strokes: string[] | string; // may be a sequence of strokes
isDuplicate: boolean;
}
/**
* Extend to provide your own hotkeys. A corresponding [[ConfigProvider]]
* must also provide the `hotkeys.foo` config options with the default values

View file

@ -256,6 +256,11 @@ multi-hotkey-input {
}
}
.item:has(.duplicate) {
background-color: theme-color('danger');
border: 1px solid theme-color('danger');
}
.add {
color: #777;
padding: 4px 10px 0;
@ -265,6 +270,11 @@ multi-hotkey-input {
&:hover { background: darken($body-bg2, 5%); }
&:active { background: darken($body-bg2, 15%); }
}
.add:has(.duplicate), .item:has(.duplicate) .body, .item:has(.duplicate) .remove {
&:hover { background: darken(theme-color('danger'), 5%); }
&:active { background: darken(theme-color('danger'), 15%); }
}
}
hotkey-input-modal {

View file

@ -162,6 +162,11 @@ multi-hotkey-input {
}
}
.item:has(.duplicate) {
background-color: theme-color('danger');
border: 1px solid theme-color('danger');
}
.add {
color: #777;
padding: 4px 10px 0;
@ -171,6 +176,11 @@ multi-hotkey-input {
&:hover { background: darken($body-bg2, 5%); }
&:active { background: darken($body-bg2, 15%); }
}
.add:has(.duplicate), .item:has(.duplicate) .body, .item:has(.duplicate) .remove {
&:hover { background: darken(theme-color('danger'), 5%); }
&:active { background: darken(theme-color('danger'), 15%); }
}
}
hotkey-input-modal {

View file

@ -14,6 +14,6 @@ h3.mb-3(translate) Hotkeys
span.ml-2.text-muted ({{hotkey.id}})
.col-4.pr-5
multi-hotkey-input(
[model]='getHotkey(hotkey.id) || []',
(modelChange)='setHotkey(hotkey.id, $event)'
[hotkeys]='getHotkeys(hotkey.id) || []',
(hotkeysChange)='setHotkeys(hotkey.id, $event)'
)

View file

@ -7,6 +7,7 @@ import {
HotkeysService,
HostAppService,
} from 'tabby-core'
import { Hotkey } from 'tabby-core/src/api/hotkeyProvider'
_('Search hotkeys')
@ -30,28 +31,44 @@ export class HotkeySettingsTabComponent {
})
}
getHotkey (id: string) {
getHotkeys (id: string): Hotkey[] {
let ptr = this.config.store.hotkeys
for (const token of id.split(/\./g)) {
ptr = ptr[token]
}
return ptr
return (ptr || []).map(hotkey => this.detectDuplicates(hotkey))
}
setHotkey (id: string, value) {
setHotkeys (id: string, hotkeys: Hotkey[]) {
let ptr = this.config.store
let prop = 'hotkeys'
for (const token of id.split(/\./g)) {
ptr = ptr[prop]
prop = token
}
ptr[prop] = value
ptr[prop] = hotkeys.map(hotkey =>
hotkey.strokes.length === 1 && Array.isArray(hotkey.strokes)
? hotkey.strokes[0]
: hotkey.strokes,
)
this.config.save()
}
hotkeyFilterFn (hotkey: HotkeyDescription, query: string): boolean {
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
const s = hotkey.name + hotkey.id + (this.getHotkey(hotkey.id) || []).toString()
const s = hotkey.name + hotkey.id + this.getHotkeys(hotkey.id).map(h => h.strokes).toString()
return s.toLowerCase().includes(query.toLowerCase())
}
private detectDuplicates (strokes: string[] | string): Hotkey {
const allHotkeys = Object
.values(this.config.store.hotkeys)
.filter((value: unknown) => Array.isArray(value))
.flat()
const isDuplicate = allHotkeys
.filter(hotkey => JSON.stringify(hotkey) === JSON.stringify(strokes))
.length > 1
return { strokes, isDuplicate }
}
}

View file

@ -1,6 +1,8 @@
.item(*ngFor='let item of model')
.body((click)='editItem(item)')
.stroke(*ngFor='let stroke of item') {{stroke}}
.remove((click)='removeItem(item)') ×
.item(*ngFor='let hotkey of hotkeys')
.body((click)='editItem(hotkey)')
.stroke(*ngFor='let stroke of hotkey.strokes')
span(*ngIf='!hotkey.isDuplicate', translate) {{stroke}}
span.duplicate(*ngIf='hotkey.isDuplicate', translate) {{stroke}}
.remove((click)='removeItem(hotkey)') ×
.add((click)='addItem()', translate) Add...

View file

@ -1,6 +1,7 @@
import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { HotkeyInputModalComponent } from './hotkeyInputModal.component'
import { Hotkey } from 'tabby-core/src/api/hotkeyProvider'
/** @hidden */
@Component({
@ -10,37 +11,41 @@ import { HotkeyInputModalComponent } from './hotkeyInputModal.component'
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MultiHotkeyInputComponent {
@Input() model: string[][] = []
@Output() modelChange = new EventEmitter()
@Input() hotkeys: Hotkey[] = []
@Output() hotkeysChange = new EventEmitter()
constructor (
private ngbModal: NgbModal,
) { }
ngOnChanges (): void {
if (typeof this.model === 'string') {
this.model = [this.model]
}
this.model = this.model.map(item => typeof item === 'string' ? [item] : item)
this.hotkeys = this.hotkeys.map(hotkey => typeof hotkey.strokes === 'string' ? { ...hotkey, strokes: [hotkey.strokes] } : hotkey)
}
editItem (item: string[]): void {
this.ngbModal.open(HotkeyInputModalComponent).result.then((value: string[]) => {
this.model[this.model.findIndex(x => x === item)] = value
this.model = this.model.slice()
this.modelChange.emit(this.model)
editItem (item: Hotkey): void {
this.ngbModal.open(HotkeyInputModalComponent).result.then((newStrokes: string[]) => {
this.hotkeys.find(hotkey => this.isEqual(hotkey, item))!.strokes = newStrokes
this.storeUpdatedHotkeys()
})
}
addItem (): void {
this.ngbModal.open(HotkeyInputModalComponent).result.then((value: string[]) => {
this.model = this.model.concat([value])
this.modelChange.emit(this.model)
this.hotkeys.push({ strokes: value, isDuplicate: false })
this.storeUpdatedHotkeys()
})
}
removeItem (item: string[]): void {
this.model = this.model.filter(x => x !== item)
this.modelChange.emit(this.model)
removeItem (item: Hotkey): void {
this.hotkeys = this.hotkeys.filter(x => x !== item)
this.storeUpdatedHotkeys()
}
private storeUpdatedHotkeys () {
this.hotkeysChange.emit(this.hotkeys)
}
private isEqual (h: Hotkey, item: Hotkey) {
return JSON.stringify(h.strokes) === JSON.stringify(item.strokes)
}
}