mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-06-20 03:13:31 -07:00
feat(notifications): add overlay notifications with position config (#110)
This commit is contained in:
@@ -41,6 +41,7 @@ export const IPC_CHANNELS = {
|
||||
reportOverlayContentBounds: 'overlay-content-bounds:report',
|
||||
reportOverlayInteractive: 'overlay-interactive:report',
|
||||
overlayModalOpened: 'overlay:modal-opened',
|
||||
overlayNotificationAction: 'overlay:notification-action',
|
||||
toggleStatsOverlay: 'stats:toggle-overlay',
|
||||
markActiveVideoWatched: 'immersion:mark-active-video-watched',
|
||||
dispatchSessionAction: 'session-action:dispatch',
|
||||
@@ -61,6 +62,7 @@ export const IPC_CHANNELS = {
|
||||
getConfigShortcuts: 'get-config-shortcuts',
|
||||
getStatsToggleKey: 'get-stats-toggle-key',
|
||||
getMarkWatchedKey: 'get-mark-watched-key',
|
||||
getOverlayNotificationPosition: 'get-overlay-notification-position',
|
||||
getControllerConfig: 'get-controller-config',
|
||||
getSecondarySubMode: 'get-secondary-sub-mode',
|
||||
getCurrentSecondarySub: 'get-current-secondary-sub',
|
||||
@@ -144,6 +146,8 @@ export const IPC_CHANNELS = {
|
||||
subtitleSidebarToggle: 'subtitle-sidebar:toggle',
|
||||
primarySubtitleBarToggle: 'primary-subtitle-bar:toggle',
|
||||
configHotReload: 'config:hot-reload',
|
||||
overlayNotification: 'overlay:notification',
|
||||
notificationHistoryToggle: 'notification-history:toggle',
|
||||
},
|
||||
} as const;
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
|
||||
import { DEFAULT_CONFIG, DEFAULT_KEYBINDINGS } from '../../config/definitions';
|
||||
import { compileSessionBindings } from '../../core/services/session-bindings';
|
||||
import { resolveConfiguredShortcuts } from '../../core/utils/shortcut-config';
|
||||
import { parseSessionActionDispatchRequest } from './validators';
|
||||
|
||||
// Regression guard: SESSION_ACTION_IDS in validators.ts is a hand-maintained mirror of the
|
||||
// SessionActionId union. If a new shortcut-backed action is added to the union/defaults but not to
|
||||
// the validator allow-list, the renderer's dispatchSessionAction IPC is rejected at runtime (which
|
||||
// surfaces as a "Renderer error recovered" toast). Compile every default binding and assert the
|
||||
// validator accepts each one so the two lists can't silently drift apart.
|
||||
test('every default session-action binding is accepted by parseSessionActionDispatchRequest', () => {
|
||||
const { bindings } = compileSessionBindings({
|
||||
shortcuts: resolveConfiguredShortcuts(DEFAULT_CONFIG, DEFAULT_CONFIG),
|
||||
keybindings: DEFAULT_KEYBINDINGS,
|
||||
statsToggleKey: DEFAULT_CONFIG.stats.toggleKey,
|
||||
statsMarkWatchedKey: DEFAULT_CONFIG.stats.markWatchedKey,
|
||||
platform: 'linux',
|
||||
rawConfig: DEFAULT_CONFIG,
|
||||
});
|
||||
|
||||
const sessionActions = bindings.filter((binding) => binding.actionType === 'session-action');
|
||||
assert.ok(sessionActions.length > 0, 'expected default session-action bindings to exist');
|
||||
|
||||
for (const binding of sessionActions) {
|
||||
if (binding.actionType !== 'session-action') continue;
|
||||
const request =
|
||||
binding.payload === undefined
|
||||
? { actionId: binding.actionId }
|
||||
: { actionId: binding.actionId, payload: binding.payload };
|
||||
assert.ok(
|
||||
parseSessionActionDispatchRequest(request) !== null,
|
||||
`validator rejected session action: ${binding.actionId}`,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test('toggleNotificationHistory dispatch request is accepted', () => {
|
||||
assert.deepEqual(parseSessionActionDispatchRequest({ actionId: 'toggleNotificationHistory' }), {
|
||||
actionId: 'toggleNotificationHistory',
|
||||
});
|
||||
});
|
||||
@@ -20,6 +20,7 @@ const RESERVED_CONTROLLER_PROFILE_IDS = new Set(['__proto__', 'constructor', 'pr
|
||||
|
||||
const SESSION_ACTION_IDS: SessionActionId[] = [
|
||||
'toggleStatsOverlay',
|
||||
'markWatched',
|
||||
'toggleVisibleOverlay',
|
||||
'copySubtitle',
|
||||
'copySubtitleMultiple',
|
||||
@@ -31,6 +32,7 @@ const SESSION_ACTION_IDS: SessionActionId[] = [
|
||||
'toggleSecondarySub',
|
||||
'markAudioCard',
|
||||
'toggleSubtitleSidebar',
|
||||
'toggleNotificationHistory',
|
||||
'openRuntimeOptions',
|
||||
'openSessionHelp',
|
||||
'openCharacterDictionaryManager',
|
||||
|
||||
@@ -10,9 +10,13 @@ export interface SubminerPluginRuntimeScriptOptConfig {
|
||||
autoStart: boolean;
|
||||
autoStartVisibleOverlay: boolean;
|
||||
autoStartPauseUntilReady: boolean;
|
||||
overlayLoadingOsd?: boolean;
|
||||
osdMessages: boolean;
|
||||
texthookerEnabled: boolean;
|
||||
}
|
||||
|
||||
const AUTO_START_PAUSE_UNTIL_READY_TIMEOUT_SECONDS = 30;
|
||||
|
||||
function boolScriptOpt(value: boolean): 'yes' | 'no' {
|
||||
return value ? 'yes' : 'no';
|
||||
}
|
||||
@@ -32,15 +36,21 @@ export function buildSubminerPluginRuntimeScriptOptParts(
|
||||
const binaryPath = sanitizeScriptOptValue(runtimeConfig.binaryPath?.trim() || fallbackAppPath);
|
||||
const socketPath = sanitizeScriptOptValue(runtimeConfig.socketPath);
|
||||
const backend = sanitizeScriptOptValue(runtimeConfig.backend);
|
||||
const overlayLoadingOsd =
|
||||
runtimeConfig.overlayLoadingOsd ??
|
||||
(runtimeConfig.autoStart && runtimeConfig.autoStartVisibleOverlay);
|
||||
return [
|
||||
`subminer-binary_path=${binaryPath}`,
|
||||
`subminer-socket_path=${socketPath}`,
|
||||
`subminer-backend=${backend}`,
|
||||
`subminer-auto_start=${boolScriptOpt(runtimeConfig.autoStart)}`,
|
||||
`subminer-auto_start_visible_overlay=${boolScriptOpt(runtimeConfig.autoStartVisibleOverlay)}`,
|
||||
`subminer-overlay_loading_osd=${boolScriptOpt(overlayLoadingOsd)}`,
|
||||
`subminer-auto_start_pause_until_ready=${boolScriptOpt(
|
||||
runtimeConfig.autoStartPauseUntilReady,
|
||||
)}`,
|
||||
`subminer-auto_start_pause_until_ready_timeout_seconds=${AUTO_START_PAUSE_UNTIL_READY_TIMEOUT_SECONDS}`,
|
||||
`subminer-osd_messages=${boolScriptOpt(runtimeConfig.osdMessages)}`,
|
||||
`subminer-texthooker_enabled=${boolScriptOpt(runtimeConfig.texthookerEnabled)}`,
|
||||
];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user