Skip to content

Commit f075160

Browse files
committed
feat: wrap annotations / trim toggle under menu-view
1 parent 14019ab commit f075160

10 files changed

Lines changed: 136 additions & 11 deletions

File tree

‎electron/main/ipc/window-ipc.mjs‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,24 @@ export function registerWindowIPC({
1919
menu.updateMenu(target);
2020
return true;
2121
});
22+
handle('window:view-state', (event, value) => {
23+
const target = trustedWindow(event);
24+
if (
25+
!value ||
26+
typeof value !== 'object' ||
27+
!['annotations', 'annotationsAvailable', 'crop'].every(
28+
(key) => typeof value[key] === 'boolean',
29+
)
30+
)
31+
throw Error('Invalid view state.');
32+
registry.stateFor(target).viewState = {
33+
annotations: value.annotations,
34+
annotationsAvailable: value.annotationsAvailable,
35+
crop: value.crop,
36+
};
37+
if (target === registry.focusedWindow()) menu.updateMenu(target);
38+
return true;
39+
});
2240
handle('window:register-options', (event, value) => {
2341
const target = trustedWindow(event);
2442
const options = {};

‎electron/main/menus/application-menu.mjs‎

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,19 @@ export function createApplicationMenu({
135135
translateAllPages.enabled = !!registry.stateFor(target)?.performance.hasDocument;
136136
const stopAllTasks = item('translation-stop-all-tasks');
137137
if (stopAllTasks) stopAllTasks.enabled = !!registry.stateFor(target)?.performance.hasDocument;
138+
// Checkbox state mirrors the renderer; Electron flips it locally on click.
139+
const viewState = registry.stateFor(target)?.viewState;
140+
const hasDocument = !!registry.stateFor(target)?.performance.hasDocument;
141+
const annotationsItem = item('view-annotations');
142+
if (annotationsItem) {
143+
annotationsItem.enabled = hasDocument && !!viewState?.annotationsAvailable;
144+
annotationsItem.checked = viewState?.annotations !== false;
145+
}
146+
const cropToggle = item('crop-toggle');
147+
if (cropToggle) {
148+
cropToggle.enabled = hasDocument;
149+
cropToggle.checked = hasDocument && !!viewState?.crop;
150+
}
138151
const state = registry.stateFor(target)?.preferences;
139152
if (!state) return;
140153
const layout = item('layout-' + (state.direction || 'vertical'));
@@ -487,12 +500,34 @@ export function createApplicationMenu({
487500
command('Fit Height', accelerator('9'), 'fit-height', 'view-fit-height'),
488501
command('Toggle Sidebar', accelerator('B'), 'sidebar', 'view-sidebar'),
489502
{ type: 'separator' },
490-
{ id: 'view-crop', label: 'Page Crop', enabled: false },
491-
command('Crop More Horizontally', undefined, 'crop:x:more', 'crop-x-more'),
492-
command('Crop Less Horizontally', undefined, 'crop:x:less', 'crop-x-less'),
493-
command('Crop More Vertically', undefined, 'crop:y:more', 'crop-y-more'),
494-
command('Crop Less Vertically', undefined, 'crop:y:less', 'crop-y-less'),
495-
command('Reset Crop', undefined, 'crop:reset', 'crop-reset'),
503+
{
504+
...command(
505+
'Show Highlights and Comments',
506+
undefined,
507+
'annotations',
508+
'view-annotations',
509+
),
510+
type: 'checkbox',
511+
checked: true,
512+
enabled: false,
513+
},
514+
{
515+
id: 'view-crop',
516+
label: 'Page Crop',
517+
submenu: [
518+
{
519+
...command('Trim Margins', undefined, 'crop:toggle', 'crop-toggle'),
520+
type: 'checkbox',
521+
checked: false,
522+
},
523+
{ type: 'separator' },
524+
command('Crop More Horizontally', undefined, 'crop:x:more', 'crop-x-more'),
525+
command('Crop Less Horizontally', undefined, 'crop:x:less', 'crop-x-less'),
526+
command('Crop More Vertically', undefined, 'crop:y:more', 'crop-y-more'),
527+
command('Crop Less Vertically', undefined, 'crop:y:less', 'crop-y-less'),
528+
command('Reset Crop', undefined, 'crop:reset', 'crop-reset'),
529+
],
530+
},
496531
{ type: 'separator' },
497532
{ id: 'view-layout', label: 'Layout', enabled: false },
498533
...['vertical', 'horizontal'].map((direction) => ({

‎electron/preload.cjs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ contextBridge.exposeInMainWorld(
134134
'previewActions',
135135
Object.freeze({
136136
translatedFileReady: (ready) => ipcRenderer.invoke('window:translated-file-ready', ready),
137+
viewState: (value) => ipcRenderer.invoke('window:view-state', value),
137138
onAction: (callback) => {
138139
const listener = (_event, action, selectionText) => callback(action, selectionText);
139140
ipcRenderer.on('reader:action', listener);

‎shared/commands/shortcuts.mjs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ const entries = [
2525
['fit-width', 'Fit Width', 'View', 'view-fit-width', '0'],
2626
['fit-height', 'Fit Height', 'View', 'view-fit-height', '9'],
2727
['sidebar', 'Toggle Sidebar', 'View', 'view-sidebar', 'B'],
28+
['annotations', 'Show Highlights and Comments', 'View', 'view-annotations'],
29+
['crop:toggle', 'Trim Margins', 'View', 'crop-toggle'],
2830
['crop:x:more', 'Crop More Horizontally', 'View', 'crop-x-more'],
2931
['crop:x:less', 'Crop Less Horizontally', 'View', 'crop-x-less'],
3032
['crop:y:more', 'Crop More Vertically', 'View', 'crop-y-more'],

‎shared/i18n/menu-extra.mjs‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ export const MENU_EXTRA_MESSAGES = {
3030
'Fit Width': 'ملاءمة العرض',
3131
'Fit Height': 'ملاءمة الارتفاع',
3232
'Toggle Sidebar': 'تبديل الشريط الجانبي',
33+
'Show Highlights and Comments': 'إظهار التمييزات والتعليقات',
3334
'Page Crop': 'اقتصاص الصفحة',
35+
'Trim Margins': 'قص الهوامش',
3436
'Crop More Horizontally': 'اقتصاص أفقي أكبر',
3537
'Crop Less Horizontally': 'اقتصاص أفقي أقل',
3638
'Crop More Vertically': 'اقتصاص عمودي أكبر',
@@ -100,7 +102,9 @@ export const MENU_EXTRA_MESSAGES = {
100102
'Fit Width': 'ظبّط العرض',
101103
'Fit Height': 'ظبّط الارتفاع',
102104
'Toggle Sidebar': 'بدّل الشريط الجانبي',
105+
'Show Highlights and Comments': 'ورّي التظليلات والتعليقات',
103106
'Page Crop': 'قصّ الصفحة',
107+
'Trim Margins': 'قصّ الهوامش',
104108
'Crop More Horizontally': 'قصّ أكتر بالعرض',
105109
'Crop Less Horizontally': 'قصّ أقل بالعرض',
106110
'Crop More Vertically': 'قصّ أكتر بالطول',
@@ -170,7 +174,9 @@ export const MENU_EXTRA_MESSAGES = {
170174
'Fit Width': 'चौड़ाई में फ़िट करें',
171175
'Fit Height': 'ऊँचाई में फ़िट करें',
172176
'Toggle Sidebar': 'साइडबार टॉगल करें',
177+
'Show Highlights and Comments': 'हाइलाइट और टिप्पणियाँ दिखाएँ',
173178
'Page Crop': 'पृष्ठ क्रॉप',
179+
'Trim Margins': 'हाशिये ट्रिम करें',
174180
'Crop More Horizontally': 'क्षैतिज रूप से अधिक क्रॉप करें',
175181
'Crop Less Horizontally': 'क्षैतिज रूप से कम क्रॉप करें',
176182
'Crop More Vertically': 'लंबवत रूप से अधिक क्रॉप करें',
@@ -240,7 +246,9 @@ export const MENU_EXTRA_MESSAGES = {
240246
'Fit Width': 'প্রস্থ অনুযায়ী মানানসই করুন',
241247
'Fit Height': 'উচ্চতা অনুযায়ী মানানসই করুন',
242248
'Toggle Sidebar': 'সাইডবার টগল করুন',
249+
'Show Highlights and Comments': 'হাইলাইট ও মন্তব্য দেখান',
243250
'Page Crop': 'পৃষ্ঠা ক্রপ',
251+
'Trim Margins': 'মার্জিন ছাঁটুন',
244252
'Crop More Horizontally': 'অনুভূমিকভাবে আরও ক্রপ করুন',
245253
'Crop Less Horizontally': 'অনুভূমিকভাবে কম ক্রপ করুন',
246254
'Crop More Vertically': 'উল্লম্বভাবে আরও ক্রপ করুন',
@@ -310,7 +318,9 @@ export const MENU_EXTRA_MESSAGES = {
310318
'Fit Width': 'По ширине',
311319
'Fit Height': 'По высоте',
312320
'Toggle Sidebar': 'Показать/скрыть боковую панель',
321+
'Show Highlights and Comments': 'Показать выделения и комментарии',
313322
'Page Crop': 'Обрезка страницы',
323+
'Trim Margins': 'Обрезать поля',
314324
'Crop More Horizontally': 'Сильнее обрезать по горизонтали',
315325
'Crop Less Horizontally': 'Слабее обрезать по горизонтали',
316326
'Crop More Vertically': 'Сильнее обрезать по вертикали',
@@ -380,7 +390,9 @@ export const MENU_EXTRA_MESSAGES = {
380390
'Fit Width': 'Ajustar à largura',
381391
'Fit Height': 'Ajustar à altura',
382392
'Toggle Sidebar': 'Mostrar/ocultar barra lateral',
393+
'Show Highlights and Comments': 'Mostrar destaques e comentários',
383394
'Page Crop': 'Recorte de página',
395+
'Trim Margins': 'Aparar margens',
384396
'Crop More Horizontally': 'Recortar mais horizontalmente',
385397
'Crop Less Horizontally': 'Recortar menos horizontalmente',
386398
'Crop More Vertically': 'Recortar mais verticalmente',
@@ -450,7 +462,9 @@ export const MENU_EXTRA_MESSAGES = {
450462
'Fit Width': 'چوڑائی کے مطابق کریں',
451463
'Fit Height': 'اونچائی کے مطابق کریں',
452464
'Toggle Sidebar': 'سائیڈبار تبدیل کریں',
465+
'Show Highlights and Comments': 'ہائی لائٹس اور تبصرے دکھائیں',
453466
'Page Crop': 'صفحہ تراشیں',
467+
'Trim Margins': 'حاشیے تراشیں',
454468
'Crop More Horizontally': 'افقی طور پر مزید تراشیں',
455469
'Crop Less Horizontally': 'افقی طور پر کم تراشیں',
456470
'Crop More Vertically': 'عمودی طور پر مزید تراشیں',
@@ -520,7 +534,9 @@ export const MENU_EXTRA_MESSAGES = {
520534
'Fit Width': 'An Breite anpassen',
521535
'Fit Height': 'An Höhe anpassen',
522536
'Toggle Sidebar': 'Seitenleiste ein-/ausblenden',
537+
'Show Highlights and Comments': 'Hervorhebungen und Kommentare anzeigen',
523538
'Page Crop': 'Seitenzuschnitt',
539+
'Trim Margins': 'Ränder beschneiden',
524540
'Crop More Horizontally': 'Horizontal stärker zuschneiden',
525541
'Crop Less Horizontally': 'Horizontal weniger zuschneiden',
526542
'Crop More Vertically': 'Vertikal stärker zuschneiden',
@@ -590,7 +606,9 @@ export const MENU_EXTRA_MESSAGES = {
590606
'Fit Width': 'Fit width',
591607
'Fit Height': 'Fit height',
592608
'Toggle Sidebar': 'Show/hide sidebar',
609+
'Show Highlights and Comments': 'Show highlight and comment dem',
593610
'Page Crop': 'Cut page',
611+
'Trim Margins': 'Cut page edge dem',
594612
'Crop More Horizontally': 'Cut more side to side',
595613
'Crop Less Horizontally': 'Cut less side to side',
596614
'Crop More Vertically': 'Cut more up and down',

‎shared/i18n/menu.mjs‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ const menuMessages = {
4444
'Fit Width': 'Fit Width',
4545
'Fit Height': 'Fit Height',
4646
'Toggle Sidebar': 'Toggle Sidebar',
47+
'Show Highlights and Comments': 'Show Highlights and Comments',
4748
'Page Crop': 'Page Crop',
49+
'Trim Margins': 'Trim Margins',
4850
'Crop More Horizontally': 'Crop More Horizontally',
4951
'Crop Less Horizontally': 'Crop Less Horizontally',
5052
'Crop More Vertically': 'Crop More Vertically',
@@ -118,7 +120,9 @@ const menuMessages = {
118120
'Fit Width': '适合宽度',
119121
'Fit Height': '适合高度',
120122
'Toggle Sidebar': '切换侧边栏',
123+
'Show Highlights and Comments': '显示高亮和批注',
121124
'Page Crop': '页面裁剪',
125+
'Trim Margins': '裁掉页边距',
122126
'Crop More Horizontally': '横向裁剪更多',
123127
'Crop Less Horizontally': '横向裁剪更少',
124128
'Crop More Vertically': '纵向裁剪更多',
@@ -192,7 +196,9 @@ const menuMessages = {
192196
'Fit Width': '符合寬度',
193197
'Fit Height': '符合高度',
194198
'Toggle Sidebar': '切換側邊欄',
199+
'Show Highlights and Comments': '顯示醒目標示與註解',
195200
'Page Crop': '頁面裁剪',
201+
'Trim Margins': '裁掉頁邊距',
196202
'Crop More Horizontally': '橫向裁剪更多',
197203
'Crop Less Horizontally': '橫向裁剪更少',
198204
'Crop More Vertically': '縱向裁剪更多',
@@ -268,7 +274,9 @@ const menuMessages = {
268274
'Fit Width': 'Ajuster à la largeur',
269275
'Fit Height': 'Ajuster à la hauteur',
270276
'Toggle Sidebar': 'Afficher/masquer la barre latérale',
277+
'Show Highlights and Comments': 'Afficher les surlignages et commentaires',
271278
'Page Crop': 'Recadrage de la page',
279+
'Trim Margins': 'Rogner les marges',
272280
'Crop More Horizontally': 'Recadrer davantage horizontalement',
273281
'Crop Less Horizontally': 'Recadrer moins horizontalement',
274282
'Crop More Vertically': 'Recadrer davantage verticalement',
@@ -342,7 +350,9 @@ const menuMessages = {
342350
'Fit Width': 'Ajustar al ancho',
343351
'Fit Height': 'Ajustar a la altura',
344352
'Toggle Sidebar': 'Mostrar/ocultar la barra lateral',
353+
'Show Highlights and Comments': 'Mostrar resaltados y comentarios',
345354
'Page Crop': 'Recorte de página',
355+
'Trim Margins': 'Recortar márgenes',
346356
'Crop More Horizontally': 'Recortar más horizontalmente',
347357
'Crop Less Horizontally': 'Recortar menos horizontalmente',
348358
'Crop More Vertically': 'Recortar más verticalmente',
@@ -416,7 +426,9 @@ const menuMessages = {
416426
'Fit Width': '幅に合わせる',
417427
'Fit Height': '高さに合わせる',
418428
'Toggle Sidebar': 'サイドバーを切り替え',
429+
'Show Highlights and Comments': 'ハイライトと注釈を表示',
419430
'Page Crop': 'ページのトリミング',
431+
'Trim Margins': '余白をトリミング',
420432
'Crop More Horizontally': '横方向にトリミングを増やす',
421433
'Crop Less Horizontally': '横方向にトリミングを減らす',
422434
'Crop More Vertically': '縦方向にトリミングを増やす',
@@ -490,7 +502,9 @@ const menuMessages = {
490502
'Fit Width': '너비에 맞추기',
491503
'Fit Height': '높이에 맞추기',
492504
'Toggle Sidebar': '사이드바 전환',
505+
'Show Highlights and Comments': '강조 표시 및 주석 표시',
493506
'Page Crop': '페이지 자르기',
507+
'Trim Margins': '여백 자르기',
494508
'Crop More Horizontally': '가로로 더 자르기',
495509
'Crop Less Horizontally': '가로로 덜 자르기',
496510
'Crop More Vertically': '세로로 더 자르기',

‎src/app/useReaderWindow.mjs‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,16 @@ export function useReaderWindow() {
607607

608608
// Display-only, total fraction removed symmetrically from each axis.
609609
const pageCrop = ref({ x: 0, y: 0 });
610+
// Mirrors the View menu checkboxes for annotations and Trim Margins.
611+
watch(
612+
() => ({
613+
annotations: showAnnotations.value,
614+
annotationsAvailable: annotations.value.length > 0,
615+
crop: pageCrop.value.x > 0 || pageCrop.value.y > 0,
616+
}),
617+
(state) => void window.previewActions?.viewState?.(state)?.catch(() => {}),
618+
{ immediate: true },
619+
);
610620
const compactParagraphPage = createParagraphCompaction({
611621
enabled: computed(
612622
() =>

‎src/features/reader/reader-commands.mjs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,8 @@ export function createReaderCommands({
172172
});
173173
} else if (action === 'sidebar') {
174174
if (session.pages.value.length) actions.readerFit.toggleSidebar();
175+
} else if (action === 'annotations') {
176+
if (session.pages.value.length) shell.showAnnotations.value = !shell.showAnnotations.value;
175177
} else if (action === 'settings') {
176178
if (shell.settingsWindowMode) actions.settingsNavigation.openSettings();
177179
else

‎src/features/reader/reading-position.mjs‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,29 @@ export function createReadingPosition({
2424
return host?.closest('.page-wrap') || host;
2525
}
2626

27+
// Last non-zero crop of this document, so Trim Margins can switch it back on.
28+
let trimmedCrop = null;
29+
function toggledCrop() {
30+
const { x, y } = readerView.pageCrop.value;
31+
if (x || y) {
32+
trimmedCrop = { x, y, epoch: session.epoch };
33+
return { x: 0, y: 0 };
34+
}
35+
if (trimmedCrop?.epoch === session.epoch) return { x: trimmedCrop.x, y: trimmedCrop.y };
36+
const defaults = {
37+
x: preferences.defaultPageCropX.value,
38+
y: preferences.defaultPageCropY.value,
39+
};
40+
return defaults.x || defaults.y ? defaults : { x: 0.1, y: 0.1 };
41+
}
42+
2743
async function changeCrop(action) {
2844
if (!session.pages.value.length) return;
2945
const view = readingView(),
3046
token = session.epoch;
3147
if (!view) return;
3248
if (action === 'crop:reset') readerView.pageCrop.value = { x: 0, y: 0 };
49+
else if (action === 'crop:toggle') readerView.pageCrop.value = toggledCrop();
3350
else {
3451
const [, axis, step] = action.split(':');
3552
if (!['x', 'y'].includes(axis)) return;

‎tests/desktop/crop-smoke.mjs‎

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,13 @@ export async function verifyCrop(window, recents) {
8080
);
8181
const menu = Menu.getApplicationMenu();
8282
const viewItems = menu.getMenuItemById('view-menu').submenu.items;
83-
const cropTitle = viewItems.findIndex((item) => item.id === 'view-crop');
84-
assert.equal(viewItems[cropTitle].enabled, false);
85-
assert.equal(viewItems[cropTitle].submenu, null);
83+
assert.ok(viewItems.some((item) => item.id === 'view-annotations'));
84+
const cropMenu = viewItems.find((item) => item.id === 'view-crop');
8685
assert.deepEqual(
87-
viewItems.slice(cropTitle + 1, cropTitle + 6).map((item) => item.id),
88-
['crop-x-more', 'crop-x-less', 'crop-y-more', 'crop-y-less', 'crop-reset'],
86+
cropMenu.submenu.items.filter((item) => item.type !== 'separator').map((item) => item.id),
87+
['crop-toggle', 'crop-x-more', 'crop-x-less', 'crop-y-more', 'crop-y-less', 'crop-reset'],
8988
);
89+
assert.equal(menu.getMenuItemById('crop-toggle').checked, false);
9090
async function command(id) {
9191
menu.getMenuItemById(id).click();
9292
await pause(500);
@@ -108,6 +108,14 @@ export async function verifyCrop(window, recents) {
108108
await command('crop-y-more');
109109
state = await geometry();
110110
assert.equal(state.view.cropY, 0.05);
111+
assert.equal(menu.getMenuItemById('crop-toggle').checked, true);
112+
await command('crop-toggle');
113+
state = await geometry();
114+
assert.deepEqual([state.view.cropX, state.view.cropY], [0, 0]);
115+
assert.equal(menu.getMenuItemById('crop-toggle').checked, false);
116+
await command('crop-toggle');
117+
state = await geometry();
118+
assert.deepEqual([state.view.cropX, state.view.cropY], [0.05, 0.05]);
111119
assert.ok(Math.abs(state.height - (state.fullHeight - 2) * 0.95 - 2) < 2);
112120
assert.ok(
113121
await evaluate(`getComputedStyle(document.querySelector('.page-wrap')).boxShadow!=='none'`),

0 commit comments

Comments
 (0)