Skip to content

Commit

Permalink
Menus: disable non-available entries
Browse files Browse the repository at this point in the history
Also:

- added a mobx reaction to regenerate menus when needed
- clean up menus init: will be called on reaction
  • Loading branch information
warpdesign committed Mar 7, 2023
1 parent 29709d0 commit 4d33dfe
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 14 deletions.
43 changes: 43 additions & 0 deletions src/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ import '@blueprintjs/popover2/lib/css/blueprint-popover2.css'
import '$src/css/main.css'
import '$src/css/windows.css'
import '$src/css/scrollbars.css'
import { reaction } from 'mobx'
import { ReactiveProperties } from '$src/types'

const App = observer(() => {
const { appState } = useStores('appState')
Expand Down Expand Up @@ -112,6 +114,47 @@ const App = observer(() => {
}
}, [])

// Install menu reactions to update native menu when needed
useEffect(() => {
return reaction(
(): ReactiveProperties => {
const view = appState.getActiveView()
const activeCache = view.getVisibleCache()

return {
// if any of these elements have changed
// we'll have to update native menus
status: activeCache.status,
path: activeCache.path,
selectedLength: activeCache.selected.length,
// enable when FsZip is merged
isReadonly: false,
isIndirect: false,
// isReadonly: activeCache.getFS().options.readonly,
// isIndirect: activeCache.getFS().options.indirect,
isOverlayOpen: document.body.classList.contains('bp4-overlay-open'),
activeViewTabNums: view.caches.length,
isExplorer: appState.isExplorer,
language: i18n.language,
// missing: about opened, tab: is it needed?
}
},
(value) => {
console.log('something changed!')
ipcRenderer.invoke('updateMenus', t('APP_MENUS', { returnObjects: true }), value)
},
{
equals: (value: ReactiveProperties, previousValue: ReactiveProperties) => {
console.log(JSON.stringify(value) === JSON.stringify(previousValue))
console.log(JSON.stringify(value))
console.log(JSON.stringify(previousValue))

return JSON.stringify(value) === JSON.stringify(previousValue)
},
},
)
}, [])

useEventListener('keydown', onShortcutsCombo, { capture: true })
useEventListener(
'copy',
Expand Down
1 change: 1 addition & 0 deletions src/components/menus/FileContextMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const FileContextMenu = ({ fileUnderMouse }: Props) => {
const clipboard = appState.clipboard
const cache = appState.getActiveCache()

// TODO: disable delete/paste when cahce.fs.readonly is true
const numFilesInClipboard = clipboard.files.length
const isInSelection = fileUnderMouse && !!cache.selected.find((file) => sameID(file.id, fileUnderMouse.id))
const isPasteEnabled = numFilesInClipboard && ((!fileUnderMouse && !cache.error) || fileUnderMouse?.isDir)
Expand Down
28 changes: 23 additions & 5 deletions src/electron/appMenus.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { clipboard, Menu, BrowserWindow, MenuItemConstructorOptions, MenuItem, app, ipcMain, dialog } from 'electron'

import { isMac, isLinux, VERSIONS } from '$src/electron/osSupport'
import { ReactiveProperties } from '$src/types'

const ACCELERATOR_EVENT = 'menu_accelerator'

Expand Down Expand Up @@ -84,8 +85,19 @@ export class AppMenu {
}
}

getMenuTemplate(): MenuItemConstructorOptions[] {
getMenuTemplate({
activeViewTabNums,
isReadonly,
isIndirect,
isOverlayOpen,
isExplorer,
path,
selectedLength,
status,
}: ReactiveProperties): MenuItemConstructorOptions[] {
const menuStrings = this.menuStrings
const explorerWithoutOverlay = !isOverlayOpen && isExplorer
const explorerWithoutOverlayCanWrite = explorerWithoutOverlay && !isReadonly && status === 'ok'
let windowMenuIndex = 4

const template = [
Expand All @@ -97,17 +109,20 @@ export class AppMenu {
label: menuStrings['NEW_TAB'],
click: this.sendComboEvent,
accelerator: 'CmdOrCtrl+T',
enabled: explorerWithoutOverlay,
},
{
label: menuStrings['CLOSE_TAB'],
click: this.sendComboEvent,
accelerator: 'CmdOrCtrl+W',
enabled: explorerWithoutOverlay && activeViewTabNums > 1,
},
{ type: 'separator' },
{
label: menuStrings['MAKEDIR'],
accelerator: 'CmdOrCtrl+N',
click: this.sendComboEvent,
enabled: explorerWithoutOverlayCanWrite,
},
{
label: menuStrings['RENAME'],
Expand All @@ -118,17 +133,20 @@ export class AppMenu {
Object.assign({ combo: 'rename', data: undefined }),
)
},
enabled: explorerWithoutOverlayCanWrite && selectedLength === 1,
},
{
label: menuStrings['DELETE'],
accelerator: 'CmdOrCtrl+D',
click: this.sendComboEvent,
enabled: explorerWithoutOverlayCanWrite && selectedLength > 0,
},
{ type: 'separator' },
{
label: menuStrings['OPEN_TERMINAL'],
accelerator: 'CmdOrCtrl+K',
click: this.sendComboEvent,
enabled: explorerWithoutOverlay && !isIndirect,
},
],
},
Expand Down Expand Up @@ -313,13 +331,13 @@ export class AppMenu {
return template as MenuItemConstructorOptions[]
}

createMenu(menuStrings: LocaleString, lang: string): void {
createMenu(menuStrings: LocaleString, props: ReactiveProperties): void {
this.menuStrings = menuStrings
this.lang = lang
this.lang = props.language

const menuTemplate = this.getMenuTemplate()
const template = this.getMenuTemplate(props)

const menu = Menu.buildFromTemplate(menuTemplate)
const menu = Menu.buildFromTemplate(template)

Menu.setApplicationMenu(menu)
}
Expand Down
8 changes: 5 additions & 3 deletions src/electron/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { AppMenu, LocaleString } from '$src/electron/appMenus'
import { isLinux } from '$src/electron/osSupport'
import { WindowSettings } from '$src/electron//windowSettings'
import { Remote } from '$src/electron/remote'
import { ReactiveProperties } from '$src/types'

const ENV_E2E = !!process.env.E2E
const HTML_PATH = `${__dirname}/index.html`
Expand Down Expand Up @@ -155,7 +156,7 @@ const ElectronApp = {
* - reloadIgnoringCache: need to reload the main window (dev only)
* - exit: wants to exit the app
* - openTerminal(cmd): should open a new terminal process using specified cmd line
* - languageChanged(strings): language has been changed so menus need to be updated
* - updateMenus(strings): language has been changed so menus need to be updated
* - selectAll: wants to generate a selectAll event
*/
installIpcMainListeners() {
Expand Down Expand Up @@ -186,9 +187,10 @@ const ElectronApp = {
})
})

ipcMain.handle('languageChanged', (e: Event, strings: LocaleString, lang: string) => {
ipcMain.handle('updateMenus', (e: Event, strings: LocaleString, props: ReactiveProperties) => {
console.log('** need to update menus :)')
if (this.appMenu) {
this.appMenu.createMenu(strings, lang)
this.appMenu.createMenu(strings, props)
} else {
console.log('languageChanged but app not ready :(')
}
Expand Down
6 changes: 3 additions & 3 deletions src/locale/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ const i18n = {
i18next,
}

i18next.on('languageChanged', (lang: string): void => {
ipcRenderer.invoke('languageChanged', i18next.t('APP_MENUS', { returnObjects: true }), lang)
})
// i18next.on('languageChanged', (lang: string): void => {
// ipcRenderer.invoke('languageChanged', i18next.t('APP_MENUS', { returnObjects: true }), lang)
// })

const languageList = Object.keys(locales)

Expand Down
8 changes: 6 additions & 2 deletions src/state/appState.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -417,9 +417,13 @@ export class AppState {
}
}

getActiveCache(): FileState {
getActiveView(): ViewState {
const winState = this.winStates[0]
const view = winState.getActiveView()
return winState.getActiveView()
}

getActiveCache(): FileState {
const view = this.getActiveView()
return this.isExplorer ? view.caches.find((cache) => cache.isVisible === true) : null
}

Expand Down
15 changes: 14 additions & 1 deletion src/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { FileDescriptor } from '$src/services/Fs'
import { FileState } from '$src/state/fileState'
import { FileState, TStatus } from '$src/state/fileState'
import { IconName } from '@blueprintjs/icons'
import { IpcRendererEvent } from 'electron/renderer'

Expand Down Expand Up @@ -31,3 +31,16 @@ export interface DraggedObject {
}

export type ArrowKey = 'ArrowUp' | 'ArrowDown' | 'ArrowLeft' | 'ArrowRight'

// Properties that trigger an update of native menus
export interface ReactiveProperties {
activeViewTabNums: number
isReadonly: boolean
isIndirect: boolean
isOverlayOpen: boolean
isExplorer: boolean
path: string
selectedLength: number
status: TStatus
language: string
}

0 comments on commit 4d33dfe

Please sign in to comment.