Skip to content

Commit

Permalink
feat: add "Open recent" file menu
Browse files Browse the repository at this point in the history
fix #6
  • Loading branch information
Xiphe committed Apr 21, 2020
1 parent 7fe44a0 commit 043c369
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 11 deletions.
6 changes: 6 additions & 0 deletions main/windowManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ export default function createWindowManager(app: App, ipcMain: IpcMain) {
win.on('focus', () => {
win.webContents.send('FOCUS');
});
win.on('blur', () => {
win.webContents.send('BLUR');
});

const { SERVER_URL, NODE_ENV } = process.env;
if (NODE_ENV === 'development') {
Expand Down Expand Up @@ -125,6 +128,9 @@ export default function createWindowManager(app: App, ipcMain: IpcMain) {
ipcMain.handle('MENU_FILE_NEW', () => {
createWindow();
});
ipcMain.handle('MENU_FILE_OPEN_EXISTING', (_, file: string) => {
createWindow(file);
});

return {
init() {
Expand Down
36 changes: 27 additions & 9 deletions src/budget/useMenu.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { useEffect, useMemo } from 'react';
import { useEffect, useMemo, useState } from 'react';
import {
createMenu,
createFileMenu,
createEditMenu,
CreateMenuCallbacks,
ipcRenderer,
Menu,
settings,
useSetShowSettings,
} from '../lib';

Expand Down Expand Up @@ -48,17 +49,34 @@ function buildMenu(callbacks: CreateMenuCallbacks) {

export default function useMenu() {
const setShowSettings = useSetShowSettings();
const menu = useMemo(() => buildMenu({ setShowSettings }), [setShowSettings]);
const [recentSignal, setRecentSignal] = useState<symbol>(Symbol());
const [focus, updateFocus] = useState<boolean>(true);
const menu = useMemo(
() => buildMenu({ setShowSettings }),
/* eslint-disable-next-line react-hooks/exhaustive-deps */
[setShowSettings, recentSignal],
);
useEffect(() => {
const activate = () => {
Menu.setApplicationMenu(menu);
};
activate();
ipcRenderer.on('FOCUS', activate);
const obs = settings.watch('recentFiles', () => {
setRecentSignal(Symbol());
});
const setFocus = () => updateFocus(true);
const setBlur = () => updateFocus(false);

ipcRenderer.on('FOCUS', setFocus);
ipcRenderer.on('BLUR', setBlur);

return () => {
ipcRenderer.off('FOCUS', activate);
obs.dispose();
ipcRenderer.off('FOCUS', setFocus);
ipcRenderer.off('BLUR', setBlur);
};
}, [menu]);
}, []);
useEffect(() => {
if (focus) {
Menu.setApplicationMenu(menu);
}
}, [focus, menu]);

return menu;
}
16 changes: 15 additions & 1 deletion src/budget/useSave.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
import { useState, useEffect, useCallback, useRef } from 'react';
import { ipcRenderer, writeFile } from '../lib';
import { ipcRenderer, writeFile, existsSync, settings } from '../lib';
import { Menu } from 'electron';
import { MENU_ID_SAVE, MENU_ID_SAVE_AS } from './useMenu';
import { BudgetState } from './Types';

type RecentFile = { name: string; file: string };
function addRecentFile(file: string, name: string) {
const recent: RecentFile[] = settings.get('recentFiles', []) as any;
const otherExistingFiles = recent.filter(
({ file: f }) => existsSync(f) && f !== file,
);

settings.set('recentFiles', [
{ file, name },
...otherExistingFiles.slice(0, 9),
]);
}

export default function useSave(menu: Menu, state: BudgetState | null) {
const [saved, setSaved] = useState<BudgetState | null | Error>(null);
const stateRef = useRef<BudgetState | null>();
Expand Down Expand Up @@ -33,6 +46,7 @@ export default function useSave(menu: Menu, state: BudgetState | null) {
return;
}

addRecentFile(file, state.name);
writeFile(file, JSON.stringify(state), (err) => {
if (!canceled) {
setSaved(err || state);
Expand Down
21 changes: 21 additions & 0 deletions src/lib/createMenu.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { MenuItemConstructorOptions } from 'electron';
import { ipcRenderer, appName } from './electron';
import settings from './electron-settings';
import { basename } from './path';

type MenuConfig = MenuItemConstructorOptions;
export type CreateMenuCallbacks = {
Expand Down Expand Up @@ -60,6 +62,11 @@ export function createFileMenu(entries: MenuConfig[] = []): MenuConfig[] {
ipcRenderer.invoke('MENU_FILE_OPEN');
},
},
{
label: 'Open Recent',
id: 'open-recent',
submenu: createRecentSubmenu(settings.get('recentFiles') as any),
},
entries.length ? { type: 'separator' } : false,
...entries,
{ type: 'separator' },
Expand All @@ -69,6 +76,20 @@ export function createFileMenu(entries: MenuConfig[] = []): MenuConfig[] {
return config.filter(isMenuConfig);
}

export function createRecentSubmenu(
recentFiles: {
name: string;
file: string;
}[],
): MenuConfig['submenu'] {
return recentFiles.map(({ name, file }) => ({
label: `${name} - ${basename(file)}`,
click() {
ipcRenderer.invoke('MENU_FILE_OPEN_EXISTING', file);
},
}));
}

export function createEditMenu(): MenuConfig {
return {
label: 'Edit',
Expand Down
3 changes: 3 additions & 0 deletions src/lib/electron-settings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import settings from 'electron-settings';

export default window.require('electron-settings') as typeof settings;
3 changes: 2 additions & 1 deletion src/lib/fs.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { writeFile as wft, readFile as rft } from 'fs';
import { writeFile as wft, readFile as rft, existsSync as est } from 'fs';
const fs = window.require('fs');

export const writeFile: typeof wft = fs.writeFile;
export const readFile: typeof rft = fs.readFile;
export const existsSync: typeof est = fs.existsSync;
2 changes: 2 additions & 0 deletions src/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export { default as createNumberFormatter } from './createNumberFormatter';
export { default as useInputProps } from './useInputProps';
export { default as useAmountInputProps } from './useAmountInputProps';
export { default as useInit, INIT_EMPTY } from './useInit';
export { default as settings } from './electron-settings';
export { createMenu, createFileMenu, createEditMenu } from './createMenu';
export {
withShowSettingsProvider,
Expand All @@ -24,6 +25,7 @@ export {
export * from './guards';
export * from './electron';
export * from './fs';
export * from './path';
export * from './useIsVisible';
export type NumberFormatter = NumberFormatterT;
export type CreateMenuCallbacks = CreateMenuCallbacksT;
4 changes: 4 additions & 0 deletions src/lib/path.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { basename as bnt } from 'path';
const path = window.require('path');

export const basename: typeof bnt = path.basename;

0 comments on commit 043c369

Please sign in to comment.