1
+ import { exec } from 'child_process' ;
1
2
import { app , BrowserWindow , clipboard , dialog , ipcMain , Menu , shell } from 'electron' ;
2
3
import type { BaseWindow , BrowserView , MenuItem , MenuItemConstructorOptions , WebContents , WebviewTag } from 'electron' ;
3
4
import contextMenu from 'electron-context-menu' ;
@@ -6,7 +7,7 @@ import type {ElectronLog} from 'electron-log';
6
7
import { autoUpdater } from 'electron-updater' ;
7
8
import { machineId } from 'node-machine-id' ;
8
9
import checkForUpdates from '@libs/checkForUpdates' ;
9
- import * as Localize from '@libs/Localize' ;
10
+ import { translate } from '@libs/Localize' ;
10
11
import CONFIG from '@src/CONFIG' ;
11
12
import CONST from '@src/CONST' ;
12
13
import type { TranslationPaths } from '@src/languages/types' ;
@@ -71,20 +72,20 @@ function pasteAsPlainText(browserWindow: BrowserWindow | BrowserView | WebviewTa
71
72
function createContextMenu ( preferredLocale : Locale = LOCALES . DEFAULT ) : ( ) => void {
72
73
return contextMenu ( {
73
74
labels : {
74
- cut : Localize . translate ( preferredLocale , 'desktopApplicationMenu.cut' ) ,
75
- paste : Localize . translate ( preferredLocale , 'desktopApplicationMenu.paste' ) ,
76
- copy : Localize . translate ( preferredLocale , 'desktopApplicationMenu.copy' ) ,
75
+ cut : translate ( preferredLocale , 'desktopApplicationMenu.cut' ) ,
76
+ paste : translate ( preferredLocale , 'desktopApplicationMenu.paste' ) ,
77
+ copy : translate ( preferredLocale , 'desktopApplicationMenu.copy' ) ,
77
78
} ,
78
79
append : ( defaultActions , parameters , browserWindow ) => [
79
80
{
80
81
// Only enable the menu item for Editable context which supports paste
81
82
visible : parameters . isEditable && parameters . editFlags . canPaste ,
82
83
role : 'pasteAndMatchStyle' ,
83
84
accelerator : DESKTOP_SHORTCUT_ACCELERATOR . PASTE_AND_MATCH_STYLE ,
84
- label : Localize . translate ( preferredLocale , 'desktopApplicationMenu.pasteAndMatchStyle' ) ,
85
+ label : translate ( preferredLocale , 'desktopApplicationMenu.pasteAndMatchStyle' ) ,
85
86
} ,
86
87
{
87
- label : Localize . translate ( preferredLocale , 'desktopApplicationMenu.pasteAsPlainText' ) ,
88
+ label : translate ( preferredLocale , 'desktopApplicationMenu.pasteAsPlainText' ) ,
88
89
visible : parameters . isEditable && parameters . editFlags . canPaste && clipboard . readText ( ) . length > 0 ,
89
90
accelerator : DESKTOP_SHORTCUT_ACCELERATOR . PASTE_AS_PLAIN_TEXT ,
90
91
click : ( ) => pasteAsPlainText ( browserWindow ) ,
@@ -126,7 +127,7 @@ let hasUpdate = false;
126
127
let downloadedVersion : string ;
127
128
let isSilentUpdating = false ;
128
129
129
- // Note that we have to subscribe to this separately and cannot use Localize. translateLocal,
130
+ // Note that we have to subscribe to this separately and cannot use translateLocal,
130
131
// because the only way code can be shared between the main and renderer processes at runtime is via the context bridge
131
132
// So we track preferredLocale separately via ELECTRON_EVENTS.LOCALE_UPDATED
132
133
const preferredLocale : Locale = CONST . LOCALES . DEFAULT ;
@@ -165,23 +166,23 @@ const manuallyCheckForUpdates = (menuItem?: MenuItem, browserWindow?: BaseWindow
165
166
if ( downloadPromise ) {
166
167
dialog . showMessageBox ( browserWindow , {
167
168
type : 'info' ,
168
- message : Localize . translate ( preferredLocale , 'checkForUpdatesModal.available.title' ) ,
169
- detail : Localize . translate ( preferredLocale , 'checkForUpdatesModal.available.message' , { isSilentUpdating} ) ,
170
- buttons : [ Localize . translate ( preferredLocale , 'checkForUpdatesModal.available.soundsGood' ) ] ,
169
+ message : translate ( preferredLocale , 'checkForUpdatesModal.available.title' ) ,
170
+ detail : translate ( preferredLocale , 'checkForUpdatesModal.available.message' , { isSilentUpdating} ) ,
171
+ buttons : [ translate ( preferredLocale , 'checkForUpdatesModal.available.soundsGood' ) ] ,
171
172
} ) ;
172
173
} else if ( result && 'error' in result && result . error ) {
173
174
dialog . showMessageBox ( browserWindow , {
174
175
type : 'error' ,
175
- message : Localize . translate ( preferredLocale , 'checkForUpdatesModal.error.title' ) ,
176
- detail : Localize . translate ( preferredLocale , 'checkForUpdatesModal.error.message' ) ,
177
- buttons : [ Localize . translate ( preferredLocale , 'checkForUpdatesModal.notAvailable.okay' ) ] ,
176
+ message : translate ( preferredLocale , 'checkForUpdatesModal.error.title' ) ,
177
+ detail : translate ( preferredLocale , 'checkForUpdatesModal.error.message' ) ,
178
+ buttons : [ translate ( preferredLocale , 'checkForUpdatesModal.notAvailable.okay' ) ] ,
178
179
} ) ;
179
180
} else {
180
181
dialog . showMessageBox ( browserWindow , {
181
182
type : 'info' ,
182
- message : Localize . translate ( preferredLocale , 'checkForUpdatesModal.notAvailable.title' ) ,
183
- detail : Localize . translate ( preferredLocale , 'checkForUpdatesModal.notAvailable.message' ) ,
184
- buttons : [ Localize . translate ( preferredLocale , 'checkForUpdatesModal.notAvailable.okay' ) ] ,
183
+ message : translate ( preferredLocale , 'checkForUpdatesModal.notAvailable.title' ) ,
184
+ detail : translate ( preferredLocale , 'checkForUpdatesModal.notAvailable.message' ) ,
185
+ buttons : [ translate ( preferredLocale , 'checkForUpdatesModal.notAvailable.okay' ) ] ,
185
186
cancelId : 2 ,
186
187
} ) ;
187
188
}
@@ -242,7 +243,7 @@ const localizeMenuItems = (submenu: MenuItemConstructorOptions[], updatedLocale:
242
243
submenu . map ( ( menu ) => {
243
244
const newMenu : MenuItemConstructorOptions = { ...menu } ;
244
245
if ( menu . id ) {
245
- const labelTranslation = Localize . translate ( updatedLocale , `desktopApplicationMenu.${ menu . id } ` as TranslationPaths ) ;
246
+ const labelTranslation = translate ( updatedLocale , `desktopApplicationMenu.${ menu . id } ` as TranslationPaths ) ;
246
247
if ( labelTranslation ) {
247
248
newMenu . label = labelTranslation ;
248
249
}
@@ -310,7 +311,25 @@ const mainWindow = (): Promise<void> => {
310
311
} ) ;
311
312
312
313
ipcMain . handle ( ELECTRON_EVENTS . REQUEST_DEVICE_ID , ( ) => machineId ( ) ) ;
314
+ ipcMain . handle ( ELECTRON_EVENTS . OPEN_LOCATION_SETTING , ( ) => {
315
+ if ( process . platform !== 'darwin' ) {
316
+ // Platform not supported for location settings
317
+ return Promise . resolve ( undefined ) ;
318
+ }
313
319
320
+ return new Promise ( ( resolve , reject ) => {
321
+ const command = 'open x-apple.systempreferences:com.apple.preference.security?Privacy_Location' ;
322
+
323
+ exec ( command , ( error ) => {
324
+ if ( error ) {
325
+ console . error ( 'Error opening location settings:' , error ) ;
326
+ reject ( error ) ;
327
+ return ;
328
+ }
329
+ resolve ( undefined ) ;
330
+ } ) ;
331
+ } ) ;
332
+ } ) ;
314
333
/*
315
334
* The default origin of our Electron app is app://- instead of https://new.expensify.com or https://staging.new.expensify.com
316
335
* This causes CORS errors because the referer and origin headers are wrong and the API responds with an Access-Control-Allow-Origin that doesn't match app://-
@@ -353,14 +372,14 @@ const mainWindow = (): Promise<void> => {
353
372
const initialMenuTemplate : MenuItemConstructorOptions [ ] = [
354
373
{
355
374
id : 'mainMenu' ,
356
- label : Localize . translate ( preferredLocale , `desktopApplicationMenu.mainMenu` ) ,
375
+ label : translate ( preferredLocale , `desktopApplicationMenu.mainMenu` ) ,
357
376
submenu : [
358
377
{ id : 'about' , role : 'about' } ,
359
- { id : 'update' , label : Localize . translate ( preferredLocale , `desktopApplicationMenu.update` ) , click : quitAndInstallWithUpdate , visible : false } ,
360
- { id : 'checkForUpdates' , label : Localize . translate ( preferredLocale , `desktopApplicationMenu.checkForUpdates` ) , click : manuallyCheckForUpdates } ,
378
+ { id : 'update' , label : translate ( preferredLocale , `desktopApplicationMenu.update` ) , click : quitAndInstallWithUpdate , visible : false } ,
379
+ { id : 'checkForUpdates' , label : translate ( preferredLocale , `desktopApplicationMenu.checkForUpdates` ) , click : manuallyCheckForUpdates } ,
361
380
{
362
381
id : 'viewShortcuts' ,
363
- label : Localize . translate ( preferredLocale , `desktopApplicationMenu.viewShortcuts` ) ,
382
+ label : translate ( preferredLocale , `desktopApplicationMenu.viewShortcuts` ) ,
364
383
accelerator : 'CmdOrCtrl+J' ,
365
384
click : ( ) => {
366
385
showKeyboardShortcutsPage ( browserWindow ) ;
@@ -378,12 +397,12 @@ const mainWindow = (): Promise<void> => {
378
397
} ,
379
398
{
380
399
id : 'fileMenu' ,
381
- label : Localize . translate ( preferredLocale , `desktopApplicationMenu.fileMenu` ) ,
400
+ label : translate ( preferredLocale , `desktopApplicationMenu.fileMenu` ) ,
382
401
submenu : [ { id : 'closeWindow' , role : 'close' , accelerator : 'Cmd+w' } ] ,
383
402
} ,
384
403
{
385
404
id : 'editMenu' ,
386
- label : Localize . translate ( preferredLocale , `desktopApplicationMenu.editMenu` ) ,
405
+ label : translate ( preferredLocale , `desktopApplicationMenu.editMenu` ) ,
387
406
submenu : [
388
407
{ id : 'undo' , role : 'undo' } ,
389
408
{ id : 'redo' , role : 'redo' } ,
@@ -406,7 +425,7 @@ const mainWindow = (): Promise<void> => {
406
425
{ type : 'separator' } ,
407
426
{
408
427
id : 'speechSubmenu' ,
409
- label : Localize . translate ( preferredLocale , `desktopApplicationMenu.speechSubmenu` ) ,
428
+ label : translate ( preferredLocale , `desktopApplicationMenu.speechSubmenu` ) ,
410
429
submenu : [
411
430
{ id : 'startSpeaking' , role : 'startSpeaking' } ,
412
431
{ id : 'stopSpeaking' , role : 'stopSpeaking' } ,
@@ -416,7 +435,7 @@ const mainWindow = (): Promise<void> => {
416
435
} ,
417
436
{
418
437
id : 'viewMenu' ,
419
- label : Localize . translate ( preferredLocale , `desktopApplicationMenu.viewMenu` ) ,
438
+ label : translate ( preferredLocale , `desktopApplicationMenu.viewMenu` ) ,
420
439
submenu : [
421
440
{ id : 'reload' , role : 'reload' } ,
422
441
{ id : 'forceReload' , role : 'forceReload' } ,
@@ -431,7 +450,7 @@ const mainWindow = (): Promise<void> => {
431
450
} ,
432
451
{
433
452
id : 'historyMenu' ,
434
- label : Localize . translate ( preferredLocale , `desktopApplicationMenu.historyMenu` ) ,
453
+ label : translate ( preferredLocale , `desktopApplicationMenu.historyMenu` ) ,
435
454
submenu : [
436
455
{
437
456
id : 'back' ,
@@ -472,33 +491,33 @@ const mainWindow = (): Promise<void> => {
472
491
} ,
473
492
{
474
493
id : 'helpMenu' ,
475
- label : Localize . translate ( preferredLocale , `desktopApplicationMenu.helpMenu` ) ,
494
+ label : translate ( preferredLocale , `desktopApplicationMenu.helpMenu` ) ,
476
495
role : 'help' ,
477
496
submenu : [
478
497
{
479
498
id : 'learnMore' ,
480
- label : Localize . translate ( preferredLocale , `desktopApplicationMenu.learnMore` ) ,
499
+ label : translate ( preferredLocale , `desktopApplicationMenu.learnMore` ) ,
481
500
click : ( ) => {
482
501
shell . openExternal ( CONST . MENU_HELP_URLS . LEARN_MORE ) ;
483
502
} ,
484
503
} ,
485
504
{
486
505
id : 'documentation' ,
487
- label : Localize . translate ( preferredLocale , `desktopApplicationMenu.documentation` ) ,
506
+ label : translate ( preferredLocale , `desktopApplicationMenu.documentation` ) ,
488
507
click : ( ) => {
489
508
shell . openExternal ( CONST . MENU_HELP_URLS . DOCUMENTATION ) ;
490
509
} ,
491
510
} ,
492
511
{
493
512
id : 'communityDiscussions' ,
494
- label : Localize . translate ( preferredLocale , `desktopApplicationMenu.communityDiscussions` ) ,
513
+ label : translate ( preferredLocale , `desktopApplicationMenu.communityDiscussions` ) ,
495
514
click : ( ) => {
496
515
shell . openExternal ( CONST . MENU_HELP_URLS . COMMUNITY_DISCUSSIONS ) ;
497
516
} ,
498
517
} ,
499
518
{
500
519
id : 'searchIssues' ,
501
- label : Localize . translate ( preferredLocale , `desktopApplicationMenu.searchIssues` ) ,
520
+ label : translate ( preferredLocale , `desktopApplicationMenu.searchIssues` ) ,
502
521
click : ( ) => {
503
522
shell . openExternal ( CONST . MENU_HELP_URLS . SEARCH_ISSUES ) ;
504
523
} ,
0 commit comments