mirror of
https://github.com/Kvan7/Exiled-Exchange-2.git
synced 2025-12-08 09:05:44 +00:00
Shortcuts for Stopwatch, closes #368
This commit is contained in:
@@ -18,7 +18,8 @@ export type IpcEvent =
|
|||||||
IpcOpenCraftOfExile |
|
IpcOpenCraftOfExile |
|
||||||
IpcImportFile |
|
IpcImportFile |
|
||||||
IpcToggleDelveGrid |
|
IpcToggleDelveGrid |
|
||||||
IpcClientLog
|
IpcClientLog |
|
||||||
|
IpcStopwatchAction
|
||||||
|
|
||||||
export type IpcEventPayload<Name extends IpcEvent['name'], T extends IpcEvent = IpcEvent> =
|
export type IpcEventPayload<Name extends IpcEvent['name'], T extends IpcEvent = IpcEvent> =
|
||||||
T extends { name: Name } ? T['payload'] : never
|
T extends { name: Name } ? T['payload'] : never
|
||||||
@@ -103,6 +104,12 @@ export type IpcClientLog =
|
|||||||
lines: string[]
|
lines: string[]
|
||||||
}>
|
}>
|
||||||
|
|
||||||
|
export type IpcStopwatchAction =
|
||||||
|
Event<'MAIN->OVERLAY::stopwatch', {
|
||||||
|
wmId: number
|
||||||
|
type: 'start-stop' | 'reset'
|
||||||
|
}>
|
||||||
|
|
||||||
interface Event<TName extends string, TPayload = undefined> {
|
interface Event<TName extends string, TPayload = undefined> {
|
||||||
name: TName
|
name: TName
|
||||||
payload: TPayload
|
payload: TPayload
|
||||||
|
|||||||
@@ -57,6 +57,8 @@ export interface ItemCheckWidget extends Widget {
|
|||||||
|
|
||||||
export interface StopwatchWidget extends Widget {
|
export interface StopwatchWidget extends Widget {
|
||||||
anchor: Anchor
|
anchor: Anchor
|
||||||
|
toggleKey: string | null
|
||||||
|
resetKey: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StashSearchWidget extends Widget {
|
export interface StashSearchWidget extends Widget {
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import { config } from './config'
|
|||||||
import { PoeWindow } from './PoeWindow'
|
import { PoeWindow } from './PoeWindow'
|
||||||
import { logger } from './logger'
|
import { logger } from './logger'
|
||||||
import { toggleOverlayState, assertOverlayActive, assertPoEActive, overlayOnEvent, overlaySendEvent } from './overlay-window'
|
import { toggleOverlayState, assertOverlayActive, assertPoEActive, overlayOnEvent, overlaySendEvent } from './overlay-window'
|
||||||
import * as ipc from '../../ipc/ipc-event'
|
import type * as ipc from '../../ipc/ipc-event'
|
||||||
import { StashSearchWidget } from '../../ipc/widgets'
|
import type * as widget from '../../ipc/widgets'
|
||||||
import { typeInChat } from './game-chat'
|
import { typeInChat } from './game-chat'
|
||||||
import { gameConfig } from './game-config'
|
import { gameConfig } from './game-config'
|
||||||
import { restoreClipboard } from './clipboard-saver'
|
import { restoreClipboard } from './clipboard-saver'
|
||||||
@@ -29,10 +29,12 @@ export interface ShortcutAction {
|
|||||||
'price-check-locked'
|
'price-check-locked'
|
||||||
)
|
)
|
||||||
focusOverlay?: boolean
|
focusOverlay?: boolean
|
||||||
} | {
|
} | ({
|
||||||
type: 'trigger-event'
|
type: 'trigger-event'
|
||||||
eventName: ipc.IpcToggleDelveGrid['name']
|
} & (
|
||||||
} | {
|
ShortcutActionTriggerEvent<ipc.IpcToggleDelveGrid['name']> |
|
||||||
|
ShortcutActionTriggerEvent<ipc.IpcStopwatchAction['name']>
|
||||||
|
)) | {
|
||||||
type: 'stash-search'
|
type: 'stash-search'
|
||||||
text: string
|
text: string
|
||||||
} | {
|
} | {
|
||||||
@@ -46,6 +48,11 @@ export interface ShortcutAction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ShortcutActionTriggerEvent<Name extends ipc.IpcEvent['name']> {
|
||||||
|
eventName: Name
|
||||||
|
payload: ipc.IpcEventPayload<Name>
|
||||||
|
}
|
||||||
|
|
||||||
function shortcutsFromConfig () {
|
function shortcutsFromConfig () {
|
||||||
let actions: ShortcutAction[] = []
|
let actions: ShortcutAction[] = []
|
||||||
|
|
||||||
@@ -89,7 +96,7 @@ function shortcutsFromConfig () {
|
|||||||
if (config.get('delveGridKey')) {
|
if (config.get('delveGridKey')) {
|
||||||
actions.push({
|
actions.push({
|
||||||
shortcut: config.get('delveGridKey')!,
|
shortcut: config.get('delveGridKey')!,
|
||||||
action: { type: 'trigger-event', eventName: 'MAIN->OVERLAY::delve-grid' },
|
action: { type: 'trigger-event', eventName: 'MAIN->OVERLAY::delve-grid', payload: undefined },
|
||||||
keepModKeys: true
|
keepModKeys: true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -110,7 +117,7 @@ function shortcutsFromConfig () {
|
|||||||
}
|
}
|
||||||
for (const widget of config.get('widgets')) {
|
for (const widget of config.get('widgets')) {
|
||||||
if (widget.wmType === 'stash-search') {
|
if (widget.wmType === 'stash-search') {
|
||||||
const stashSearch = widget as StashSearchWidget
|
const stashSearch = widget as widget.StashSearchWidget
|
||||||
for (const entry of stashSearch.entries) {
|
for (const entry of stashSearch.entries) {
|
||||||
if (entry.hotkey) {
|
if (entry.hotkey) {
|
||||||
actions.push({
|
actions.push({
|
||||||
@@ -119,6 +126,30 @@ function shortcutsFromConfig () {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (widget.wmType === 'timer') {
|
||||||
|
const stopwatch = widget as widget.StopwatchWidget
|
||||||
|
if (stopwatch.toggleKey) {
|
||||||
|
actions.push({
|
||||||
|
shortcut: stopwatch.toggleKey,
|
||||||
|
keepModKeys: true,
|
||||||
|
action: {
|
||||||
|
type: 'trigger-event',
|
||||||
|
eventName: 'MAIN->OVERLAY::stopwatch',
|
||||||
|
payload: { wmId: widget.wmId, type: 'start-stop' }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (stopwatch.resetKey) {
|
||||||
|
actions.push({
|
||||||
|
shortcut: stopwatch.resetKey,
|
||||||
|
keepModKeys: true,
|
||||||
|
action: {
|
||||||
|
type: 'trigger-event',
|
||||||
|
eventName: 'MAIN->OVERLAY::stopwatch',
|
||||||
|
payload: { wmId: widget.wmId, type: 'reset' }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,7 +203,7 @@ function registerGlobal () {
|
|||||||
} else if (entry.action.type === 'paste-in-chat') {
|
} else if (entry.action.type === 'paste-in-chat') {
|
||||||
typeInChat(entry.action.text, entry.action.send)
|
typeInChat(entry.action.text, entry.action.send)
|
||||||
} else if (entry.action.type === 'trigger-event') {
|
} else if (entry.action.type === 'trigger-event') {
|
||||||
overlaySendEvent({ name: entry.action.eventName, payload: undefined })
|
overlaySendEvent({ name: entry.action.eventName, payload: entry.action.payload } as ipc.IpcEvent)
|
||||||
} else if (entry.action.type === 'stash-search') {
|
} else if (entry.action.type === 'stash-search') {
|
||||||
stashSearch(entry.action.text)
|
stashSearch(entry.action.text)
|
||||||
} else if (entry.action.type === 'copy-item') {
|
} else if (entry.action.type === 'copy-item') {
|
||||||
|
|||||||
@@ -33,10 +33,12 @@ class MainProcessBinding {
|
|||||||
onEvent<Name extends IpcEvent['name']> (
|
onEvent<Name extends IpcEvent['name']> (
|
||||||
name: Name,
|
name: Name,
|
||||||
cb: (payload: IpcEventPayload<Name>) => void
|
cb: (payload: IpcEventPayload<Name>) => void
|
||||||
) {
|
): AbortController {
|
||||||
|
const controller = new AbortController()
|
||||||
this.evBus.addEventListener(name, (e) => {
|
this.evBus.addEventListener(name, (e) => {
|
||||||
cb((e as CustomEvent<IpcEventPayload<Name>>).detail)
|
cb((e as CustomEvent<IpcEventPayload<Name>>).detail)
|
||||||
})
|
}, { signal: controller.signal })
|
||||||
|
return controller
|
||||||
}
|
}
|
||||||
|
|
||||||
closeOverlay () {
|
closeOverlay () {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<widget :config="config" move-handles="center" v-slot="{ isMoving }" readonly :hideable="false">
|
<widget :config="config" move-handles="center" v-slot="{ isMoving }" :inline-edit="false" :hideable="false">
|
||||||
<div :class="$style.wrapper">
|
<div :class="$style.wrapper">
|
||||||
<div :class="$style.timer">
|
<div :class="$style.timer">
|
||||||
<span>{{ formatted.h }}:{{ formatted.m }}:</span><span>{{ formatted.s }}</span>
|
<span>{{ formatted.h }}:{{ formatted.m }}:</span><span>{{ formatted.s }}</span>
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
<div v-if="!isMoving" :class="$style.controls">
|
<div v-if="!isMoving" :class="$style.controls">
|
||||||
<button v-if="!isRunning" @click="start" :class="$style.button"><i class="fas fa-play"></i></button>
|
<button v-if="!isRunning" @click="start" :class="$style.button"><i class="fas fa-play"></i></button>
|
||||||
<button v-else @click="stop" :class="$style.button"><i class="fas fa-pause"></i></button>
|
<button v-else @click="stop" :class="$style.button"><i class="fas fa-pause"></i></button>
|
||||||
<button @click="restart" :class="$style.button"><i class="fas fa-redo"></i></button>
|
<button @click="reset" :class="$style.button"><i class="fas fa-redo"></i></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</widget>
|
</widget>
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
import { defineComponent, PropType, inject, ref, onUnmounted, computed } from 'vue'
|
import { defineComponent, PropType, inject, ref, onUnmounted, computed } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import Widget from './Widget.vue'
|
import Widget from './Widget.vue'
|
||||||
|
import { MainProcess } from '@/web/background/IPC'
|
||||||
import { Duration } from 'luxon'
|
import { Duration } from 'luxon'
|
||||||
import { WidgetManager, StopwatchWidget } from './interfaces'
|
import { WidgetManager, StopwatchWidget } from './interfaces'
|
||||||
|
|
||||||
@@ -38,10 +39,25 @@ export default defineComponent({
|
|||||||
x: (Math.random() * (60 - 40) + 40),
|
x: (Math.random() * (60 - 40) + 40),
|
||||||
y: (Math.random() * (60 - 40) + 40)
|
y: (Math.random() * (60 - 40) + 40)
|
||||||
}
|
}
|
||||||
|
props.config.toggleKey = null
|
||||||
|
props.config.resetKey = null
|
||||||
wm.show(props.config.wmId)
|
wm.show(props.config.wmId)
|
||||||
}
|
}
|
||||||
props.config.wmFlags = ['invisible-on-blur']
|
props.config.wmFlags = ['invisible-on-blur']
|
||||||
|
|
||||||
|
const hotkeyController = MainProcess.onEvent('MAIN->OVERLAY::stopwatch', (action) => {
|
||||||
|
if (action.wmId !== props.config.wmId) return
|
||||||
|
|
||||||
|
if (action.type === 'start-stop') {
|
||||||
|
isRunning.value ? stop() : start()
|
||||||
|
} else if (action.type === 'reset') {
|
||||||
|
reset()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
onUnmounted(() => {
|
||||||
|
hotkeyController.abort()
|
||||||
|
})
|
||||||
|
|
||||||
const isRunning = ref(false)
|
const isRunning = ref(false)
|
||||||
const millis = ref(0)
|
const millis = ref(0)
|
||||||
const prevTick = ref(0)
|
const prevTick = ref(0)
|
||||||
@@ -73,7 +89,7 @@ export default defineComponent({
|
|||||||
wm.setFlag(props.config.wmId, 'invisible-on-blur', true)
|
wm.setFlag(props.config.wmId, 'invisible-on-blur', true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function restart () {
|
function reset () {
|
||||||
prevTick.value = Date.now()
|
prevTick.value = Date.now()
|
||||||
millis.value = (isRunning.value) ? 1000 : 0
|
millis.value = (isRunning.value) ? 1000 : 0
|
||||||
if (!isRunning.value) {
|
if (!isRunning.value) {
|
||||||
@@ -96,7 +112,7 @@ export default defineComponent({
|
|||||||
isRunning,
|
isRunning,
|
||||||
start,
|
start,
|
||||||
stop,
|
stop,
|
||||||
restart
|
reset
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import SettingsPricecheck from './price-check.vue'
|
|||||||
import SettingsDebug from './debug.vue'
|
import SettingsDebug from './debug.vue'
|
||||||
import SettingsMaps from './maps/maps.vue'
|
import SettingsMaps from './maps/maps.vue'
|
||||||
import SettingsStashSearch from './stash-search.vue'
|
import SettingsStashSearch from './stash-search.vue'
|
||||||
|
import SettingsStopwatch from './stopwatch.vue'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
@@ -121,6 +122,8 @@ function menuByType (type?: string) {
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case 'stash-search':
|
case 'stash-search':
|
||||||
return [[SettingsStashSearch]]
|
return [[SettingsStashSearch]]
|
||||||
|
case 'timer':
|
||||||
|
return [[SettingsStopwatch]]
|
||||||
default:
|
default:
|
||||||
return [
|
return [
|
||||||
[SettingsHotkeys, SettingsChat],
|
[SettingsHotkeys, SettingsChat],
|
||||||
@@ -185,7 +188,8 @@ function flatJoin<T, J> (arr: T[][], joinEl: () => J) {
|
|||||||
"Maps": "Карты",
|
"Maps": "Карты",
|
||||||
"Debug": "Debug",
|
"Debug": "Debug",
|
||||||
"Chat": "Чат",
|
"Chat": "Чат",
|
||||||
"Stash search": "Поиск в тайнике"
|
"Stash search": "Поиск в тайнике",
|
||||||
|
"Stopwatch": "Секундомер"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|||||||
44
renderer/src/web/settings/stopwatch.vue
Normal file
44
renderer/src/web/settings/stopwatch.vue
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<template>
|
||||||
|
<div class="max-w-md p-2">
|
||||||
|
<div class="mb-4 flex">
|
||||||
|
<label class="flex-1">{{ t('Start and Pause') }}</label>
|
||||||
|
<hotkey-input v-model="toggleKey" class="w-48" />
|
||||||
|
</div>
|
||||||
|
<div class="mb-4 flex">
|
||||||
|
<label class="flex-1">{{ t('Reset') }}</label>
|
||||||
|
<hotkey-input v-model="resetKey" class="w-48" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import HotkeyInput from './HotkeyInput.vue'
|
||||||
|
import { configProp, configModelValue } from './utils'
|
||||||
|
import type { StopwatchWidget } from '@/web/overlay/interfaces'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'Stopwatch',
|
||||||
|
components: { HotkeyInput },
|
||||||
|
props: configProp<StopwatchWidget>(),
|
||||||
|
setup (props) {
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
return {
|
||||||
|
t,
|
||||||
|
toggleKey: configModelValue(() => props.configWidget, 'toggleKey'),
|
||||||
|
resetKey: configModelValue(() => props.configWidget, 'resetKey')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
{
|
||||||
|
"ru": {
|
||||||
|
"Start and Pause": "Старт и пауза",
|
||||||
|
"Reset": "Сброс"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</i18n>
|
||||||
Reference in New Issue
Block a user