399 lines
		
	
	
	
		
			8.9 KiB
			
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			399 lines
		
	
	
	
		
			8.9 KiB
			
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
// Copyright 2017 Signal Messenger, LLC
 | 
						|
// SPDX-License-Identifier: AGPL-3.0-only
 | 
						|
 | 
						|
import { isString } from 'lodash';
 | 
						|
 | 
						|
import type { LocalizerType } from '../ts/types/I18N';
 | 
						|
import type {
 | 
						|
  MenuListType,
 | 
						|
  MenuOptionsType,
 | 
						|
  MenuActionsType,
 | 
						|
} from '../ts/types/menu';
 | 
						|
 | 
						|
export type CreateTemplateOptionsType = MenuOptionsType & MenuActionsType;
 | 
						|
 | 
						|
export const createTemplate = (
 | 
						|
  options: CreateTemplateOptionsType,
 | 
						|
  i18n: LocalizerType
 | 
						|
): MenuListType => {
 | 
						|
  if (!isString(options.platform)) {
 | 
						|
    throw new TypeError('`options.platform` must be a string');
 | 
						|
  }
 | 
						|
 | 
						|
  const {
 | 
						|
    isProduction,
 | 
						|
    devTools,
 | 
						|
    includeSetup,
 | 
						|
    openContactUs,
 | 
						|
    openForums,
 | 
						|
    openJoinTheBeta,
 | 
						|
    openReleaseNotes,
 | 
						|
    openSupportPage,
 | 
						|
    platform,
 | 
						|
    setupAsNewDevice,
 | 
						|
    setupAsStandalone,
 | 
						|
    stageLocalBackupForImport,
 | 
						|
    forceUpdate,
 | 
						|
    showAbout,
 | 
						|
    showDebugLog,
 | 
						|
    showCallingDevTools,
 | 
						|
    showKeyboardShortcuts,
 | 
						|
    showSettings,
 | 
						|
    openArtCreator,
 | 
						|
    zoomIn,
 | 
						|
    zoomOut,
 | 
						|
    zoomReset,
 | 
						|
  } = options;
 | 
						|
 | 
						|
  const template: MenuListType = [
 | 
						|
    {
 | 
						|
      label: i18n('icu:mainMenuFile'),
 | 
						|
      submenu: [
 | 
						|
        {
 | 
						|
          label: i18n('icu:mainMenuCreateStickers'),
 | 
						|
          click: openArtCreator,
 | 
						|
        },
 | 
						|
        {
 | 
						|
          label: i18n('icu:mainMenuSettings'),
 | 
						|
          accelerator: 'CommandOrControl+,',
 | 
						|
          click: showSettings,
 | 
						|
        },
 | 
						|
        {
 | 
						|
          type: 'separator',
 | 
						|
        },
 | 
						|
        {
 | 
						|
          role: 'quit',
 | 
						|
          label: i18n('icu:appMenuQuit'),
 | 
						|
        },
 | 
						|
      ],
 | 
						|
    },
 | 
						|
    {
 | 
						|
      label: i18n('icu:mainMenuEdit'),
 | 
						|
      submenu: [
 | 
						|
        {
 | 
						|
          role: 'undo',
 | 
						|
          label: i18n('icu:editMenuUndo'),
 | 
						|
        },
 | 
						|
        {
 | 
						|
          role: 'redo',
 | 
						|
          label: i18n('icu:editMenuRedo'),
 | 
						|
        },
 | 
						|
        {
 | 
						|
          type: 'separator',
 | 
						|
        },
 | 
						|
        {
 | 
						|
          role: 'cut',
 | 
						|
          label: i18n('icu:editMenuCut'),
 | 
						|
        },
 | 
						|
        {
 | 
						|
          role: 'copy',
 | 
						|
          label: i18n('icu:editMenuCopy'),
 | 
						|
        },
 | 
						|
        {
 | 
						|
          role: 'paste',
 | 
						|
          label: i18n('icu:editMenuPaste'),
 | 
						|
        },
 | 
						|
        {
 | 
						|
          role: 'pasteAndMatchStyle',
 | 
						|
          label: i18n('icu:editMenuPasteAndMatchStyle'),
 | 
						|
        },
 | 
						|
        {
 | 
						|
          role: 'delete',
 | 
						|
          label: i18n('icu:editMenuDelete'),
 | 
						|
        },
 | 
						|
        {
 | 
						|
          role: 'selectAll',
 | 
						|
          label: i18n('icu:editMenuSelectAll'),
 | 
						|
        },
 | 
						|
      ],
 | 
						|
    },
 | 
						|
    {
 | 
						|
      label: i18n('icu:mainMenuView'),
 | 
						|
      submenu: [
 | 
						|
        {
 | 
						|
          accelerator: 'CmdOrCtrl+0',
 | 
						|
          label: i18n('icu:viewMenuResetZoom'),
 | 
						|
          click: zoomReset,
 | 
						|
        },
 | 
						|
        {
 | 
						|
          accelerator: 'CmdOrCtrl+=',
 | 
						|
          label: i18n('icu:viewMenuZoomIn'),
 | 
						|
          click: zoomIn,
 | 
						|
        },
 | 
						|
        {
 | 
						|
          accelerator: 'CmdOrCtrl+-',
 | 
						|
          label: i18n('icu:viewMenuZoomOut'),
 | 
						|
          click: zoomOut,
 | 
						|
        },
 | 
						|
        {
 | 
						|
          type: 'separator',
 | 
						|
        },
 | 
						|
        {
 | 
						|
          role: 'togglefullscreen',
 | 
						|
          label: i18n('icu:viewMenuToggleFullScreen'),
 | 
						|
        },
 | 
						|
        {
 | 
						|
          type: 'separator',
 | 
						|
        },
 | 
						|
        {
 | 
						|
          label: i18n('icu:debugLog'),
 | 
						|
          click: showDebugLog,
 | 
						|
        },
 | 
						|
        ...(devTools
 | 
						|
          ? [
 | 
						|
              {
 | 
						|
                type: 'separator' as const,
 | 
						|
              },
 | 
						|
              {
 | 
						|
                role: 'toggleDevTools' as const,
 | 
						|
                label: i18n('icu:viewMenuToggleDevTools'),
 | 
						|
              },
 | 
						|
              {
 | 
						|
                label: i18n('icu:viewMenuOpenCallingDevTools'),
 | 
						|
                click: showCallingDevTools,
 | 
						|
              },
 | 
						|
            ]
 | 
						|
          : []),
 | 
						|
        ...(devTools && platform !== 'linux'
 | 
						|
          ? [
 | 
						|
              {
 | 
						|
                label: i18n('icu:forceUpdate'),
 | 
						|
                click: forceUpdate,
 | 
						|
              },
 | 
						|
            ]
 | 
						|
          : []),
 | 
						|
      ],
 | 
						|
    },
 | 
						|
    {
 | 
						|
      label: i18n('icu:mainMenuWindow'),
 | 
						|
      role: 'window',
 | 
						|
      submenu: [
 | 
						|
        {
 | 
						|
          role: 'minimize',
 | 
						|
          label: i18n('icu:windowMenuMinimize'),
 | 
						|
        },
 | 
						|
      ],
 | 
						|
    },
 | 
						|
    {
 | 
						|
      label: i18n('icu:mainMenuHelp'),
 | 
						|
      role: 'help',
 | 
						|
      submenu: [
 | 
						|
        {
 | 
						|
          label: i18n('icu:helpMenuShowKeyboardShortcuts'),
 | 
						|
          accelerator: 'CmdOrCtrl+/',
 | 
						|
          click: showKeyboardShortcuts,
 | 
						|
        },
 | 
						|
        {
 | 
						|
          type: 'separator',
 | 
						|
        },
 | 
						|
        {
 | 
						|
          label: i18n('icu:contactUs'),
 | 
						|
          click: openContactUs,
 | 
						|
        },
 | 
						|
        {
 | 
						|
          label: i18n('icu:goToReleaseNotes'),
 | 
						|
          click: openReleaseNotes,
 | 
						|
        },
 | 
						|
        {
 | 
						|
          label: i18n('icu:goToForums'),
 | 
						|
          click: openForums,
 | 
						|
        },
 | 
						|
        {
 | 
						|
          label: i18n('icu:goToSupportPage'),
 | 
						|
          click: openSupportPage,
 | 
						|
        },
 | 
						|
        ...(isProduction
 | 
						|
          ? [
 | 
						|
              {
 | 
						|
                label: i18n('icu:joinTheBeta'),
 | 
						|
                click: openJoinTheBeta,
 | 
						|
              },
 | 
						|
            ]
 | 
						|
          : []),
 | 
						|
        {
 | 
						|
          type: 'separator',
 | 
						|
        },
 | 
						|
        {
 | 
						|
          label: i18n('icu:aboutSignalDesktop'),
 | 
						|
          click: showAbout,
 | 
						|
        },
 | 
						|
      ],
 | 
						|
    },
 | 
						|
  ];
 | 
						|
 | 
						|
  if (includeSetup) {
 | 
						|
    const fileMenu = template[0];
 | 
						|
 | 
						|
    if (Array.isArray(fileMenu.submenu)) {
 | 
						|
      // These are in reverse order, since we're prepending them one at a time
 | 
						|
      if (options.isNightly) {
 | 
						|
        fileMenu.submenu.unshift({
 | 
						|
          label: i18n('icu:menuStageLocalBackupForImport'),
 | 
						|
          click: stageLocalBackupForImport,
 | 
						|
        });
 | 
						|
      }
 | 
						|
 | 
						|
      if (options.development) {
 | 
						|
        fileMenu.submenu.unshift({
 | 
						|
          label: i18n('icu:menuSetupAsStandalone'),
 | 
						|
          click: setupAsStandalone,
 | 
						|
        });
 | 
						|
      }
 | 
						|
 | 
						|
      fileMenu.submenu.unshift({
 | 
						|
        type: 'separator',
 | 
						|
      });
 | 
						|
      fileMenu.submenu.unshift({
 | 
						|
        label: i18n('icu:menuSetupAsNewDevice'),
 | 
						|
        click: setupAsNewDevice,
 | 
						|
      });
 | 
						|
    } else {
 | 
						|
      throw new Error('createTemplate: fileMenu.submenu was not an array!');
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (platform === 'darwin') {
 | 
						|
    return updateForMac(template, i18n, options);
 | 
						|
  }
 | 
						|
 | 
						|
  return template;
 | 
						|
};
 | 
						|
 | 
						|
function updateForMac(
 | 
						|
  template: MenuListType,
 | 
						|
  i18n: LocalizerType,
 | 
						|
  options: CreateTemplateOptionsType
 | 
						|
): MenuListType {
 | 
						|
  const { showAbout, showSettings, showWindow } = options;
 | 
						|
 | 
						|
  // Remove About item and separator from Help menu, since they're in the app menu
 | 
						|
  const aboutMenu = template[4];
 | 
						|
  if (Array.isArray(aboutMenu.submenu)) {
 | 
						|
    aboutMenu.submenu.pop();
 | 
						|
    aboutMenu.submenu.pop();
 | 
						|
  } else {
 | 
						|
    throw new Error('updateForMac: help.submenu was not an array!');
 | 
						|
  }
 | 
						|
 | 
						|
  // Remove preferences, separator, and quit from the File menu, since they're
 | 
						|
  // in the app menu
 | 
						|
  const fileMenu = template[0];
 | 
						|
  if (Array.isArray(fileMenu.submenu)) {
 | 
						|
    fileMenu.submenu.pop();
 | 
						|
    fileMenu.submenu.pop();
 | 
						|
    fileMenu.submenu.pop();
 | 
						|
    // And insert "close".
 | 
						|
    fileMenu.submenu.push(
 | 
						|
      {
 | 
						|
        type: 'separator',
 | 
						|
      },
 | 
						|
      {
 | 
						|
        label: i18n('icu:windowMenuClose'),
 | 
						|
        accelerator: 'CmdOrCtrl+W',
 | 
						|
        role: 'close',
 | 
						|
      }
 | 
						|
    );
 | 
						|
  } else {
 | 
						|
    throw new Error('updateForMac: fileMenu.submenu was not an array!');
 | 
						|
  }
 | 
						|
 | 
						|
  // Add the OSX-specific Signal Desktop menu at the far left
 | 
						|
  template.unshift({
 | 
						|
    label: i18n('icu:signalDesktop'),
 | 
						|
    submenu: [
 | 
						|
      {
 | 
						|
        label: i18n('icu:aboutSignalDesktop'),
 | 
						|
        click: showAbout,
 | 
						|
      },
 | 
						|
      {
 | 
						|
        type: 'separator',
 | 
						|
      },
 | 
						|
      {
 | 
						|
        label: i18n('icu:mainMenuSettings'),
 | 
						|
        accelerator: 'CommandOrControl+,',
 | 
						|
        click: showSettings,
 | 
						|
      },
 | 
						|
      {
 | 
						|
        type: 'separator',
 | 
						|
      },
 | 
						|
      {
 | 
						|
        label: i18n('icu:appMenuServices'),
 | 
						|
        role: 'services',
 | 
						|
      },
 | 
						|
      {
 | 
						|
        type: 'separator',
 | 
						|
      },
 | 
						|
      {
 | 
						|
        label: i18n('icu:appMenuHide'),
 | 
						|
        role: 'hide',
 | 
						|
      },
 | 
						|
      {
 | 
						|
        label: i18n('icu:appMenuHideOthers'),
 | 
						|
        role: 'hideOthers',
 | 
						|
      },
 | 
						|
      {
 | 
						|
        label: i18n('icu:appMenuUnhide'),
 | 
						|
        role: 'unhide',
 | 
						|
      },
 | 
						|
      {
 | 
						|
        type: 'separator',
 | 
						|
      },
 | 
						|
      {
 | 
						|
        label: i18n('icu:appMenuQuit'),
 | 
						|
        role: 'quit',
 | 
						|
      },
 | 
						|
    ],
 | 
						|
  });
 | 
						|
 | 
						|
  const editMenu = template[2];
 | 
						|
  if (Array.isArray(editMenu.submenu)) {
 | 
						|
    editMenu.submenu.push(
 | 
						|
      {
 | 
						|
        type: 'separator',
 | 
						|
      },
 | 
						|
      {
 | 
						|
        label: i18n('icu:speech'),
 | 
						|
        submenu: [
 | 
						|
          {
 | 
						|
            role: 'startSpeaking',
 | 
						|
            label: i18n('icu:editMenuStartSpeaking'),
 | 
						|
          },
 | 
						|
          {
 | 
						|
            role: 'stopSpeaking',
 | 
						|
            label: i18n('icu:editMenuStopSpeaking'),
 | 
						|
          },
 | 
						|
        ],
 | 
						|
      }
 | 
						|
    );
 | 
						|
  } else {
 | 
						|
    throw new Error('updateForMac: edit.submenu was not an array!');
 | 
						|
  }
 | 
						|
 | 
						|
  // Replace Window menu
 | 
						|
  // eslint-disable-next-line no-param-reassign
 | 
						|
  template[4].submenu = [
 | 
						|
    {
 | 
						|
      label: i18n('icu:windowMenuMinimize'),
 | 
						|
      accelerator: 'CmdOrCtrl+M',
 | 
						|
      role: 'minimize',
 | 
						|
    },
 | 
						|
    {
 | 
						|
      label: i18n('icu:windowMenuZoom'),
 | 
						|
      role: 'zoom',
 | 
						|
    },
 | 
						|
    {
 | 
						|
      label: i18n('icu:show'),
 | 
						|
      accelerator: 'CmdOrCtrl+Shift+0',
 | 
						|
      click: showWindow,
 | 
						|
    },
 | 
						|
    {
 | 
						|
      type: 'separator',
 | 
						|
    },
 | 
						|
    {
 | 
						|
      role: 'front',
 | 
						|
      label: i18n('icu:windowMenuBringAllToFront'),
 | 
						|
    },
 | 
						|
  ];
 | 
						|
 | 
						|
  return template;
 | 
						|
}
 |