mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-08-06 07:21:33 -07:00
feat(overlay): add in-app changelog modal
- Add a changelog modal opened from tray "View Changelog" or the update notification's "What's New" button; renders in-player or in its own window like the help modal - Fetch changelog from the newest published release so newer-than-installed notes are visible, falling back to the bundled CHANGELOG.md on failure - Group versions by minor line (current expanded, older folded), badge the installed version, tag newer ones "New" - Support J/K/arrow navigation, Enter to fold/unfold, R to refetch, Esc to close - Add changelog parsing/semver-compare utils and changelog IPC channel/runtime; bundle CHANGELOG.md into packaged builds - Replace release/release-notes.md with changes/changelog-modal.md changeset entry
This commit is contained in:
@@ -456,6 +456,7 @@ function createKeyboardHandlerHarness() {
|
||||
let openControllerSelectCount = 0;
|
||||
let openControllerDebugCount = 0;
|
||||
let playlistBrowserKeydownCount = 0;
|
||||
let changelogKeydownCount = 0;
|
||||
|
||||
const createWordNode = (left: number) => ({
|
||||
classList: createClassList(),
|
||||
@@ -504,6 +505,10 @@ function createKeyboardHandlerHarness() {
|
||||
return true;
|
||||
},
|
||||
handleSessionHelpKeydown: () => false,
|
||||
handleChangelogKeydown: () => {
|
||||
changelogKeydownCount += 1;
|
||||
return true;
|
||||
},
|
||||
openSessionHelpModal: () => {},
|
||||
openControllerSelectModal: () => {
|
||||
openControllerSelectCount += 1;
|
||||
@@ -522,6 +527,7 @@ function createKeyboardHandlerHarness() {
|
||||
openControllerSelectCount: () => openControllerSelectCount,
|
||||
openControllerDebugCount: () => openControllerDebugCount,
|
||||
playlistBrowserKeydownCount: () => playlistBrowserKeydownCount,
|
||||
changelogKeydownCount: () => changelogKeydownCount,
|
||||
setWordCount: (count: number) => {
|
||||
wordNodes = Array.from({ length: count }, (_, index) => createWordNode(10 + index * 70));
|
||||
},
|
||||
@@ -1404,6 +1410,50 @@ test('keyboard mode: playlist browser modal handles h before lookup controls', a
|
||||
}
|
||||
});
|
||||
|
||||
test('keyboard mode: changelog modal handles h/l fold keys before lookup controls', async () => {
|
||||
const { ctx, testGlobals, handlers, changelogKeydownCount } = createKeyboardHandlerHarness();
|
||||
|
||||
try {
|
||||
await handlers.setupMpvInputForwarding();
|
||||
handlers.handleKeyboardModeToggleRequested();
|
||||
ctx.state.changelogModalOpen = true;
|
||||
ctx.state.keyboardSelectedWordIndex = 2;
|
||||
|
||||
// H and L fold/unfold changelog entries; they must not move the subtitle
|
||||
// word selection or seek mpv behind the open modal.
|
||||
testGlobals.dispatchKeydown({ key: 'h', code: 'KeyH' });
|
||||
testGlobals.dispatchKeydown({ key: 'l', code: 'KeyL' });
|
||||
|
||||
assert.equal(changelogKeydownCount(), 2);
|
||||
assert.equal(ctx.state.keyboardSelectedWordIndex, 2);
|
||||
} finally {
|
||||
testGlobals.restore();
|
||||
}
|
||||
});
|
||||
|
||||
test('keyboard mode: changelog modal handles arrow keys before yomitan popup', async () => {
|
||||
const { ctx, testGlobals, handlers, changelogKeydownCount } = createKeyboardHandlerHarness();
|
||||
|
||||
try {
|
||||
await handlers.setupMpvInputForwarding();
|
||||
ctx.state.changelogModalOpen = true;
|
||||
ctx.state.yomitanPopupVisible = true;
|
||||
testGlobals.setPopupVisible(true);
|
||||
|
||||
testGlobals.dispatchKeydown({ key: 'ArrowDown', code: 'ArrowDown' });
|
||||
|
||||
assert.equal(changelogKeydownCount(), 1);
|
||||
assert.equal(
|
||||
testGlobals.commandEvents.some(
|
||||
(event) => event.type === 'forwardKeyDown' && event.code === 'ArrowDown',
|
||||
),
|
||||
false,
|
||||
);
|
||||
} finally {
|
||||
testGlobals.restore();
|
||||
}
|
||||
});
|
||||
|
||||
test('keyboard mode: configured stats toggle works even while popup is open', async () => {
|
||||
const { handlers, testGlobals } = createKeyboardHandlerHarness();
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ export function createKeyboardHandlers(
|
||||
handleControllerSelectKeydown: (e: KeyboardEvent) => boolean;
|
||||
handleControllerDebugKeydown: (e: KeyboardEvent) => boolean;
|
||||
handleSessionHelpKeydown: (e: KeyboardEvent) => boolean;
|
||||
handleChangelogKeydown: (e: KeyboardEvent) => boolean;
|
||||
openSessionHelpModal: (opening: {
|
||||
bindingKey: 'KeyH' | 'KeyK';
|
||||
fallbackUsed: boolean;
|
||||
@@ -1095,6 +1096,14 @@ export function createKeyboardHandlers(
|
||||
}
|
||||
}
|
||||
|
||||
// Ahead of the keyboard-driven lookup controls: the changelog modal binds
|
||||
// arrows/H/L for folding, and those would otherwise move the subtitle word
|
||||
// selection (and seek mpv) behind the open modal.
|
||||
if (ctx.state.changelogModalOpen) {
|
||||
options.handleChangelogKeydown(e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (handleKeyboardDrivenModeLookupControls(e)) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user