aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--package.json4
-rw-r--r--pnpm-lock.yaml33
m---------recipes0
-rw-r--r--src/api/server/ServerApi.ts14
-rw-r--r--src/components/services/tabs/TabItem.tsx8
-rw-r--r--src/components/settings/settings/EditSettingsForm.tsx125
-rw-r--r--src/config.ts1
-rw-r--r--src/containers/auth/SetupAssistantScreen.tsx5
-rw-r--r--src/containers/settings/EditSettingsScreen.tsx244
-rw-r--r--src/electron/ipc-api/dnd.ts1
-rw-r--r--src/electron/ipc-api/download.ts10
-rw-r--r--src/features/workspaces/components/WorkspaceDrawerItem.tsx8
-rw-r--r--src/i18n/locales/de.json21
-rw-r--r--src/i18n/locales/en-US.json9
-rw-r--r--src/i18n/locales/it.json31
-rw-r--r--src/i18n/locales/ru.json13
-rw-r--r--src/index.ts27
-rw-r--r--src/jsUtils.ts21
-rw-r--r--src/lib/Menu.ts17
-rw-r--r--src/models/Recipe.ts5
-rw-r--r--src/models/Service.ts17
-rw-r--r--src/stores/ServicesStore.ts3
-rw-r--r--src/webview/contextMenuBuilder.ts59
-rw-r--r--src/webview/notifications.ts75
-rw-r--r--src/webview/recipe.ts2
-rw-r--r--test/jsUtils.test.ts46
26 files changed, 569 insertions, 230 deletions
diff --git a/package.json b/package.json
index abb7dca68..888cb5e0e 100644
--- a/package.json
+++ b/package.json
@@ -3,7 +3,7 @@
3 "productName": "Ferdium", 3 "productName": "Ferdium",
4 "desktopName": "ferdium.desktop", 4 "desktopName": "ferdium.desktop",
5 "appId": "org.ferdium.ferdium-app", 5 "appId": "org.ferdium.ferdium-app",
6 "version": "6.7.4-nightly.2", 6 "version": "6.7.5-nightly.2",
7 "description": "Messaging app for WhatsApp, Slack, Telegram, Hangouts and many many more.", 7 "description": "Messaging app for WhatsApp, Slack, Telegram, Hangouts and many many more.",
8 "author": "Ferdium Contributors <hello@ferdium.org> (https://ferdium.org/)", 8 "author": "Ferdium Contributors <hello@ferdium.org> (https://ferdium.org/)",
9 "license": "Apache-2.0", 9 "license": "Apache-2.0",
@@ -163,7 +163,7 @@
163 "chalk": "5.3.0", 163 "chalk": "5.3.0",
164 "concurrently": "8.2.2", 164 "concurrently": "8.2.2",
165 "cross-env": "7.0.3", 165 "cross-env": "7.0.3",
166 "electron": "30.0.2", 166 "electron": "30.0.6",
167 "electron-builder": "24.13.3", 167 "electron-builder": "24.13.3",
168 "esbuild": "0.16.17", 168 "esbuild": "0.16.17",
169 "esbuild-plugin-copy": "2.1.1", 169 "esbuild-plugin-copy": "2.1.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 20737139d..934011d21 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -40,7 +40,7 @@ dependencies:
40 version: 5.1.0 40 version: 5.1.0
41 '@electron/remote': 41 '@electron/remote':
42 specifier: 2.1.2 42 specifier: 2.1.2
43 version: 2.1.2(electron@30.0.2) 43 version: 2.1.2(electron@30.0.6)
44 '@emotion/react': 44 '@emotion/react':
45 specifier: 11.11.4 45 specifier: 11.11.4
46 version: 11.11.4(@types/react@18.2.77)(react@18.2.0) 46 version: 11.11.4(@types/react@18.2.77)(react@18.2.0)
@@ -70,7 +70,7 @@ dependencies:
70 version: 7.4.0(history@5.3.0)(mobx@6.12.3)(path-to-regexp@6.2.2) 70 version: 7.4.0(history@5.3.0)(mobx@6.12.3)(path-to-regexp@6.2.2)
71 '@syed_umair/electron-process-manager': 71 '@syed_umair/electron-process-manager':
72 specifier: 1.1.0 72 specifier: 1.1.0
73 version: 1.1.0(electron@30.0.2) 73 version: 1.1.0(electron@30.0.6)
74 auto-launch: 74 auto-launch:
75 specifier: 5.0.6 75 specifier: 5.0.6
76 version: 5.0.6 76 version: 5.0.6
@@ -352,8 +352,8 @@ devDependencies:
352 specifier: 7.0.3 352 specifier: 7.0.3
353 version: 7.0.3 353 version: 7.0.3
354 electron: 354 electron:
355 specifier: 30.0.2 355 specifier: 30.0.6
356 version: 30.0.2 356 version: 30.0.6
357 electron-builder: 357 electron-builder:
358 specifier: 24.13.3 358 specifier: 24.13.3
359 version: 24.13.3(electron-builder-squirrel-windows@24.13.3) 359 version: 24.13.3(electron-builder-squirrel-windows@24.13.3)
@@ -646,7 +646,7 @@ packages:
646 engines: {node: '>=6.9.0'} 646 engines: {node: '>=6.9.0'}
647 dependencies: 647 dependencies:
648 '@babel/highlight': 7.24.5 648 '@babel/highlight': 7.24.5
649 picocolors: 1.0.0 649 picocolors: 1.0.1
650 650
651 /@babel/compat-data@7.22.20: 651 /@babel/compat-data@7.22.20:
652 resolution: {integrity: sha512-BQYjKbpXjoXwFW5jGqiizJQQT/aC7pFm9Ok1OWssonuguICi264lbgMzRp2ZMmRSlfkX6DsWDDcsrctK8Rwfiw==} 652 resolution: {integrity: sha512-BQYjKbpXjoXwFW5jGqiizJQQT/aC7pFm9Ok1OWssonuguICi264lbgMzRp2ZMmRSlfkX6DsWDDcsrctK8Rwfiw==}
@@ -908,7 +908,7 @@ packages:
908 '@babel/helper-validator-identifier': 7.24.5 908 '@babel/helper-validator-identifier': 7.24.5
909 chalk: 2.4.2 909 chalk: 2.4.2
910 js-tokens: 4.0.0 910 js-tokens: 4.0.0
911 picocolors: 1.0.0 911 picocolors: 1.0.1
912 912
913 /@babel/parser@7.23.5: 913 /@babel/parser@7.23.5:
914 resolution: {integrity: sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==} 914 resolution: {integrity: sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==}
@@ -1494,12 +1494,12 @@ packages:
1494 - supports-color 1494 - supports-color
1495 dev: true 1495 dev: true
1496 1496
1497 /@electron/remote@2.1.2(electron@30.0.2): 1497 /@electron/remote@2.1.2(electron@30.0.6):
1498 resolution: {integrity: sha512-EPwNx+nhdrTBxyCqXt/pftoQg/ybtWDW3DUWHafejvnB1ZGGfMpv6e15D8KeempocjXe78T7WreyGGb3mlZxdA==} 1498 resolution: {integrity: sha512-EPwNx+nhdrTBxyCqXt/pftoQg/ybtWDW3DUWHafejvnB1ZGGfMpv6e15D8KeempocjXe78T7WreyGGb3mlZxdA==}
1499 peerDependencies: 1499 peerDependencies:
1500 electron: '>= 13.0.0' 1500 electron: '>= 13.0.0'
1501 dependencies: 1501 dependencies:
1502 electron: 30.0.2 1502 electron: 30.0.6
1503 dev: false 1503 dev: false
1504 1504
1505 /@electron/universal@1.5.1: 1505 /@electron/universal@1.5.1:
@@ -3024,12 +3024,12 @@ packages:
3024 path-to-regexp: 6.2.2 3024 path-to-regexp: 6.2.2
3025 dev: false 3025 dev: false
3026 3026
3027 /@syed_umair/electron-process-manager@1.1.0(electron@30.0.2): 3027 /@syed_umair/electron-process-manager@1.1.0(electron@30.0.6):
3028 resolution: {integrity: sha512-rbDJ1GQ51DcsP+354WpI/3xWOra1HH4cT1jA0maK8VJogn7s5BiMO2XkSBaCoeMCvTIIwx7Y6dgUHpfnL2M6wg==} 3028 resolution: {integrity: sha512-rbDJ1GQ51DcsP+354WpI/3xWOra1HH4cT1jA0maK8VJogn7s5BiMO2XkSBaCoeMCvTIIwx7Y6dgUHpfnL2M6wg==}
3029 peerDependencies: 3029 peerDependencies:
3030 electron: '>=21' 3030 electron: '>=21'
3031 dependencies: 3031 dependencies:
3032 electron: 30.0.2 3032 electron: 30.0.6
3033 electron-process-reporter: 1.4.0 3033 electron-process-reporter: 1.4.0
3034 dev: false 3034 dev: false
3035 3035
@@ -4722,7 +4722,7 @@ packages:
4722 engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} 4722 engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
4723 hasBin: true 4723 hasBin: true
4724 dependencies: 4724 dependencies:
4725 caniuse-lite: 1.0.30001615 4725 caniuse-lite: 1.0.30001620
4726 electron-to-chromium: 1.4.710 4726 electron-to-chromium: 1.4.710
4727 node-releases: 2.0.14 4727 node-releases: 2.0.14
4728 update-browserslist-db: 1.0.13(browserslist@4.23.0) 4728 update-browserslist-db: 1.0.13(browserslist@4.23.0)
@@ -4973,8 +4973,8 @@ packages:
4973 resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==} 4973 resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==}
4974 dev: false 4974 dev: false
4975 4975
4976 /caniuse-lite@1.0.30001615: 4976 /caniuse-lite@1.0.30001620:
4977 resolution: {integrity: sha512-1IpazM5G3r38meiae0bHRnPhz+CBQ3ZLqbQMtrg+AsTPKAXgW38JNsXkyZ+v8waCsDmPq87lmfun5Q2AGysNEQ==} 4977 resolution: {integrity: sha512-WJvYsOjd1/BYUY6SNGUosK9DUidBPDTnOARHp3fSmFO1ekdxaY6nKRttEVrfMmYi80ctS0kz1wiWmm14fVc3ew==}
4978 4978
4979 /caseless@0.12.0: 4979 /caseless@0.12.0:
4980 resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} 4980 resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==}
@@ -6217,8 +6217,8 @@ packages:
6217 mkdirp: 0.5.6 6217 mkdirp: 0.5.6
6218 dev: false 6218 dev: false
6219 6219
6220 /electron@30.0.2: 6220 /electron@30.0.6:
6221 resolution: {integrity: sha512-zv7T+GG89J/hyWVkQsLH4Y/rVEfqJG5M/wOBIGNaDdqd8UV9/YZPdS7CuFeaIj0H9LhCt95xkIQNpYB/3svOkQ==} 6221 resolution: {integrity: sha512-PkhEPFdpYcTzjAO3gMHZ+map7g2+xCrMDedo/L1i0ir2BRXvAB93IkTJX497U6Srb/09r2cFt+k20VPNVCdw3Q==}
6222 engines: {node: '>= 12.20.55'} 6222 engines: {node: '>= 12.20.55'}
6223 hasBin: true 6223 hasBin: true
6224 requiresBuild: true 6224 requiresBuild: true
@@ -11322,6 +11322,9 @@ packages:
11322 /picocolors@1.0.0: 11322 /picocolors@1.0.0:
11323 resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} 11323 resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
11324 11324
11325 /picocolors@1.0.1:
11326 resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==}
11327
11325 /picomatch@2.3.1: 11328 /picomatch@2.3.1:
11326 resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 11329 resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
11327 engines: {node: '>=8.6'} 11330 engines: {node: '>=8.6'}
diff --git a/recipes b/recipes
Subproject 7ab6497fbd7bc64c3f2b17b587d273c9bbd155c Subproject dd668a67d84ee37cc8a9d39aea2e7b17ef93f31
diff --git a/src/api/server/ServerApi.ts b/src/api/server/ServerApi.ts
index b5dd499ab..5434880dc 100644
--- a/src/api/server/ServerApi.ts
+++ b/src/api/server/ServerApi.ts
@@ -12,6 +12,7 @@ import {
12 statSync, 12 statSync,
13 writeFileSync, 13 writeFileSync,
14} from 'fs-extra'; 14} from 'fs-extra';
15import ms from 'ms';
15import tar from 'tar'; 16import tar from 'tar';
16 17
17import RecipeModel, { type IRecipe } from '../../models/Recipe'; 18import RecipeModel, { type IRecipe } from '../../models/Recipe';
@@ -460,7 +461,7 @@ export default class ServerApi {
460 } 461 }
461 debug(archivePath); 462 debug(archivePath);
462 463
463 await sleep(10); 464 await sleep(ms('10ms'));
464 465
465 await tar.x({ 466 await tar.x({
466 file: archivePath, 467 file: archivePath,
@@ -471,14 +472,21 @@ export default class ServerApi {
471 onwarn: x => debug('warn', recipeId, x), 472 onwarn: x => debug('warn', recipeId, x),
472 }); 473 });
473 474
474 await sleep(10); 475 await sleep(ms('10ms'));
475 476
476 const { id } = readJsonSync(join(recipeTempDirectory, 'package.json')); 477 const { id, defaultIcon } = readJsonSync(
478 join(recipeTempDirectory, 'package.json'),
479 );
477 const recipeDirectory = join(recipesDirectory, id); 480 const recipeDirectory = join(recipesDirectory, id);
478 copySync(recipeTempDirectory, recipeDirectory); 481 copySync(recipeTempDirectory, recipeDirectory);
479 removeSync(recipeTempDirectory); 482 removeSync(recipeTempDirectory);
480 removeSync(join(recipesDirectory, recipeId, 'recipe.tar.gz')); 483 removeSync(join(recipesDirectory, recipeId, 'recipe.tar.gz'));
481 484
485 // TODO: This is a temporary fix to remove svg icons from the user AppData. This should be removed after versions of all recipes have been bumped up
486 if (defaultIcon) {
487 removeSync(join(recipeDirectory, 'icon.svg'));
488 }
489
482 return id; 490 return id;
483 } 491 }
484 492
diff --git a/src/components/services/tabs/TabItem.tsx b/src/components/services/tabs/TabItem.tsx
index 0e999506a..94c0b7e7f 100644
--- a/src/components/services/tabs/TabItem.tsx
+++ b/src/components/services/tabs/TabItem.tsx
@@ -364,10 +364,10 @@ class TabItem extends Component<IProps, IState> {
364 role="presentation" 364 role="presentation"
365 onContextMenu={() => menu.popup()} 365 onContextMenu={() => menu.popup()}
366 data-tooltip-id="tooltip-sidebar-button" 366 data-tooltip-id="tooltip-sidebar-button"
367 data-tooltip-content={`${service.name} ${acceleratorString( 367 data-tooltip-content={`${service.name} ${acceleratorString({
368 shortcutIndex, 368 index: shortcutIndex,
369 cmdOrCtrlShortcutKey(false), 369 keyCombo: cmdOrCtrlShortcutKey(false),
370 )}`} 370 })}`}
371 > 371 >
372 <img src={service.icon} className="tab-item__icon" alt="" /> 372 <img src={service.icon} className="tab-item__icon" alt="" />
373 {showServiceNameSetting && ( 373 {showServiceNameSetting && (
diff --git a/src/components/settings/settings/EditSettingsForm.tsx b/src/components/settings/settings/EditSettingsForm.tsx
index c3e8d46a0..2900aa2af 100644
--- a/src/components/settings/settings/EditSettingsForm.tsx
+++ b/src/components/settings/settings/EditSettingsForm.tsx
@@ -1,5 +1,6 @@
1import { systemPreferences } from '@electron/remote'; 1import { systemPreferences } from '@electron/remote';
2import { mdiGithub, mdiOpenInNew, mdiPowerPlug } from '@mdi/js'; 2import { mdiGithub, mdiOpenInNew, mdiPowerPlug } from '@mdi/js';
3import { ipcRenderer } from 'electron';
3import { noop } from 'lodash'; 4import { noop } from 'lodash';
4import { observer } from 'mobx-react'; 5import { observer } from 'mobx-react';
5import prettyBytes from 'pretty-bytes'; 6import prettyBytes from 'pretty-bytes';
@@ -191,6 +192,14 @@ const messages = defineMessages({
191 id: 'settings.app.subheadlineCache', 192 id: 'settings.app.subheadlineCache',
192 defaultMessage: 'Cache', 193 defaultMessage: 'Cache',
193 }, 194 },
195 subheadlineUserAgent: {
196 id: 'settings.app.subheadlineUserAgent',
197 defaultMessage: 'User Agent',
198 },
199 subheadlineDownloads: {
200 id: 'settings.app.subheadlineDownloads',
201 defaultMessage: 'Downloads',
202 },
194 cacheInfo: { 203 cacheInfo: {
195 id: 'settings.app.cacheInfo', 204 id: 'settings.app.cacheInfo',
196 defaultMessage: 'Ferdium cache is currently using {size} of disk space.', 205 defaultMessage: 'Ferdium cache is currently using {size} of disk space.',
@@ -281,6 +290,10 @@ const messages = defineMessages({
281 id: 'settings.app.buttonOpenFerdiumCertsFolder', 290 id: 'settings.app.buttonOpenFerdiumCertsFolder',
282 defaultMessage: 'Open certificates folder', 291 defaultMessage: 'Open certificates folder',
283 }, 292 },
293 buttonOpenFolderSelector: {
294 id: 'settings.app.buttonOpenFolderSelector',
295 defaultMessage: 'Open folder selector',
296 },
284}); 297});
285 298
286const Hr = (): ReactElement => ( 299const Hr = (): ReactElement => (
@@ -1034,49 +1047,87 @@ class EditSettingsForm extends Component<IProps, IState> {
1034 1047
1035 <Hr /> 1048 <Hr />
1036 1049
1037 <Input 1050 <div className="settings__settings-group">
1038 placeholder="User Agent" 1051 <H3>{intl.formatMessage(messages.subheadlineDownloads)}</H3>
1039 onChange={e => this.submit(e)} 1052
1040 {...form.$('userAgentPref').bind()} 1053 <Input
1041 /> 1054 placeholder="Default download folder"
1042 <p className="settings__help"> 1055 onChange={e => {
1043 {intl.formatMessage(globalMessages.userAgentHelp)} 1056 this.submit(e);
1044 </p> 1057 }}
1045 <p className="settings__help"> 1058 {...form.$('downloadFolderPath').bind()}
1046 {intl.formatMessage(messages.appRestartRequired)} 1059 />
1047 </p> 1060
1061 <Button
1062 buttonType="secondary"
1063 label={intl.formatMessage(
1064 messages.buttonOpenFolderSelector,
1065 )}
1066 className="settings__open-settings-cache-button"
1067 onClick={e => {
1068 ipcRenderer
1069 .invoke('download-folder-select')
1070 .then(path => {
1071 if (path) {
1072 form.$('downloadFolderPath').set(path);
1073 this.submit(e);
1074 }
1075 })
1076 .catch(console.error);
1077 }}
1078 disabled={isClearingAllCache}
1079 loaded={!isClearingAllCache}
1080 />
1081 </div>
1048 1082
1049 <Hr /> 1083 <Hr />
1050 1084
1051 <div className="settings__settings-group"> 1085 <div className="settings__settings-group">
1052 <H3>{intl.formatMessage(messages.subheadlineCache)}</H3> 1086 <Input
1053 <p> 1087 placeholder="User Agent"
1054 {intl.formatMessage(messages.cacheInfo, { 1088 onChange={e => this.submit(e)}
1055 size: cacheSize, 1089 {...form.$('userAgentPref').bind()}
1056 })} 1090 />
1091
1092 <p className="settings__help">
1093 {intl.formatMessage(globalMessages.userAgentHelp)}
1057 </p> 1094 </p>
1058 {notCleared && ( 1095 <p className="settings__help">
1059 <p>{intl.formatMessage(messages.cacheNotCleared)}</p> 1096 {intl.formatMessage(messages.appRestartRequired)}
1060 )} 1097 </p>
1098
1099 <Hr />
1100
1061 <div className="settings__settings-group"> 1101 <div className="settings__settings-group">
1062 <div className="settings__open-settings-cache-container"> 1102 <H3>{intl.formatMessage(messages.subheadlineCache)}</H3>
1063 <Button 1103 <p>
1064 buttonType="secondary" 1104 {intl.formatMessage(messages.cacheInfo, {
1065 label={intl.formatMessage(globalMessages.clearCache)} 1105 size: cacheSize,
1066 className="settings__open-settings-cache-button" 1106 })}
1067 onClick={() => { 1107 </p>
1068 onClearAllCache(); 1108 {notCleared && (
1069 this.onClearCacheClicked(); 1109 <p>{intl.formatMessage(messages.cacheNotCleared)}</p>
1070 }} 1110 )}
1071 disabled={isClearingAllCache} 1111 <div className="settings__settings-group">
1072 loaded={!isClearingAllCache} 1112 <div className="settings__open-settings-cache-container">
1073 /> 1113 <Button
1074 <Button 1114 buttonType="secondary"
1075 buttonType="secondary" 1115 label={intl.formatMessage(globalMessages.clearCache)}
1076 label="Open Process Manager" 1116 className="settings__open-settings-cache-button"
1077 className="settings__open-settings-cache-button" 1117 onClick={() => {
1078 onClick={openProcessManager} 1118 onClearAllCache();
1079 /> 1119 this.onClearCacheClicked();
1120 }}
1121 disabled={isClearingAllCache}
1122 loaded={!isClearingAllCache}
1123 />
1124 <Button
1125 buttonType="secondary"
1126 label="Open Process Manager"
1127 className="settings__open-settings-cache-button"
1128 onClick={openProcessManager}
1129 />
1130 </div>
1080 </div> 1131 </div>
1081 </div> 1132 </div>
1082 </div> 1133 </div>
diff --git a/src/config.ts b/src/config.ts
index 348b4b85d..0034b00a6 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -401,6 +401,7 @@ export const DEFAULT_APP_SETTINGS = {
401 automaticUpdates: true, 401 automaticUpdates: true,
402 universalDarkMode: true, 402 universalDarkMode: true,
403 userAgentPref: '', 403 userAgentPref: '',
404 downloadFolderPath: '',
404 adaptableDarkMode: true, 405 adaptableDarkMode: true,
405 accentColor: DEFAULT_ACCENT_COLOR, 406 accentColor: DEFAULT_ACCENT_COLOR,
406 progressbarAccentColor: DEFAULT_ACCENT_COLOR, 407 progressbarAccentColor: DEFAULT_ACCENT_COLOR,
diff --git a/src/containers/auth/SetupAssistantScreen.tsx b/src/containers/auth/SetupAssistantScreen.tsx
index d15b4e6e1..b73b5705d 100644
--- a/src/containers/auth/SetupAssistantScreen.tsx
+++ b/src/containers/auth/SetupAssistantScreen.tsx
@@ -1,4 +1,5 @@
1import { inject, observer } from 'mobx-react'; 1import { inject, observer } from 'mobx-react';
2import ms from 'ms';
2import { Component, type ReactElement } from 'react'; 3import { Component, type ReactElement } from 'react';
3import type { StoresProps } from '../../@types/ferdium-components.types'; 4import type { StoresProps } from '../../@types/ferdium-components.types';
4import type { ILegacyServices } from '../../@types/legacy-types'; 5import type { ILegacyServices } from '../../@types/legacy-types';
@@ -83,11 +84,11 @@ class SetupAssistantScreen extends Component<IProps, IState> {
83 }); 84 });
84 85
85 // eslint-disable-next-line no-await-in-loop 86 // eslint-disable-next-line no-await-in-loop
86 await sleep(100); 87 await sleep(ms('100ms'));
87 } 88 }
88 89
89 this.setState({ isSettingUpServices: false }); 90 this.setState({ isSettingUpServices: false });
90 await sleep(100); 91 await sleep(ms('100ms'));
91 router.push('/'); 92 router.push('/');
92 } 93 }
93 94
diff --git a/src/containers/settings/EditSettingsScreen.tsx b/src/containers/settings/EditSettingsScreen.tsx
index fdd9bd8bc..31e8d6484 100644
--- a/src/containers/settings/EditSettingsScreen.tsx
+++ b/src/containers/settings/EditSettingsScreen.tsx
@@ -341,6 +341,32 @@ const messages = defineMessages({
341 id: 'settings.app.form.keepAllWorkspacesLoaded', 341 id: 'settings.app.form.keepAllWorkspacesLoaded',
342 defaultMessage: 'Keep all workspaces loaded', 342 defaultMessage: 'Keep all workspaces loaded',
343 }, 343 },
344 downloadFolderPath: {
345 id: 'settings.app.form.downloadFolderPath',
346 defaultMessage:
347 'Default download folder (leave blank to be prompted for each download)',
348 },
349 restartDialogTitle: {
350 id: 'settings.app.restart.restartDialogTitle',
351 defaultMessage: 'Ferdium - Relaunch Application',
352 },
353 restartNow: {
354 id: 'settings.app.restart.restartNow',
355 defaultMessage: 'Restart now',
356 },
357 restartLater: {
358 id: 'settings.app.restart.restartLater',
359 defaultMessage: 'Restart later',
360 },
361 restartDialogMessage: {
362 id: 'settings.app.restart.restartDialogMessage',
363 defaultMessage: 'Do you want to relaunch Ferdium?',
364 },
365 restartDialogDetail: {
366 id: 'settings.app.restart.restartDialogDetail',
367 defaultMessage:
368 'You made a change that requires a restart. This will close Ferdium and restart it.',
369 },
344}); 370});
345 371
346interface EditSettingsScreenProps extends StoresProps, WrappedComponentProps {} 372interface EditSettingsScreenProps extends StoresProps, WrappedComponentProps {}
@@ -364,6 +390,7 @@ class EditSettingsScreen extends Component<
364 } 390 }
365 391
366 onSubmit(settingsData) { 392 onSubmit(settingsData) {
393 const { intl } = this.props;
367 const { todos, workspaces } = this.props.stores; 394 const { todos, workspaces } = this.props.stores;
368 const { 395 const {
369 app, 396 app,
@@ -386,97 +413,130 @@ class EditSettingsScreen extends Component<
386 413
387 debug(`Updating settings store with data: ${settingsData}`); 414 debug(`Updating settings store with data: ${settingsData}`);
388 415
416 const { app: currentSettings } = this.props.stores.settings.all;
417
418 const newSettings = {
419 runInBackground: Boolean(settingsData.runInBackground),
420 enableSystemTray: Boolean(settingsData.enableSystemTray),
421 reloadAfterResume: Boolean(settingsData.reloadAfterResume),
422 reloadAfterResumeTime: Number(settingsData.reloadAfterResumeTime),
423 startMinimized: Boolean(settingsData.startMinimized),
424 confirmOnQuit: Boolean(settingsData.confirmOnQuit),
425 minimizeToSystemTray: Boolean(settingsData.minimizeToSystemTray),
426 closeToSystemTray: Boolean(settingsData.closeToSystemTray),
427 privateNotifications: Boolean(settingsData.privateNotifications),
428 clipboardNotifications: Boolean(settingsData.clipboardNotifications),
429 notifyTaskBarOnMessage: Boolean(settingsData.notifyTaskBarOnMessage),
430 isTwoFactorAutoCatcherEnabled: Boolean(
431 settingsData.isTwoFactorAutoCatcherEnabled,
432 ),
433 twoFactorAutoCatcherMatcher: settingsData.twoFactorAutoCatcherMatcher,
434 navigationBarBehaviour: settingsData.navigationBarBehaviour,
435 webRTCIPHandlingPolicy: settingsData.webRTCIPHandlingPolicy,
436 searchEngine: settingsData.searchEngine,
437 translatorEngine: settingsData.translatorEngine,
438 translatorLanguage: settingsData.translatorLanguage,
439 sentry: Boolean(settingsData.sentry),
440 hibernateOnStartup: Boolean(settingsData.hibernateOnStartup),
441 hibernationStrategy: Number(settingsData.hibernationStrategy),
442 wakeUpStrategy: Number(settingsData.wakeUpStrategy),
443 wakeUpHibernationStrategy: Number(settingsData.wakeUpHibernationStrategy),
444 wakeUpHibernationSplay: Boolean(settingsData.wakeUpHibernationSplay),
445 predefinedTodoServer: settingsData.predefinedTodoServer,
446 customTodoServer: settingsData.customTodoServer,
447 isLockingFeatureEnabled: Boolean(settingsData.isLockingFeatureEnabled),
448 lockedPassword: useOriginalPassword
449 ? this.props.stores.settings.all.app.lockedPassword
450 : hash(String(settingsData.lockedPassword)),
451 useTouchIdToUnlock: Boolean(settingsData.useTouchIdToUnlock),
452 inactivityLock: Number(settingsData.inactivityLock),
453 scheduledDNDEnabled: Boolean(settingsData.scheduledDNDEnabled),
454 scheduledDNDStart: settingsData.scheduledDNDStart,
455 scheduledDNDEnd: settingsData.scheduledDNDEnd,
456 enableGPUAcceleration: Boolean(settingsData.enableGPUAcceleration),
457 downloadFolderPath: String(settingsData.downloadFolderPath),
458 enableGlobalHideShortcut: Boolean(settingsData.enableGlobalHideShortcut),
459 showDisabledServices: Boolean(settingsData.showDisabledServices),
460 showServiceName: Boolean(settingsData.showServiceName),
461 darkMode: Boolean(settingsData.darkMode),
462 adaptableDarkMode: Boolean(settingsData.adaptableDarkMode),
463 universalDarkMode: Boolean(settingsData.universalDarkMode),
464 splitMode: Boolean(settingsData.splitMode),
465 splitColumns: Number(settingsData.splitColumns),
466 serviceRibbonWidth: Number(settingsData.serviceRibbonWidth),
467 sidebarServicesLocation: Number(settingsData.sidebarServicesLocation),
468 iconSize: Number(settingsData.iconSize),
469 enableLongPressServiceHint: Boolean(
470 settingsData.enableLongPressServiceHint,
471 ),
472 useHorizontalStyle: Boolean(settingsData.useHorizontalStyle),
473 hideCollapseButton: Boolean(settingsData.hideCollapseButton),
474 hideRecipesButton: Boolean(settingsData.hideRecipesButton),
475 hideSplitModeButton: Boolean(settingsData.hideSplitModeButton),
476 useGrayscaleServices: Boolean(settingsData.useGrayscaleServices),
477 grayscaleServicesDim: Number(settingsData.grayscaleServicesDim),
478 hideWorkspacesButton: Boolean(settingsData.hideWorkspacesButton),
479 hideNotificationsButton: Boolean(settingsData.hideNotificationsButton),
480 hideSettingsButton: Boolean(settingsData.hideSettingsButton),
481 hideDownloadButton: Boolean(settingsData.hideDownloadButton),
482 alwaysShowWorkspaces: Boolean(settingsData.alwaysShowWorkspaces),
483 hideAllServicesWorkspace: Boolean(settingsData.hideAllServicesWorkspace),
484 accentColor: settingsData.accentColor,
485 progressbarAccentColor: settingsData.progressbarAccentColor,
486 showMessageBadgeWhenMuted: Boolean(
487 settingsData.showMessageBadgeWhenMuted,
488 ),
489 showDragArea: Boolean(settingsData.showDragArea),
490 enableSpellchecking: Boolean(settingsData.enableSpellchecking),
491 enableTranslator: Boolean(settingsData.enableTranslator),
492 useSelfSignedCertificates: Boolean(
493 settingsData.useSelfSignedCertificates,
494 ),
495 spellcheckerLanguage: settingsData.spellcheckerLanguage,
496 userAgentPref: settingsData.userAgentPref,
497 beta: Boolean(settingsData.beta), // we need this info in the main process as well
498 automaticUpdates: Boolean(settingsData.automaticUpdates), // we need this info in the main process as well
499 locale: settingsData.locale, // we need this info in the main process as well
500 };
501
502 const requiredRestartKeys = [
503 'webRTCIPHandlingPolicy',
504 'sentry',
505 'searchEngine',
506 'enableSpellchecking',
507 'spellcheckerLanguage',
508 'enableGlobalHideShortcut',
509 // 'userAgentPref', // TODO: this is an input field, so it changes on every key stroke
510 ];
511
512 // Check if any of the keys that require a restart have changed
513 const requiresRestart = requiredRestartKeys.some(
514 key => newSettings[key] !== currentSettings[key],
515 );
516
517 if (requiresRestart) {
518 debug('Settings require restart');
519
520 const options: Electron.MessageBoxOptions = {
521 type: 'warning',
522 buttons: [
523 intl.formatMessage(messages.restartNow),
524 intl.formatMessage(messages.restartLater),
525 ],
526 defaultId: 0,
527 cancelId: 1,
528 title: intl.formatMessage(messages.restartDialogTitle),
529 message: intl.formatMessage(messages.restartDialogMessage),
530 detail: intl.formatMessage(messages.restartDialogDetail),
531 };
532
533 ipcRenderer.send('relaunch-app', options);
534 }
535
389 settings.update({ 536 settings.update({
390 type: 'app', 537 type: 'app',
391 // TODO: The conversions might not be necessary once we convert to typescript 538 // TODO: The conversions might not be necessary once we convert to typescript
392 data: { 539 data: newSettings,
393 runInBackground: Boolean(settingsData.runInBackground),
394 enableSystemTray: Boolean(settingsData.enableSystemTray),
395 reloadAfterResume: Boolean(settingsData.reloadAfterResume),
396 reloadAfterResumeTime: Number(settingsData.reloadAfterResumeTime),
397 startMinimized: Boolean(settingsData.startMinimized),
398 confirmOnQuit: Boolean(settingsData.confirmOnQuit),
399 minimizeToSystemTray: Boolean(settingsData.minimizeToSystemTray),
400 closeToSystemTray: Boolean(settingsData.closeToSystemTray),
401 privateNotifications: Boolean(settingsData.privateNotifications),
402 clipboardNotifications: Boolean(settingsData.clipboardNotifications),
403 notifyTaskBarOnMessage: Boolean(settingsData.notifyTaskBarOnMessage),
404 isTwoFactorAutoCatcherEnabled: Boolean(
405 settingsData.isTwoFactorAutoCatcherEnabled,
406 ),
407 twoFactorAutoCatcherMatcher: settingsData.twoFactorAutoCatcherMatcher,
408 navigationBarBehaviour: settingsData.navigationBarBehaviour,
409 webRTCIPHandlingPolicy: settingsData.webRTCIPHandlingPolicy,
410 searchEngine: settingsData.searchEngine,
411 translatorEngine: settingsData.translatorEngine,
412 translatorLanguage: settingsData.translatorLanguage,
413 sentry: Boolean(settingsData.sentry),
414 hibernateOnStartup: Boolean(settingsData.hibernateOnStartup),
415 hibernationStrategy: Number(settingsData.hibernationStrategy),
416 wakeUpStrategy: Number(settingsData.wakeUpStrategy),
417 wakeUpHibernationStrategy: Number(
418 settingsData.wakeUpHibernationStrategy,
419 ),
420 wakeUpHibernationSplay: Boolean(settingsData.wakeUpHibernationSplay),
421 predefinedTodoServer: settingsData.predefinedTodoServer,
422 customTodoServer: settingsData.customTodoServer,
423 isLockingFeatureEnabled: Boolean(settingsData.isLockingFeatureEnabled),
424 lockedPassword: useOriginalPassword
425 ? this.props.stores.settings.all.app.lockedPassword
426 : hash(String(settingsData.lockedPassword)),
427 useTouchIdToUnlock: Boolean(settingsData.useTouchIdToUnlock),
428 inactivityLock: Number(settingsData.inactivityLock),
429 scheduledDNDEnabled: Boolean(settingsData.scheduledDNDEnabled),
430 scheduledDNDStart: settingsData.scheduledDNDStart,
431 scheduledDNDEnd: settingsData.scheduledDNDEnd,
432 enableGPUAcceleration: Boolean(settingsData.enableGPUAcceleration),
433 enableGlobalHideShortcut: Boolean(
434 settingsData.enableGlobalHideShortcut,
435 ),
436 showDisabledServices: Boolean(settingsData.showDisabledServices),
437 showServiceName: Boolean(settingsData.showServiceName),
438 darkMode: Boolean(settingsData.darkMode),
439 adaptableDarkMode: Boolean(settingsData.adaptableDarkMode),
440 universalDarkMode: Boolean(settingsData.universalDarkMode),
441 splitMode: Boolean(settingsData.splitMode),
442 splitColumns: Number(settingsData.splitColumns),
443 serviceRibbonWidth: Number(settingsData.serviceRibbonWidth),
444 sidebarServicesLocation: Number(settingsData.sidebarServicesLocation),
445 iconSize: Number(settingsData.iconSize),
446 enableLongPressServiceHint: Boolean(
447 settingsData.enableLongPressServiceHint,
448 ),
449 useHorizontalStyle: Boolean(settingsData.useHorizontalStyle),
450 hideCollapseButton: Boolean(settingsData.hideCollapseButton),
451 hideRecipesButton: Boolean(settingsData.hideRecipesButton),
452 hideSplitModeButton: Boolean(settingsData.hideSplitModeButton),
453 useGrayscaleServices: Boolean(settingsData.useGrayscaleServices),
454 grayscaleServicesDim: Number(settingsData.grayscaleServicesDim),
455 hideWorkspacesButton: Boolean(settingsData.hideWorkspacesButton),
456 hideNotificationsButton: Boolean(settingsData.hideNotificationsButton),
457 hideSettingsButton: Boolean(settingsData.hideSettingsButton),
458 hideDownloadButton: Boolean(settingsData.hideDownloadButton),
459 alwaysShowWorkspaces: Boolean(settingsData.alwaysShowWorkspaces),
460 hideAllServicesWorkspace: Boolean(
461 settingsData.hideAllServicesWorkspace,
462 ),
463 accentColor: settingsData.accentColor,
464 progressbarAccentColor: settingsData.progressbarAccentColor,
465 showMessageBadgeWhenMuted: Boolean(
466 settingsData.showMessageBadgeWhenMuted,
467 ),
468 showDragArea: Boolean(settingsData.showDragArea),
469 enableSpellchecking: Boolean(settingsData.enableSpellchecking),
470 enableTranslator: Boolean(settingsData.enableTranslator),
471 useSelfSignedCertificates: Boolean(
472 settingsData.useSelfSignedCertificates,
473 ),
474 spellcheckerLanguage: settingsData.spellcheckerLanguage,
475 userAgentPref: settingsData.userAgentPref,
476 beta: Boolean(settingsData.beta), // we need this info in the main process as well
477 automaticUpdates: Boolean(settingsData.automaticUpdates), // we need this info in the main process as well
478 locale: settingsData.locale, // we need this info in the main process as well
479 },
480 }); 540 });
481 541
482 user.update({ 542 user.update({
@@ -982,6 +1042,14 @@ class EditSettingsScreen extends Component<
982 default: DEFAULT_APP_SETTINGS.userAgentPref, 1042 default: DEFAULT_APP_SETTINGS.userAgentPref,
983 placeholder: defaultUserAgent(), 1043 placeholder: defaultUserAgent(),
984 }, 1044 },
1045 downloadFolderPath: {
1046 label: intl.formatMessage(messages.downloadFolderPath),
1047 value: ifUndefined<string>(
1048 settings.all.app.downloadFolderPath,
1049 DEFAULT_APP_SETTINGS.downloadFolderPath,
1050 ),
1051 default: DEFAULT_APP_SETTINGS.userAgentPref,
1052 },
985 darkMode: { 1053 darkMode: {
986 label: intl.formatMessage(messages.darkMode), 1054 label: intl.formatMessage(messages.darkMode),
987 value: ifUndefined<boolean>( 1055 value: ifUndefined<boolean>(
diff --git a/src/electron/ipc-api/dnd.ts b/src/electron/ipc-api/dnd.ts
index 30ace7c84..280521a9f 100644
--- a/src/electron/ipc-api/dnd.ts
+++ b/src/electron/ipc-api/dnd.ts
@@ -8,7 +8,6 @@ export default async () => {
8 if (!isMac) { 8 if (!isMac) {
9 return false; 9 return false;
10 } 10 }
11
12 const { getDoNotDisturb } = await import('macos-notification-state'); 11 const { getDoNotDisturb } = await import('macos-notification-state');
13 12
14 if (!getDoNotDisturb) { 13 if (!getDoNotDisturb) {
diff --git a/src/electron/ipc-api/download.ts b/src/electron/ipc-api/download.ts
index d749cb889..a306ba68d 100644
--- a/src/electron/ipc-api/download.ts
+++ b/src/electron/ipc-api/download.ts
@@ -52,4 +52,14 @@ export default (params: { mainWindow: BrowserWindow }) => {
52 } 52 }
53 }, 53 },
54 ); 54 );
55
56 ipcMain.handle('download-folder-select', async () => {
57 const result = await dialog.showOpenDialog(params.mainWindow, {
58 properties: ['openDirectory'],
59 });
60
61 if (result.canceled) return null;
62
63 return result.filePaths[0];
64 });
55}; 65};
diff --git a/src/features/workspaces/components/WorkspaceDrawerItem.tsx b/src/features/workspaces/components/WorkspaceDrawerItem.tsx
index 01a18ffb0..23851edf6 100644
--- a/src/features/workspaces/components/WorkspaceDrawerItem.tsx
+++ b/src/features/workspaces/components/WorkspaceDrawerItem.tsx
@@ -125,10 +125,10 @@ class WorkspaceDrawerItem extends Component<IProps> {
125 }} 125 }}
126 onKeyDown={noop} 126 onKeyDown={noop}
127 data-tooltip-id="tooltip-workspaces-drawer" 127 data-tooltip-id="tooltip-workspaces-drawer"
128 data-tooltip-content={acceleratorString( 128 data-tooltip-content={acceleratorString({
129 shortcutIndex, 129 index: shortcutIndex,
130 `${cmdOrCtrlShortcutKey(false)}+${altKey(false)}`, 130 keyCombo: `${cmdOrCtrlShortcutKey(false)}+${altKey(false)}`,
131 )} 131 })}
132 > 132 >
133 <span 133 <span
134 className={classnames([ 134 className={classnames([
diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json
index d2d317586..50ab8d4ce 100644
--- a/src/i18n/locales/de.json
+++ b/src/i18n/locales/de.json
@@ -16,6 +16,7 @@
16 "feature.publishDebugInfo.info": "Die Veröffentlichung deiner Debug-Informationen hilft uns, Probleme und Fehler in Ferdium zu finden. Indem du deine Debug-Informationen veröffentlichst, akzeptierst du die Datenschutzbestimmungen und Nutzungsbedingungen vom Ferdium Debugger", 16 "feature.publishDebugInfo.info": "Die Veröffentlichung deiner Debug-Informationen hilft uns, Probleme und Fehler in Ferdium zu finden. Indem du deine Debug-Informationen veröffentlichst, akzeptierst du die Datenschutzbestimmungen und Nutzungsbedingungen vom Ferdium Debugger",
17 "feature.publishDebugInfo.privacy": "Datenschutzrichtlinien", 17 "feature.publishDebugInfo.privacy": "Datenschutzrichtlinien",
18 "feature.publishDebugInfo.publish": "Akzeptieren und Veröffentlichen", 18 "feature.publishDebugInfo.publish": "Akzeptieren und Veröffentlichen",
19 "feature.publishDebugInfo.published": "Ihr Debug-Protokoll wurde veröffentlicht und ist nun verfügbar unter",
19 "feature.publishDebugInfo.terms": "Nutzungsbedingungen", 20 "feature.publishDebugInfo.terms": "Nutzungsbedingungen",
20 "feature.publishDebugInfo.title": "Debug-Informationen veröffentlichen", 21 "feature.publishDebugInfo.title": "Debug-Informationen veröffentlichen",
21 "feature.quickSwitch.info": "Wähle einen Dienst mit TAB, ↑ und ↓. Um einen Dienst zu öffnen, drücke ENTER.", 22 "feature.quickSwitch.info": "Wähle einen Dienst mit TAB, ↑ und ↓. Um einen Dienst zu öffnen, drücke ENTER.",
@@ -24,6 +25,7 @@
24 "global.api.unhealthy": "Verbindung zu {serverNameParse} Online-Diensten kann nicht hergestellt werden", 25 "global.api.unhealthy": "Verbindung zu {serverNameParse} Online-Diensten kann nicht hergestellt werden",
25 "global.cancel": "Abbrechen", 26 "global.cancel": "Abbrechen",
26 "global.clearCache": "Cache leeren", 27 "global.clearCache": "Cache leeren",
28 "global.downloads": "Downloads",
27 "global.edit": "Bearbeiten", 29 "global.edit": "Bearbeiten",
28 "global.no": "Nein", 30 "global.no": "Nein",
29 "global.notConnectedToTheInternet": "Du bist nicht mit dem Internet verbunden.", 31 "global.notConnectedToTheInternet": "Du bist nicht mit dem Internet verbunden.",
@@ -122,6 +124,7 @@
122 "menu.view.back": "Zurück", 124 "menu.view.back": "Zurück",
123 "menu.view.forward": "Vorwärts", 125 "menu.view.forward": "Vorwärts",
124 "menu.view.lockFerdium": "Ferdium sperren", 126 "menu.view.lockFerdium": "Ferdium sperren",
127 "menu.view.openProcessManager": "Prozessverwaltung öffnen",
125 "menu.view.openQuickSwitch": "Quick Switch öffnen", 128 "menu.view.openQuickSwitch": "Quick Switch öffnen",
126 "menu.view.reloadFerdium": "Ferdium neu laden", 129 "menu.view.reloadFerdium": "Ferdium neu laden",
127 "menu.view.reloadService": "Dienst neu laden", 130 "menu.view.reloadService": "Dienst neu laden",
@@ -161,6 +164,8 @@
161 "service.errorHandler.headline": "Oh nein!", 164 "service.errorHandler.headline": "Oh nein!",
162 "service.errorHandler.message": "Fehler", 165 "service.errorHandler.message": "Fehler",
163 "service.errorHandler.text": "{name} konnte nicht geladen werden.", 166 "service.errorHandler.text": "{name} konnte nicht geladen werden.",
167 "service.screenshare.cancel": "Abbrechen",
168 "service.screenshare.loading": "Bildschirme und Fenster werden geladen",
164 "service.webviewLoader.loading": "{service} wird geladen", 169 "service.webviewLoader.loading": "{service} wird geladen",
165 "services.getStarted": "Los geht's", 170 "services.getStarted": "Los geht's",
166 "services.login": "Bitte anmelden, um Ferdium nutzen zu können.", 171 "services.login": "Bitte anmelden, um Ferdium nutzen zu können.",
@@ -189,6 +194,7 @@
189 "settings.app.buttonOpenFerdiumCertsFolder": "Ordner „Zertifikate” öffnen", 194 "settings.app.buttonOpenFerdiumCertsFolder": "Ordner „Zertifikate” öffnen",
190 "settings.app.buttonOpenFerdiumProfileFolder": "Profilordner anzeigen", 195 "settings.app.buttonOpenFerdiumProfileFolder": "Profilordner anzeigen",
191 "settings.app.buttonOpenFerdiumServiceRecipesFolder": "Rezeptordner öffnen", 196 "settings.app.buttonOpenFerdiumServiceRecipesFolder": "Rezeptordner öffnen",
197 "settings.app.buttonOpenFolderSelector": "Ordnerauswahl öffnen",
192 "settings.app.buttonOpenImportExport": "Importieren/Exportieren", 198 "settings.app.buttonOpenImportExport": "Importieren/Exportieren",
193 "settings.app.buttonSearchForUpdate": "Nach Aktualisierungen suchen", 199 "settings.app.buttonSearchForUpdate": "Nach Aktualisierungen suchen",
194 "settings.app.buttonShowChangelog": "Änderungen zeigen", 200 "settings.app.buttonShowChangelog": "Änderungen zeigen",
@@ -208,6 +214,7 @@
208 "settings.app.form.confirmOnQuit": "Beim Beenden von Ferdium bestätigen", 214 "settings.app.form.confirmOnQuit": "Beim Beenden von Ferdium bestätigen",
209 "settings.app.form.customTodoServer": "Eigener Todo Server", 215 "settings.app.form.customTodoServer": "Eigener Todo Server",
210 "settings.app.form.darkMode": "Dark Mode aktivieren", 216 "settings.app.form.darkMode": "Dark Mode aktivieren",
217 "settings.app.form.downloadFolderPath": "Standard-Download-Ordner (leer lassen, um bei jedem Download gefragt zu werden)",
211 "settings.app.form.enableGPUAcceleration": "Hardwarebeschleunigung aktivieren", 218 "settings.app.form.enableGPUAcceleration": "Hardwarebeschleunigung aktivieren",
212 "settings.app.form.enableGlobalHideShortcut": "Allgemeine Verknüpfung zum Ausblenden von Ferdium aktivieren", 219 "settings.app.form.enableGlobalHideShortcut": "Allgemeine Verknüpfung zum Ausblenden von Ferdium aktivieren",
213 "settings.app.form.enableLock": "Passwort-Sperre aktivieren", 220 "settings.app.form.enableLock": "Passwort-Sperre aktivieren",
@@ -220,7 +227,9 @@
220 "settings.app.form.grayscaleServicesDim": "Graustufen Dimmwert", 227 "settings.app.form.grayscaleServicesDim": "Graustufen Dimmwert",
221 "settings.app.form.hibernateOnStartup": "Dienste beim Start in den Ruhezustand versetzen", 228 "settings.app.form.hibernateOnStartup": "Dienste beim Start in den Ruhezustand versetzen",
222 "settings.app.form.hibernationStrategy": "\"Service Hibernation\"-Strategie", 229 "settings.app.form.hibernationStrategy": "\"Service Hibernation\"-Strategie",
230 "settings.app.form.hideAllServicesWorkspace": "Arbeitsbereich „Alle Dienste“ ausblenden",
223 "settings.app.form.hideCollapseButton": "Schaltfläche „Ausklappen” ausblenden", 231 "settings.app.form.hideCollapseButton": "Schaltfläche „Ausklappen” ausblenden",
232 "settings.app.form.hideDownloadButton": "Schaltfläche „Downloads“ ausblenden",
224 "settings.app.form.hideNotificationsButton": "Schaltfläche „Benachrichtigungen und Töne” ausblenden", 233 "settings.app.form.hideNotificationsButton": "Schaltfläche „Benachrichtigungen und Töne” ausblenden",
225 "settings.app.form.hideRecipesButton": "Schaltfläche „Neuen Dienst hinzufügen” ausblenden", 234 "settings.app.form.hideRecipesButton": "Schaltfläche „Neuen Dienst hinzufügen” ausblenden",
226 "settings.app.form.hideSettingsButton": "Schaltfläche „Einstellungen” ausblenden", 235 "settings.app.form.hideSettingsButton": "Schaltfläche „Einstellungen” ausblenden",
@@ -278,10 +287,16 @@
278 "settings.app.hibernateInfo": "Standardmäßig öffnet Ferdium alle deine Dienste im Hintergrund, sodass diese bereit sind, wenn du sie verwenden möchtest. \"Service Hibernation\" wird deine Dienste nach einer bestimmten Zeitspanne schließen. Dies ist nützlich, um RAM zu sparen oder Dienste davon abzuhalten, deinen Computer zu verlangsamen.", 287 "settings.app.hibernateInfo": "Standardmäßig öffnet Ferdium alle deine Dienste im Hintergrund, sodass diese bereit sind, wenn du sie verwenden möchtest. \"Service Hibernation\" wird deine Dienste nach einer bestimmten Zeitspanne schließen. Dies ist nützlich, um RAM zu sparen oder Dienste davon abzuhalten, deinen Computer zu verlangsamen.",
279 "settings.app.inactivityLockInfo": "Minuten der Inaktivität, nach denen Ferdium automatisch sperren soll. Verwenden Sie 0, um dies zu deaktivieren", 288 "settings.app.inactivityLockInfo": "Minuten der Inaktivität, nach denen Ferdium automatisch sperren soll. Verwenden Sie 0, um dies zu deaktivieren",
280 "settings.app.infoOpenCertificatesFolder": "Um ein Zertifikat zu installieren, klicken Sie auf die Schaltfläche unten, um den Zertifikatsordner zu öffnen, und kopieren Sie es in den Ordner. Danach können Sie den Dienst aktualisieren (STRG/CMD + R). Zum Entfernen/Deinstallieren löschen Sie einfach die Zertifikatsdatei und starten Ferdium neu.", 289 "settings.app.infoOpenCertificatesFolder": "Um ein Zertifikat zu installieren, klicken Sie auf die Schaltfläche unten, um den Zertifikatsordner zu öffnen, und kopieren Sie es in den Ordner. Danach können Sie den Dienst aktualisieren (STRG/CMD + R). Zum Entfernen/Deinstallieren löschen Sie einfach die Zertifikatsdatei und starten Ferdium neu.",
290 "settings.app.lockInfo": "Die Passwortsperre ermöglicht es Ihnen, Ihre Nachrichten zu schützen.\nWenn Sie die Passwortsperre verwenden, werden Sie bei jedem Start von Ferdium aufgefordert, Ihr Passwort einzugeben, oder Sie sperren Ferdium selbst, indem Sie das Schlosssymbol in der unteren linken Ecke oder das Tastaturkürzel {lockShortcut} verwenden.",
281 "settings.app.lockedPassword": "Passwort", 291 "settings.app.lockedPassword": "Passwort",
282 "settings.app.lockedPasswordInfo": "Bitte stelle sicher, dass du ein Passwort setzt, an welches du dich erinnern kannst.\nSolltest du dieses Passwort vergessen, musst du Ferdium neu installieren.", 292 "settings.app.lockedPasswordInfo": "Bitte stelle sicher, dass du ein Passwort setzt, an welches du dich erinnern kannst.\nSolltest du dieses Passwort vergessen, musst du Ferdium neu installieren.",
283 "settings.app.overallTheme": "Allgemeines Farbschema", 293 "settings.app.overallTheme": "Allgemeines Farbschema",
284 "settings.app.progressbarTheme": "Farbschema der Fortschrittsanzeige", 294 "settings.app.progressbarTheme": "Farbschema der Fortschrittsanzeige",
295 "settings.app.restart.restartDialogDetail": "Sie haben eine Änderung vorgenommen, die einen Neustart erfordert. Dadurch wird Ferdium geschlossen und neu gestartet.",
296 "settings.app.restart.restartDialogMessage": "Möchten Sie Ferdium erneut starten?",
297 "settings.app.restart.restartDialogTitle": "Ferdium - Anwendung neu starten",
298 "settings.app.restart.restartLater": "Später neu starten",
299 "settings.app.restart.restartNow": "Jetzt neu starten",
285 "settings.app.restartRequired": "Änderungen werden erst nach einem Neustart wirksam", 300 "settings.app.restartRequired": "Änderungen werden erst nach einem Neustart wirksam",
286 "settings.app.scheduledDNDInfo": "Die geplante \"Nicht-stören\"-Funktion erlaubt es dir eine Zeitspanne festzulegen, in der du keine Benachrichtigungen von Ferdium erhalten möchtest.", 301 "settings.app.scheduledDNDInfo": "Die geplante \"Nicht-stören\"-Funktion erlaubt es dir eine Zeitspanne festzulegen, in der du keine Benachrichtigungen von Ferdium erhalten möchtest.",
287 "settings.app.scheduledDNDTimeInfo": "Zeiten im 24-Stunden-Format (z.B. 18:00). Endzeit kann vor Beginn der Startzeit sein (z.B. 17:00 Uhr, Ende 09:00), um die Funktion über Nacht zu aktivieren.", 302 "settings.app.scheduledDNDTimeInfo": "Zeiten im 24-Stunden-Format (z.B. 18:00). Endzeit kann vor Beginn der Startzeit sein (z.B. 17:00 Uhr, Ende 09:00), um die Funktion über Nacht zu aktivieren.",
@@ -298,8 +313,11 @@
298 "settings.app.sentryInfo": "Das Senden von Telemetriedaten ermöglicht es uns, Fehler in Ferdium zu finden - es werden keine persönlichen Informationen wie Ihre Nachrichtendaten gesendet!", 313 "settings.app.sentryInfo": "Das Senden von Telemetriedaten ermöglicht es uns, Fehler in Ferdium zu finden - es werden keine persönlichen Informationen wie Ihre Nachrichtendaten gesendet!",
299 "settings.app.serverHelp": "Verbunden mit dem Server unter {serverURL}", 314 "settings.app.serverHelp": "Verbunden mit dem Server unter {serverURL}",
300 "settings.app.servicesUpdateStatusUpToDate": "Ihre Dienste sind auf dem neuesten Stand", 315 "settings.app.servicesUpdateStatusUpToDate": "Ihre Dienste sind auf dem neuesten Stand",
316 "settings.app.spellCheckerLanguageInfo": "Ferdium verwendet die in Ihrem Mac eingebaute Rechtschreibprüfung, um auf Tippfehler zu prüfen. Wenn Sie die Sprachen, die die Rechtschreibprüfung prüft, ändern möchten, können Sie dies in den Systemeinstellungen Ihres Macs tun.",
301 "settings.app.subheadlineCache": "Cache", 317 "settings.app.subheadlineCache": "Cache",
318 "settings.app.subheadlineDownloads": "Downloads",
302 "settings.app.subheadlineFerdiumProfile": "Ferdium Profil", 319 "settings.app.subheadlineFerdiumProfile": "Ferdium Profil",
320 "settings.app.subheadlineUserAgent": "Browserkennung",
303 "settings.app.todoServerInfo": "Dieser Server wird für die \"Ferdium Todo\"-Funktion verwendet.", 321 "settings.app.todoServerInfo": "Dieser Server wird für die \"Ferdium Todo\"-Funktion verwendet.",
304 "settings.app.translationHelp": "Hilf uns, Ferdium in Deine Sprache zu übersetzen.", 322 "settings.app.translationHelp": "Hilf uns, Ferdium in Deine Sprache zu übersetzen.",
305 "settings.app.universalDarkModeInfo": "Universeller Dark Mode versucht dynamisch Dienste abzudunkeln, die vom normalen Dark Mode noch nicht unterstützt werden.", 323 "settings.app.universalDarkModeInfo": "Universeller Dark Mode versucht dynamisch Dienste abzudunkeln, die vom normalen Dark Mode noch nicht unterstützt werden.",
@@ -329,6 +347,8 @@
329 "settings.recipes.missingService": "Fehlt ein Dienst?", 347 "settings.recipes.missingService": "Fehlt ein Dienst?",
330 "settings.recipes.nothingFound": "Leider hat kein Dienst zu deinem Suchbegriff gepasst - aber du kannst ihn wahrscheinlich trotzdem über die Option \"Eigene Website\" hinzufügen. Bitte beachte, dass die Website möglicherweise weitere Dienste anzeigt, die seit deiner aktuellen Version zu Ferdium hinzugefügt wurden. Um diese neuen Dienste zu erhalten, erwäge bitte ein Upgrade auf eine neuere Version von Ferdium.", 348 "settings.recipes.nothingFound": "Leider hat kein Dienst zu deinem Suchbegriff gepasst - aber du kannst ihn wahrscheinlich trotzdem über die Option \"Eigene Website\" hinzufügen. Bitte beachte, dass die Website möglicherweise weitere Dienste anzeigt, die seit deiner aktuellen Version zu Ferdium hinzugefügt wurden. Um diese neuen Dienste zu erhalten, erwäge bitte ein Upgrade auf eine neuere Version von Ferdium.",
331 "settings.recipes.servicesSuccessfulAddedInfo": "Dienst erfolgreich hinzugefügt", 349 "settings.recipes.servicesSuccessfulAddedInfo": "Dienst erfolgreich hinzugefügt",
350 "settings.releasenotes.connectionError": "Bei der Verbindung zu Github ist ein Fehler aufgetreten. Bitte versuchen Sie es später noch einmal.",
351 "settings.releasenotes.connectionErrorPageMissing": "Bei der Verbindung zu Github ist ein Fehler aufgetreten, die gesuchte Seite ist nicht vorhanden.",
332 "settings.releasenotes.headline": "Neuigkeiten", 352 "settings.releasenotes.headline": "Neuigkeiten",
333 "settings.searchService": "Dienst suchen", 353 "settings.searchService": "Dienst suchen",
334 "settings.service.error.goBack": "Zurück zu den Diensten", 354 "settings.service.error.goBack": "Zurück zu den Diensten",
@@ -385,6 +405,7 @@
385 "settings.service.form.tabOnPremise": "Selbst gehostet ⭐️", 405 "settings.service.form.tabOnPremise": "Selbst gehostet ⭐️",
386 "settings.service.form.team": "Team", 406 "settings.service.form.team": "Team",
387 "settings.service.form.trapLinkClicks": "URLs in Ferdium öffnen", 407 "settings.service.form.trapLinkClicks": "URLs in Ferdium öffnen",
408 "settings.service.form.useFavicon": "Favicon des Dienstes anstelle des Standard- oder benutzerdefinierten Symbols verwenden",
388 "settings.service.form.useHostedService": "Hosted {name} verwenden.", 409 "settings.service.form.useHostedService": "Hosted {name} verwenden.",
389 "settings.service.form.yourServices": "Deine Dienste", 410 "settings.service.form.yourServices": "Deine Dienste",
390 "settings.service.reloadRequired": "Änderungen werden erst nach einem Neuladen des Dienstes wirksam", 411 "settings.service.reloadRequired": "Änderungen werden erst nach einem Neuladen des Dienstes wirksam",
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json
index 3947b2e5f..cb0f4369c 100644
--- a/src/i18n/locales/en-US.json
+++ b/src/i18n/locales/en-US.json
@@ -194,6 +194,7 @@
194 "settings.app.buttonOpenFerdiumCertsFolder": "Open certificates folder", 194 "settings.app.buttonOpenFerdiumCertsFolder": "Open certificates folder",
195 "settings.app.buttonOpenFerdiumProfileFolder": "Open Profile folder", 195 "settings.app.buttonOpenFerdiumProfileFolder": "Open Profile folder",
196 "settings.app.buttonOpenFerdiumServiceRecipesFolder": "Open Service Recipes folder", 196 "settings.app.buttonOpenFerdiumServiceRecipesFolder": "Open Service Recipes folder",
197 "settings.app.buttonOpenFolderSelector": "Open folder selector",
197 "settings.app.buttonOpenImportExport": "Import / Export", 198 "settings.app.buttonOpenImportExport": "Import / Export",
198 "settings.app.buttonSearchForUpdate": "Check for updates", 199 "settings.app.buttonSearchForUpdate": "Check for updates",
199 "settings.app.buttonShowChangelog": "Show changelog", 200 "settings.app.buttonShowChangelog": "Show changelog",
@@ -213,6 +214,7 @@
213 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdium", 214 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdium",
214 "settings.app.form.customTodoServer": "Custom Todo Server", 215 "settings.app.form.customTodoServer": "Custom Todo Server",
215 "settings.app.form.darkMode": "Enable Dark Mode", 216 "settings.app.form.darkMode": "Enable Dark Mode",
217 "settings.app.form.downloadFolderPath": "Default download folder (leave blank to be prompted for each download)",
216 "settings.app.form.enableGPUAcceleration": "Enable GPU Acceleration", 218 "settings.app.form.enableGPUAcceleration": "Enable GPU Acceleration",
217 "settings.app.form.enableGlobalHideShortcut": "Enable Global shortcut to hide Ferdium", 219 "settings.app.form.enableGlobalHideShortcut": "Enable Global shortcut to hide Ferdium",
218 "settings.app.form.enableLock": "Enable Password Lock", 220 "settings.app.form.enableLock": "Enable Password Lock",
@@ -290,6 +292,11 @@
290 "settings.app.lockedPasswordInfo": "Please make sure to set a password you'll remember.\nIf you loose this password, you will have to reinstall Ferdium.", 292 "settings.app.lockedPasswordInfo": "Please make sure to set a password you'll remember.\nIf you loose this password, you will have to reinstall Ferdium.",
291 "settings.app.overallTheme": "Overall Theme", 293 "settings.app.overallTheme": "Overall Theme",
292 "settings.app.progressbarTheme": "Progressbar Theme", 294 "settings.app.progressbarTheme": "Progressbar Theme",
295 "settings.app.restart.restartDialogDetail": "You made a change that requires a restart. This will close Ferdium and restart it.",
296 "settings.app.restart.restartDialogMessage": "Do you want to relaunch Ferdium?",
297 "settings.app.restart.restartDialogTitle": "Ferdium - Relaunch Application",
298 "settings.app.restart.restartLater": "Restart later",
299 "settings.app.restart.restartNow": "Restart now",
293 "settings.app.restartRequired": "Changes require restart", 300 "settings.app.restartRequired": "Changes require restart",
294 "settings.app.scheduledDNDInfo": "Scheduled Do-not-Disturb allows you to define a period of time in which you do not want to get Notifications from Ferdium.", 301 "settings.app.scheduledDNDInfo": "Scheduled Do-not-Disturb allows you to define a period of time in which you do not want to get Notifications from Ferdium.",
295 "settings.app.scheduledDNDTimeInfo": "Times in 24-Hour-Format. End time can be before start time (e.g. start 17:00, end 09:00) to enable Do-not-Disturb overnight.", 302 "settings.app.scheduledDNDTimeInfo": "Times in 24-Hour-Format. End time can be before start time (e.g. start 17:00, end 09:00) to enable Do-not-Disturb overnight.",
@@ -308,7 +315,9 @@
308 "settings.app.servicesUpdateStatusUpToDate": "Your services are up-to-date", 315 "settings.app.servicesUpdateStatusUpToDate": "Your services are up-to-date",
309 "settings.app.spellCheckerLanguageInfo": "Ferdium uses your Mac's built-in spellchecker to check for typos. If you want to change the languages the spellchecker checks for, you can do so in your Mac's System Preferences.", 316 "settings.app.spellCheckerLanguageInfo": "Ferdium uses your Mac's built-in spellchecker to check for typos. If you want to change the languages the spellchecker checks for, you can do so in your Mac's System Preferences.",
310 "settings.app.subheadlineCache": "Cache", 317 "settings.app.subheadlineCache": "Cache",
318 "settings.app.subheadlineDownloads": "Downloads",
311 "settings.app.subheadlineFerdiumProfile": "Ferdium Profile", 319 "settings.app.subheadlineFerdiumProfile": "Ferdium Profile",
320 "settings.app.subheadlineUserAgent": "User Agent",
312 "settings.app.todoServerInfo": "This server will be used for the \"Ferdium Todo\" feature.", 321 "settings.app.todoServerInfo": "This server will be used for the \"Ferdium Todo\" feature.",
313 "settings.app.translationHelp": "Help us to translate Ferdium into your language.", 322 "settings.app.translationHelp": "Help us to translate Ferdium into your language.",
314 "settings.app.universalDarkModeInfo": "Universal Dark Mode tries to dynamically generate dark mode styles for services that are otherwise not currently supported.", 323 "settings.app.universalDarkModeInfo": "Universal Dark Mode tries to dynamically generate dark mode styles for services that are otherwise not currently supported.",
diff --git a/src/i18n/locales/it.json b/src/i18n/locales/it.json
index 6484d9524..8e3bb4e92 100644
--- a/src/i18n/locales/it.json
+++ b/src/i18n/locales/it.json
@@ -9,11 +9,14 @@
9 "connectionLostBanner.cta": "Ricarica Servizio", 9 "connectionLostBanner.cta": "Ricarica Servizio",
10 "connectionLostBanner.informationLink": "Cos'è successo?", 10 "connectionLostBanner.informationLink": "Cos'è successo?",
11 "connectionLostBanner.message": "Oh no! Ferdium ha perso la connessione con {name}.", 11 "connectionLostBanner.message": "Oh no! Ferdium ha perso la connessione con {name}.",
12 "downloadManager.empty": "La tua lista di download è vuota.",
13 "downloadManager.headline": "Gestione Download",
12 "feature.basicAuth.signIn": "Accedi", 14 "feature.basicAuth.signIn": "Accedi",
13 "feature.publishDebugInfo.error": "Si è verificato un errore durante il tentativo di pubblicare le informazioni di debug. Riprova più tardi o vedi la console per maggiori informazioni.", 15 "feature.publishDebugInfo.error": "Si è verificato un errore durante il tentativo di pubblicare le informazioni di debug. Riprova più tardi o vedi la console per maggiori informazioni.",
14 "feature.publishDebugInfo.info": "Pubblicare le informazioni di debug ci aiuta a trovare problemi ed errori in Ferdium. Pubblicando le informazioni di debug accetti l'informativa sulla privacy e i termini di servizio di Ferdium Debugger", 16 "feature.publishDebugInfo.info": "Pubblicare le informazioni di debug ci aiuta a trovare problemi ed errori in Ferdium. Pubblicando le informazioni di debug accetti l'informativa sulla privacy e i termini di servizio di Ferdium Debugger",
15 "feature.publishDebugInfo.privacy": "Informativa sulla privacy", 17 "feature.publishDebugInfo.privacy": "Informativa sulla privacy",
16 "feature.publishDebugInfo.publish": "Accetta e pubblica", 18 "feature.publishDebugInfo.publish": "Accetta e pubblica",
19 "feature.publishDebugInfo.published": "Il tuo log di debug è stato pubblicato ed è disponibile a",
17 "feature.publishDebugInfo.terms": "Termini di Servizio", 20 "feature.publishDebugInfo.terms": "Termini di Servizio",
18 "feature.publishDebugInfo.title": "Pubblica le informazioni di debug", 21 "feature.publishDebugInfo.title": "Pubblica le informazioni di debug",
19 "feature.quickSwitch.info": "Seleziona un servizio con TAB, ↑ e ↓. Apri un servizio con INVIO.", 22 "feature.quickSwitch.info": "Seleziona un servizio con TAB, ↑ e ↓. Apri un servizio con INVIO.",
@@ -21,6 +24,8 @@
21 "feature.quickSwitch.title": "Cambio Veloce", 24 "feature.quickSwitch.title": "Cambio Veloce",
22 "global.api.unhealthy": "Impossibile connettersi ai servizi online di {serverNameParse}", 25 "global.api.unhealthy": "Impossibile connettersi ai servizi online di {serverNameParse}",
23 "global.cancel": "Annulla", 26 "global.cancel": "Annulla",
27 "global.clearCache": "Svuota la cache",
28 "global.downloads": "Downloads",
24 "global.edit": "Modifica", 29 "global.edit": "Modifica",
25 "global.no": "No", 30 "global.no": "No",
26 "global.notConnectedToTheInternet": "Non sei connesso a Internet.", 31 "global.notConnectedToTheInternet": "Non sei connesso a Internet.",
@@ -119,6 +124,7 @@
119 "menu.view.back": "Indietro", 124 "menu.view.back": "Indietro",
120 "menu.view.forward": "Avanti", 125 "menu.view.forward": "Avanti",
121 "menu.view.lockFerdium": "Blocca Ferdium", 126 "menu.view.lockFerdium": "Blocca Ferdium",
127 "menu.view.openProcessManager": "Apri Gestione Processi",
122 "menu.view.openQuickSwitch": "Apri Cambio Rapido", 128 "menu.view.openQuickSwitch": "Apri Cambio Rapido",
123 "menu.view.reloadFerdium": "Ricarica Ferdium", 129 "menu.view.reloadFerdium": "Ricarica Ferdium",
124 "menu.view.reloadService": "Ricarica Servizio", 130 "menu.view.reloadService": "Ricarica Servizio",
@@ -158,6 +164,8 @@
158 "service.errorHandler.headline": "Oh no!", 164 "service.errorHandler.headline": "Oh no!",
159 "service.errorHandler.message": "Errore", 165 "service.errorHandler.message": "Errore",
160 "service.errorHandler.text": "{name} non si è caricato correttamente.", 166 "service.errorHandler.text": "{name} non si è caricato correttamente.",
167 "service.screenshare.cancel": "Annulla",
168 "service.screenshare.loading": "Caricamento schermi e finestre",
161 "service.webviewLoader.loading": "Caricamento {service}", 169 "service.webviewLoader.loading": "Caricamento {service}",
162 "services.getStarted": "Iniziamo", 170 "services.getStarted": "Iniziamo",
163 "services.login": "Effettua il login per utlizzare Ferdium.", 171 "services.login": "Effettua il login per utlizzare Ferdium.",
@@ -183,8 +191,10 @@
183 "settings.account.yourLicense": "La tua licenza Ferdium:", 191 "settings.account.yourLicense": "La tua licenza Ferdium:",
184 "settings.app.accentColorInfo": "Scrivi la tua scelta di colore in un formato compatibile con CSS. (Predefinito: {defaultAccentColor} o cancella il campo di input)", 192 "settings.app.accentColorInfo": "Scrivi la tua scelta di colore in un formato compatibile con CSS. (Predefinito: {defaultAccentColor} o cancella il campo di input)",
185 "settings.app.buttonInstallUpdate": "Riavvia e installa l'aggiornamento", 193 "settings.app.buttonInstallUpdate": "Riavvia e installa l'aggiornamento",
194 "settings.app.buttonOpenFerdiumCertsFolder": "Apri la cartella dei certificati",
186 "settings.app.buttonOpenFerdiumProfileFolder": "Apri cartella del profilo utente", 195 "settings.app.buttonOpenFerdiumProfileFolder": "Apri cartella del profilo utente",
187 "settings.app.buttonOpenFerdiumServiceRecipesFolder": "Apri cartella ricette dei servizi", 196 "settings.app.buttonOpenFerdiumServiceRecipesFolder": "Apri cartella ricette dei servizi",
197 "settings.app.buttonOpenFolderSelector": "Apri esplora risorse",
188 "settings.app.buttonOpenImportExport": "Importa / Esporta", 198 "settings.app.buttonOpenImportExport": "Importa / Esporta",
189 "settings.app.buttonSearchForUpdate": "Controlla aggiornamenti", 199 "settings.app.buttonSearchForUpdate": "Controlla aggiornamenti",
190 "settings.app.buttonShowChangelog": "Visualizza le modifiche", 200 "settings.app.buttonShowChangelog": "Visualizza le modifiche",
@@ -204,6 +214,7 @@
204 "settings.app.form.confirmOnQuit": "Conferma quando esci da Ferdium", 214 "settings.app.form.confirmOnQuit": "Conferma quando esci da Ferdium",
205 "settings.app.form.customTodoServer": "Server Todo personalizzato", 215 "settings.app.form.customTodoServer": "Server Todo personalizzato",
206 "settings.app.form.darkMode": "Attiva la modalità scura", 216 "settings.app.form.darkMode": "Attiva la modalità scura",
217 "settings.app.form.downloadFolderPath": "Cartella predefinita per i download (lasciare vuoto per selezionarla a ogni download)",
207 "settings.app.form.enableGPUAcceleration": "Attiva Accelerazione GPU", 218 "settings.app.form.enableGPUAcceleration": "Attiva Accelerazione GPU",
208 "settings.app.form.enableGlobalHideShortcut": "Abilita la combinazione di tasti (shortcut) per nascondere Ferdium", 219 "settings.app.form.enableGlobalHideShortcut": "Abilita la combinazione di tasti (shortcut) per nascondere Ferdium",
209 "settings.app.form.enableLock": "Abilita blocco con password", 220 "settings.app.form.enableLock": "Abilita blocco con password",
@@ -216,7 +227,9 @@
216 "settings.app.form.grayscaleServicesDim": "Livello di luminosità della scala di grigi", 227 "settings.app.form.grayscaleServicesDim": "Livello di luminosità della scala di grigi",
217 "settings.app.form.hibernateOnStartup": "Mantieni i servizi in ibernazione all'avvio", 228 "settings.app.form.hibernateOnStartup": "Mantieni i servizi in ibernazione all'avvio",
218 "settings.app.form.hibernationStrategy": "Strategia di ibernazione", 229 "settings.app.form.hibernationStrategy": "Strategia di ibernazione",
230 "settings.app.form.hideAllServicesWorkspace": "Nascondi spazio di lavoro \"Tutti i servizi\"",
219 "settings.app.form.hideCollapseButton": "Nascondi il pulsante comprimi", 231 "settings.app.form.hideCollapseButton": "Nascondi il pulsante comprimi",
232 "settings.app.form.hideDownloadButton": "Nascondi il pulsante Scarica",
220 "settings.app.form.hideNotificationsButton": "Nascondi il pulsante Notifiche & Suono", 233 "settings.app.form.hideNotificationsButton": "Nascondi il pulsante Notifiche & Suono",
221 "settings.app.form.hideRecipesButton": "Nascondi il punsate aggiungi servizio", 234 "settings.app.form.hideRecipesButton": "Nascondi il punsate aggiungi servizio",
222 "settings.app.form.hideSettingsButton": "Nascondi il pulsante delle impostazioni", 235 "settings.app.form.hideSettingsButton": "Nascondi il pulsante delle impostazioni",
@@ -224,6 +237,7 @@
224 "settings.app.form.hideWorkspacesButton": "Nascondi barra di trascinamento", 237 "settings.app.form.hideWorkspacesButton": "Nascondi barra di trascinamento",
225 "settings.app.form.iconSize": "Dimensione icone servizi", 238 "settings.app.form.iconSize": "Dimensione icone servizi",
226 "settings.app.form.inactivityLock": "Blocca dopo inattività", 239 "settings.app.form.inactivityLock": "Blocca dopo inattività",
240 "settings.app.form.isTwoFactorAutoCatcherEnabled": "Cattura automaticamente i codici a due fattori dalle notifiche (Es: messaggi Android) e copia negli appunti",
227 "settings.app.form.keepAllWorkspacesLoaded": "Mantieni tutti i workspace caricati", 241 "settings.app.form.keepAllWorkspacesLoaded": "Mantieni tutti i workspace caricati",
228 "settings.app.form.language": "Lingua", 242 "settings.app.form.language": "Lingua",
229 "settings.app.form.lockPassword": "Password", 243 "settings.app.form.lockPassword": "Password",
@@ -253,9 +267,11 @@
253 "settings.app.form.startMinimized": "Avvio ridotto a icona", 267 "settings.app.form.startMinimized": "Avvio ridotto a icona",
254 "settings.app.form.translatorEngine": "Motore di traduzione", 268 "settings.app.form.translatorEngine": "Motore di traduzione",
255 "settings.app.form.translatorLanguage": "Lingua predefinita del traduttore", 269 "settings.app.form.translatorLanguage": "Lingua predefinita del traduttore",
270 "settings.app.form.twoFactorAutoCatcherMatcher": "Parole/espressioni separate da virgole e case-sensitive per catturare i codici a due fattori. Es.: token, code, sms, verify",
256 "settings.app.form.universalDarkMode": "Abilita la modalità scura universale", 271 "settings.app.form.universalDarkMode": "Abilita la modalità scura universale",
257 "settings.app.form.useGrayscaleServices": "Visualizza le icon dei servizi con scala di grigi", 272 "settings.app.form.useGrayscaleServices": "Visualizza le icon dei servizi con scala di grigi",
258 "settings.app.form.useHorizontalStyle": "Usa stile orizzontale", 273 "settings.app.form.useHorizontalStyle": "Usa stile orizzontale",
274 "settings.app.form.useSelfSignedCertificates": "Usa certificati auto-firmati",
259 "settings.app.form.useTouchIdToUnlock": "Consenti l'utilizzo di TouchID per sbloccare Ferdium", 275 "settings.app.form.useTouchIdToUnlock": "Consenti l'utilizzo di TouchID per sbloccare Ferdium",
260 "settings.app.form.wakeUpHibernationSplay": "Esegui cicli di ibernato/risveglio per ridurre il carico", 276 "settings.app.form.wakeUpHibernationSplay": "Esegui cicli di ibernato/risveglio per ridurre il carico",
261 "settings.app.form.wakeUpHibernationStrategy": "Strategia di ibernazione dopo il risveglio automatico", 277 "settings.app.form.wakeUpHibernationStrategy": "Strategia di ibernazione dopo il risveglio automatico",
@@ -270,10 +286,17 @@
270 "settings.app.headlineUpdates": "Aggiornamenti", 286 "settings.app.headlineUpdates": "Aggiornamenti",
271 "settings.app.hibernateInfo": "Per impostazione predefinita, Ferdium manterrà tutti i servizi aperti e caricati in background in modo che siano pronti quando si desidera utilizzarli. Il servizio Hibernation sospenderà i servizi dopo un tempo specificato. Questo è utile per risparmiare RAM o per evitare che i servizi rallentino il computer.", 287 "settings.app.hibernateInfo": "Per impostazione predefinita, Ferdium manterrà tutti i servizi aperti e caricati in background in modo che siano pronti quando si desidera utilizzarli. Il servizio Hibernation sospenderà i servizi dopo un tempo specificato. Questo è utile per risparmiare RAM o per evitare che i servizi rallentino il computer.",
272 "settings.app.inactivityLockInfo": "Minuti di inattività oltre i quali Ferdium si bloccherà automaticamente, 0 per disabilitare", 288 "settings.app.inactivityLockInfo": "Minuti di inattività oltre i quali Ferdium si bloccherà automaticamente, 0 per disabilitare",
289 "settings.app.infoOpenCertificatesFolder": "Per installare un certificato, fai clic sul pulsante qui sotto per aprire la cartella dei certificati e copialo nella cartella. Dopo di che è possibile aggiornare il servizio (CTRL/CMD + R). Per rimuovere/disinstallare, basta eliminare il file del certificato e riavviare Ferdium.",
290 "settings.app.lockInfo": "Password Lock ti permette di mantenere i tuoi messaggi protetti. Usando Password Lock, ti verrà richiesto di inserire la tua password ogni volta che avvii Ferdium o di bloccare Ferdium stesso usando il simbolo del lucchetto nell'angolo in basso a sinistra o la scorciatoia {lockShortcut}.",
273 "settings.app.lockedPassword": "Password", 291 "settings.app.lockedPassword": "Password",
274 "settings.app.lockedPasswordInfo": "Assicurati di impostare una password che ricordi.\nSe perdi questa password, dovrai reinstallare Ferdium.", 292 "settings.app.lockedPasswordInfo": "Assicurati di impostare una password che ricordi.\nSe perdi questa password, dovrai reinstallare Ferdium.",
275 "settings.app.overallTheme": "Tema Globale", 293 "settings.app.overallTheme": "Tema Globale",
276 "settings.app.progressbarTheme": "Colore della barra di avanzamento", 294 "settings.app.progressbarTheme": "Colore della barra di avanzamento",
295 "settings.app.restart.restartDialogDetail": "Hai fatto un cambiamento che richiede un riavvio. Questo chiuderà Ferdium e lo riavvierà.",
296 "settings.app.restart.restartDialogMessage": "Vuoi riavviare Ferdium?",
297 "settings.app.restart.restartDialogTitle": "Ferdium - Riavvia Applicazione",
298 "settings.app.restart.restartLater": "Riavvia più tardi",
299 "settings.app.restart.restartNow": "Riavvia ora",
277 "settings.app.restartRequired": "Le modifiche richiedono un riavvio", 300 "settings.app.restartRequired": "Le modifiche richiedono un riavvio",
278 "settings.app.scheduledDNDInfo": "I Do-not-Disturb pianificati consentono di definire un periodo di tempo nel quale le notifiche da Ferdium saranno disabilitate.", 301 "settings.app.scheduledDNDInfo": "I Do-not-Disturb pianificati consentono di definire un periodo di tempo nel quale le notifiche da Ferdium saranno disabilitate.",
279 "settings.app.scheduledDNDTimeInfo": "Ora in formato 24 ore. L'ora di fine può essere prima dell'ora di inizio (ad esempio inizio 17:00, fine 09:00) per abilitare Do-not-Disturb durante la notte.", 302 "settings.app.scheduledDNDTimeInfo": "Ora in formato 24 ore. L'ora di fine può essere prima dell'ora di inizio (ad esempio inizio 17:00, fine 09:00) per abilitare Do-not-Disturb durante la notte.",
@@ -289,14 +312,19 @@
289 "settings.app.sectionUpdates": "Impostazioni Aggiornamenti App", 312 "settings.app.sectionUpdates": "Impostazioni Aggiornamenti App",
290 "settings.app.sentryInfo": "L'invio dei dati di telemetria ci permette di trovare errori in Ferdium - non invieremo nessuna informazione personale relativa ai tuoi messaggi!", 313 "settings.app.sentryInfo": "L'invio dei dati di telemetria ci permette di trovare errori in Ferdium - non invieremo nessuna informazione personale relativa ai tuoi messaggi!",
291 "settings.app.serverHelp": "Connesso al server a {serverURL}", 314 "settings.app.serverHelp": "Connesso al server a {serverURL}",
315 "settings.app.servicesUpdateStatusUpToDate": "I tuoi servizi sono aggiornati",
316 "settings.app.spellCheckerLanguageInfo": "Ferdium utilizza il controllo ortografico del tuo Mac per verificare la presenza di errori. Se si desidera modificare le lingue del controllo ortografico, è possibile farlo nelle preferenze di sistema del vostro Mac.",
292 "settings.app.subheadlineCache": "Cache", 317 "settings.app.subheadlineCache": "Cache",
318 "settings.app.subheadlineDownloads": "Downloads",
293 "settings.app.subheadlineFerdiumProfile": "Profilo Ferdium", 319 "settings.app.subheadlineFerdiumProfile": "Profilo Ferdium",
320 "settings.app.subheadlineUserAgent": "User Agent",
294 "settings.app.todoServerInfo": "Questo server sarà utilizzato per la funzione \"Ferdium Todo\".", 321 "settings.app.todoServerInfo": "Questo server sarà utilizzato per la funzione \"Ferdium Todo\".",
295 "settings.app.translationHelp": "Aiutaci a tradurre Ferdium nella tua lingua.", 322 "settings.app.translationHelp": "Aiutaci a tradurre Ferdium nella tua lingua.",
296 "settings.app.universalDarkModeInfo": "La modalità 'Dark Mode' universale cerca di generare dinamicamente uno stile di visualizzazione a sfondo scuro per quei servizi che non lo supportano nativamente.", 323 "settings.app.universalDarkModeInfo": "La modalità 'Dark Mode' universale cerca di generare dinamicamente uno stile di visualizzazione a sfondo scuro per quei servizi che non lo supportano nativamente.",
297 "settings.app.updateStatusAvailable": "Aggiornamento disponibile, download in corso...", 324 "settings.app.updateStatusAvailable": "Aggiornamento disponibile, download in corso...",
298 "settings.app.updateStatusSearching": "Ricerca aggiornamenti...", 325 "settings.app.updateStatusSearching": "Ricerca aggiornamenti...",
299 "settings.app.updateStatusUpToDate": "Stai utilizzando l'ultima versione di Ferdium", 326 "settings.app.updateStatusUpToDate": "Stai utilizzando l'ultima versione di Ferdium",
327 "settings.app.warningSelfSignedCertificates": "ATTENZIONE: Abilita questa funzione solo se sai cosa stai facendo. Abilitare la funzione è un rischio per la sicurezza e dovrebbe essere utilizzato solo a fini di prova.",
300 "settings.invite.headline": "Invita Amici", 328 "settings.invite.headline": "Invita Amici",
301 "settings.navigation.account": "Profilo", 329 "settings.navigation.account": "Profilo",
302 "settings.navigation.availableServices": "Servizi disponibili", 330 "settings.navigation.availableServices": "Servizi disponibili",
@@ -319,6 +347,8 @@
319 "settings.recipes.missingService": "Manca un servizio?", 347 "settings.recipes.missingService": "Manca un servizio?",
320 "settings.recipes.nothingFound": "Non è stato trovato alcun servizio corrispondente alla ricerca impostata. Ricorda che anche se non esiste un servizio specifico, potrebbe essere possibile usare la funzionalità \"Sito Custom\". Inoltre potrebbe essere che sul sito web di Ferdium siano mostrati più servizi di quanti disponibili nella applicazione correntemente in uso. Nel caso, per accedere a questi servizi, è possibile aggiornare Ferdium.", 348 "settings.recipes.nothingFound": "Non è stato trovato alcun servizio corrispondente alla ricerca impostata. Ricorda che anche se non esiste un servizio specifico, potrebbe essere possibile usare la funzionalità \"Sito Custom\". Inoltre potrebbe essere che sul sito web di Ferdium siano mostrati più servizi di quanti disponibili nella applicazione correntemente in uso. Nel caso, per accedere a questi servizi, è possibile aggiornare Ferdium.",
321 "settings.recipes.servicesSuccessfulAddedInfo": "Servizio aggiunto con successo", 349 "settings.recipes.servicesSuccessfulAddedInfo": "Servizio aggiunto con successo",
350 "settings.releasenotes.connectionError": "Si è verificato un errore durante la connessione a Github, riprova più tardi.",
351 "settings.releasenotes.connectionErrorPageMissing": "Si è verificato un errore durante la connessione a Github, la pagina che stai cercando non esiste.",
322 "settings.releasenotes.headline": "Note di rilascio", 352 "settings.releasenotes.headline": "Note di rilascio",
323 "settings.searchService": "Cerca servizio", 353 "settings.searchService": "Cerca servizio",
324 "settings.service.error.goBack": "Torna ai servizi", 354 "settings.service.error.goBack": "Torna ai servizi",
@@ -375,6 +405,7 @@
375 "settings.service.form.tabOnPremise": "Auto Hosted", 405 "settings.service.form.tabOnPremise": "Auto Hosted",
376 "settings.service.form.team": "Gruppo", 406 "settings.service.form.team": "Gruppo",
377 "settings.service.form.trapLinkClicks": "Apri url con Ferdium", 407 "settings.service.form.trapLinkClicks": "Apri url con Ferdium",
408 "settings.service.form.useFavicon": "Utilizza la favicon del servizio al posto dell'icona predefinita oppure un'icona personalizzata",
378 "settings.service.form.useHostedService": "Utilizza il servizio personalizzato {name}.", 409 "settings.service.form.useHostedService": "Utilizza il servizio personalizzato {name}.",
379 "settings.service.form.yourServices": "I tuoi servizi", 410 "settings.service.form.yourServices": "I tuoi servizi",
380 "settings.service.reloadRequired": "Le modifiche richiedo il reload del servizio", 411 "settings.service.reloadRequired": "Le modifiche richiedo il reload del servizio",
diff --git a/src/i18n/locales/ru.json b/src/i18n/locales/ru.json
index e6ee0e35f..24ca894ee 100644
--- a/src/i18n/locales/ru.json
+++ b/src/i18n/locales/ru.json
@@ -159,6 +159,7 @@
159 "service.errorHandler.headline": "О, нет!", 159 "service.errorHandler.headline": "О, нет!",
160 "service.errorHandler.message": "Ошибка", 160 "service.errorHandler.message": "Ошибка",
161 "service.errorHandler.text": "{name} не смог загрузиться.", 161 "service.errorHandler.text": "{name} не смог загрузиться.",
162 "service.screenshare.cancel": "Отмена",
162 "service.webviewLoader.loading": "Загрузка {service}", 163 "service.webviewLoader.loading": "Загрузка {service}",
163 "services.getStarted": "Начать работу", 164 "services.getStarted": "Начать работу",
164 "services.login": "Пожалуйста, войдите, чтобы использовать Ferdium.", 165 "services.login": "Пожалуйста, войдите, чтобы использовать Ferdium.",
@@ -214,6 +215,7 @@
214 "settings.app.form.enableTodos": "Включить задания Ferdium", 215 "settings.app.form.enableTodos": "Включить задания Ferdium",
215 "settings.app.form.hibernateOnStartup": "Оставлять сервисы в состоянии глубокого сна во время запуска", 216 "settings.app.form.hibernateOnStartup": "Оставлять сервисы в состоянии глубокого сна во время запуска",
216 "settings.app.form.hibernationStrategy": "Стратегия гибернации", 217 "settings.app.form.hibernationStrategy": "Стратегия гибернации",
218 "settings.app.form.hideCollapseButton": "Скрыть кнопку \"Свернуть\"",
217 "settings.app.form.hideDownloadButton": "Скрыть кнопку \"Загрузки\"", 219 "settings.app.form.hideDownloadButton": "Скрыть кнопку \"Загрузки\"",
218 "settings.app.form.hideNotificationsButton": "Скрыть кнопки уведомлений и звука", 220 "settings.app.form.hideNotificationsButton": "Скрыть кнопки уведомлений и звука",
219 "settings.app.form.hideSettingsButton": "Скрыть кнопку настроек", 221 "settings.app.form.hideSettingsButton": "Скрыть кнопку настроек",
@@ -244,6 +246,7 @@
244 "settings.app.form.splitMode": "Включить раздельный режим просмотра", 246 "settings.app.form.splitMode": "Включить раздельный режим просмотра",
245 "settings.app.form.startMinimized": "Запускать свернутым", 247 "settings.app.form.startMinimized": "Запускать свернутым",
246 "settings.app.form.universalDarkMode": "Включить универсальный темный режим", 248 "settings.app.form.universalDarkMode": "Включить универсальный темный режим",
249 "settings.app.form.useSelfSignedCertificates": "Принимать самоподписные сертификаты",
247 "settings.app.form.useTouchIdToUnlock": "Разрешить разблокировку Ferdium по TouchID", 250 "settings.app.form.useTouchIdToUnlock": "Разрешить разблокировку Ferdium по TouchID",
248 "settings.app.form.wakeUpHibernationSplay": "Чередование циклов cна/пробуждения для уменьшения нагрузки", 251 "settings.app.form.wakeUpHibernationSplay": "Чередование циклов cна/пробуждения для уменьшения нагрузки",
249 "settings.app.form.wakeUpHibernationStrategy": "Действия после автоматического просыпания", 252 "settings.app.form.wakeUpHibernationStrategy": "Действия после автоматического просыпания",
@@ -261,10 +264,15 @@
261 "settings.app.lockedPasswordInfo": "Пожалуйста, убедитесь, что установлен пароль, который вы запомните.\nЕсли вы потеряете этот пароль, вам придется переустановить Ferdium.", 264 "settings.app.lockedPasswordInfo": "Пожалуйста, убедитесь, что установлен пароль, который вы запомните.\nЕсли вы потеряете этот пароль, вам придется переустановить Ferdium.",
262 "settings.app.overallTheme": "Общая тема", 265 "settings.app.overallTheme": "Общая тема",
263 "settings.app.progressbarTheme": "Тема Прогресса", 266 "settings.app.progressbarTheme": "Тема Прогресса",
267 "settings.app.restart.restartDialogMessage": "Вы хотите перезапустить Ferdium?",
268 "settings.app.restart.restartDialogTitle": "Ferdium - Перезапуск приложения",
269 "settings.app.restart.restartLater": "Перезапустить позже",
270 "settings.app.restart.restartNow": "Перезапустить сейчас",
264 "settings.app.restartRequired": "Изменения требуют перезагрузки приложения", 271 "settings.app.restartRequired": "Изменения требуют перезагрузки приложения",
265 "settings.app.scheduledDNDInfo": "Запланированный режим \"не беспокоить\" позволяет вам определить период времени, в течение которого вы не желаете получать уведомления от Ferdium.", 272 "settings.app.scheduledDNDInfo": "Запланированный режим \"не беспокоить\" позволяет вам определить период времени, в течение которого вы не желаете получать уведомления от Ferdium.",
266 "settings.app.scheduledDNDTimeInfo": "Время в 24-часовом формате. Время окончания может быть раньше времени начала (например, начало 17:00, конец 09:00), чтобы включить ночной режим \"не беспокоить\".", 273 "settings.app.scheduledDNDTimeInfo": "Время в 24-часовом формате. Время окончания может быть раньше времени начала (например, начало 17:00, конец 09:00), чтобы включить ночной режим \"не беспокоить\".",
267 "settings.app.sectionAdvanced": "Расширенные настройки", 274 "settings.app.sectionAdvanced": "Расширенные настройки",
275 "settings.app.sectionHibernation": "Гибернация",
268 "settings.app.sectionLanguage": "Настройка языка", 276 "settings.app.sectionLanguage": "Настройка языка",
269 "settings.app.sectionPrivacy": "Настройки конфиденциальности", 277 "settings.app.sectionPrivacy": "Настройки конфиденциальности",
270 "settings.app.sectionServiceIconsSettings": "Настройки значков сервиса", 278 "settings.app.sectionServiceIconsSettings": "Настройки значков сервиса",
@@ -274,6 +282,7 @@
274 "settings.app.serverHelp": "Подключен к серверу {serverURL}", 282 "settings.app.serverHelp": "Подключен к серверу {serverURL}",
275 "settings.app.servicesUpdateStatusUpToDate": "Ваши сервисы актуальны", 283 "settings.app.servicesUpdateStatusUpToDate": "Ваши сервисы актуальны",
276 "settings.app.subheadlineCache": "Кэш", 284 "settings.app.subheadlineCache": "Кэш",
285 "settings.app.subheadlineDownloads": "Загрузки",
277 "settings.app.subheadlineFerdiumProfile": "Профиль Ferdium", 286 "settings.app.subheadlineFerdiumProfile": "Профиль Ferdium",
278 "settings.app.todoServerInfo": "Этот сервер будет использоваться для функции задач \"Ferdium Todo\".", 287 "settings.app.todoServerInfo": "Этот сервер будет использоваться для функции задач \"Ferdium Todo\".",
279 "settings.app.translationHelp": "Помогите нам перевести Ferdium на ваш язык.", 288 "settings.app.translationHelp": "Помогите нам перевести Ferdium на ваш язык.",
@@ -303,6 +312,8 @@
303 "settings.recipes.missingService": "Не можете найти сервис?", 312 "settings.recipes.missingService": "Не можете найти сервис?",
304 "settings.recipes.nothingFound": "Извините, но сервис не соответствует вашему поисковому запросу - но вы все еще можете добавить его, используя опцию \"Пользовательский сайт\". Пожалуйста, обратите внимание, что на сайте может отображаться больше служб, которые могли быть добавлены в новых версиях Ferdium. Для получения новых сервисов, пожалуйста, обновите Ferdium до актуальной версии.", 313 "settings.recipes.nothingFound": "Извините, но сервис не соответствует вашему поисковому запросу - но вы все еще можете добавить его, используя опцию \"Пользовательский сайт\". Пожалуйста, обратите внимание, что на сайте может отображаться больше служб, которые могли быть добавлены в новых версиях Ferdium. Для получения новых сервисов, пожалуйста, обновите Ferdium до актуальной версии.",
305 "settings.recipes.servicesSuccessfulAddedInfo": "Сервис успешно добавлен", 314 "settings.recipes.servicesSuccessfulAddedInfo": "Сервис успешно добавлен",
315 "settings.releasenotes.connectionError": "Произошла ошибка при подключении к Github, пожалуйста, повторите попытку позже.",
316 "settings.releasenotes.connectionErrorPageMissing": "Произошла ошибка при подключении к Github, страница, которую вы ищете, отсутствует.",
306 "settings.releasenotes.headline": "Информация о выпуске", 317 "settings.releasenotes.headline": "Информация о выпуске",
307 "settings.searchService": "Найти сервис", 318 "settings.searchService": "Найти сервис",
308 "settings.service.error.goBack": "Вернуться к сервисам", 319 "settings.service.error.goBack": "Вернуться к сервисам",
@@ -324,6 +335,7 @@
324 "settings.service.form.enableNotification": "Включить уведомления", 335 "settings.service.form.enableNotification": "Включить уведомления",
325 "settings.service.form.enableService": "Включить сервис", 336 "settings.service.form.enableService": "Включить сервис",
326 "settings.service.form.enableWakeUp": "Включить пробуждение", 337 "settings.service.form.enableWakeUp": "Включить пробуждение",
338 "settings.service.form.headlineAppearance": "Оформление",
327 "settings.service.form.headlineBadges": "Значки непрочитанных сообщений", 339 "settings.service.form.headlineBadges": "Значки непрочитанных сообщений",
328 "settings.service.form.headlineDarkReaderSettings": "Настройки тёмного чтения", 340 "settings.service.form.headlineDarkReaderSettings": "Настройки тёмного чтения",
329 "settings.service.form.headlineGeneral": "Общие", 341 "settings.service.form.headlineGeneral": "Общие",
@@ -440,6 +452,7 @@
440 "validation.minLength": "Кількість символів в {field} повина бути не меньше {length}", 452 "validation.minLength": "Кількість символів в {field} повина бути не меньше {length}",
441 "validation.oneRequired": "Необходим как минимум один", 453 "validation.oneRequired": "Необходим как минимум один",
442 "validation.required": "{field} необходимо", 454 "validation.required": "{field} необходимо",
455 "validation.url": "{field} не является действительным URL",
443 "webControls.back": "Назад", 456 "webControls.back": "Назад",
444 "webControls.forward": "Переслать", 457 "webControls.forward": "Переслать",
445 "webControls.goHome": "Домой", 458 "webControls.goHome": "Домой",
diff --git a/src/index.ts b/src/index.ts
index cccf0ef66..a602c994e 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -245,6 +245,18 @@ const createWindow = () => {
245 openExternalUrl(url); 245 openExternalUrl(url);
246 return { action: 'deny' }; 246 return { action: 'deny' };
247 }); 247 });
248
249 // Handle will download event from main process (prevent download dialog)
250 contents.session.on('will-download', (_e, item) => {
251 const downloadFolderPath = retrieveSettingValue(
252 'downloadFolderPath',
253 DEFAULT_APP_SETTINGS.downloadFolderPath,
254 ) as string;
255
256 if (downloadFolderPath !== '') {
257 item.setSavePath(join(downloadFolderPath, item.getFilename()));
258 }
259 });
248 } 260 }
249 }); 261 });
250 262
@@ -393,7 +405,8 @@ const createWindow = () => {
393 }); 405 });
394 406
395 if (isMac) { 407 if (isMac) {
396 import('./electron/macOSPermissions').then(macOSPermissions => { 408 // Note: Do not remove the extension. See https://github.com/ferdium/ferdium-app/issues/1755 for explanation
409 import('./electron/macOSPermissions.js').then(macOSPermissions => {
397 const { askFormacOSPermissions } = macOSPermissions; 410 const { askFormacOSPermissions } = macOSPermissions;
398 411
399 setTimeout(() => askFormacOSPermissions(mainWindow!), ms('30s')); 412 setTimeout(() => askFormacOSPermissions(mainWindow!), ms('30s'));
@@ -782,3 +795,15 @@ app.on(
782 callback(checkIfCertIsPresent(certificate.data)); 795 callback(checkIfCertIsPresent(certificate.data));
783 }, 796 },
784); 797);
798
799ipcMain.on('relaunch-app', async (_, options) => {
800 // Ask user to confirm
801 const result = await dialog.showMessageBox(mainWindow!, options);
802
803 if (result.response === options.cancelId) {
804 return;
805 }
806
807 app.relaunch();
808 app.quit();
809});
diff --git a/src/jsUtils.ts b/src/jsUtils.ts
index 0befb8d56..145875cfa 100644
--- a/src/jsUtils.ts
+++ b/src/jsUtils.ts
@@ -28,12 +28,21 @@ export const safeParseInt = (text?: string | number | null) => {
28 return Math.max(adjustedNumber, 0); 28 return Math.max(adjustedNumber, 0);
29}; 29};
30 30
31export const acceleratorString = ( 31interface IAcceleratorString {
32 index: number, 32 keyCombo: string;
33 keyCombo: string, 33 index: number;
34 prefix: string = '(', 34 prefix?: string;
35 suffix: string = ')', 35 suffix?: string;
36) => (index <= 10 ? `${prefix}${keyCombo}+${index % 10}${suffix}` : ''); 36 maxIndex?: number;
37}
38export const acceleratorString = ({
39 index,
40 keyCombo,
41 prefix = '(',
42 suffix = ')',
43 maxIndex = 9,
44}: IAcceleratorString) =>
45 index <= maxIndex ? `${prefix}${keyCombo}+${index % 10}${suffix}` : '';
37 46
38export const removeNewLines = (input: string): string => 47export const removeNewLines = (input: string): string =>
39 input.replaceAll(/\r?\n|\r/g, ''); 48 input.replaceAll(/\r?\n|\r/g, '');
diff --git a/src/lib/Menu.ts b/src/lib/Menu.ts
index bb8eead3a..8fd8e0a73 100644
--- a/src/lib/Menu.ts
+++ b/src/lib/Menu.ts
@@ -496,7 +496,15 @@ function titleBarTemplateFactory(
496 }, 496 },
497 { 497 {
498 label: intl.formatMessage(menuItems.zoomIn), 498 label: intl.formatMessage(menuItems.zoomIn),
499 accelerator: `${cmdOrCtrlShortcutKey()}+plus`, 499 // TODO: Modify this logic once https://github.com/electron/electron/issues/40674 is fixed
500 // This is a workaround for the issue where the zoom in shortcut is not working
501 // This makes sure the accelerator is not registered
502 accelerator: isWindows
503 ? `${cmdOrCtrlShortcutKey()}++`
504 : `${cmdOrCtrlShortcutKey()}+Plus`,
505 registerAccelerator: !!isMac,
506 acceleratorWorksWhenHidden: !!isMac,
507 // ---------------------------
500 click() { 508 click() {
501 const activeService = getActiveService(); 509 const activeService = getActiveService();
502 if (!activeService) { 510 if (!activeService) {
@@ -1134,7 +1142,12 @@ class FranzMenu implements StoresProps {
1134 for (const [i, service] of services.allDisplayed.entries()) { 1142 for (const [i, service] of services.allDisplayed.entries()) {
1135 menu.push({ 1143 menu.push({
1136 label: this._getServiceName(service), 1144 label: this._getServiceName(service),
1137 accelerator: acceleratorString(i + 1, cmdOrCtrlShortcutKey(), '', ''), 1145 accelerator: acceleratorString({
1146 index: i + 1,
1147 keyCombo: cmdOrCtrlShortcutKey(),
1148 prefix: '',
1149 suffix: '',
1150 }),
1138 type: 'radio', 1151 type: 'radio',
1139 checked: service.isActive, 1152 checked: service.isActive,
1140 click: () => { 1153 click: () => {
diff --git a/src/models/Recipe.ts b/src/models/Recipe.ts
index 11eb1884f..87043693b 100644
--- a/src/models/Recipe.ts
+++ b/src/models/Recipe.ts
@@ -26,6 +26,7 @@ interface RecipeData {
26 message?: string; 26 message?: string;
27 allowFavoritesDelineationInUnreadCount?: boolean; 27 allowFavoritesDelineationInUnreadCount?: boolean;
28 }; 28 };
29 defaultIcon: string;
29} 30}
30 31
31export interface IRecipe { 32export interface IRecipe {
@@ -49,6 +50,7 @@ export interface IRecipe {
49 path: string; 50 path: string;
50 partition: string; 51 partition: string;
51 local: boolean; 52 local: boolean;
53 defaultIcon: string;
52 54
53 readonly overrideUserAgent?: () => string; 55 readonly overrideUserAgent?: () => string;
54 56
@@ -76,6 +78,8 @@ export default class Recipe implements IRecipe {
76 78
77 version = ''; 79 version = '';
78 80
81 defaultIcon = '';
82
79 // Removing this specific type will cause a typescript error 83 // Removing this specific type will cause a typescript error
80 // even while it's the exact same as the interface 84 // even while it's the exact same as the interface
81 aliases: string[] = []; 85 aliases: string[] = [];
@@ -135,6 +139,7 @@ export default class Recipe implements IRecipe {
135 // from the recipe 139 // from the recipe
136 this.id = ifUndefined<string>(data.id, this.id); 140 this.id = ifUndefined<string>(data.id, this.id);
137 this.name = ifUndefined<string>(data.name, this.name); 141 this.name = ifUndefined<string>(data.name, this.name);
142 this.defaultIcon = ifUndefined<string>(data.defaultIcon, this.defaultIcon);
138 this.version = ifUndefined<string>(data.version, this.version); 143 this.version = ifUndefined<string>(data.version, this.version);
139 this.aliases = ifUndefined<string[]>(data.aliases, this.aliases); 144 this.aliases = ifUndefined<string[]>(data.aliases, this.aliases);
140 this.serviceURL = ifUndefined<string>( 145 this.serviceURL = ifUndefined<string>(
diff --git a/src/models/Service.ts b/src/models/Service.ts
index 525661172..ae04b8b58 100644
--- a/src/models/Service.ts
+++ b/src/models/Service.ts
@@ -7,6 +7,7 @@ import type ElectronWebView from 'react-electron-web-view';
7import { v4 as uuidV4 } from 'uuid'; 7import { v4 as uuidV4 } from 'uuid';
8import { needsToken } from '../api/apiBase'; 8import { needsToken } from '../api/apiBase';
9import { DEFAULT_SERVICE_ORDER, DEFAULT_SERVICE_SETTINGS } from '../config'; 9import { DEFAULT_SERVICE_ORDER, DEFAULT_SERVICE_SETTINGS } from '../config';
10import { isMac } from '../environment';
10import { todosStore } from '../features/todos'; 11import { todosStore } from '../features/todos';
11import { getFaviconUrl } from '../helpers/favicon-helpers'; 12import { getFaviconUrl } from '../helpers/favicon-helpers';
12import { isValidExternalURL, normalizedUrl } from '../helpers/url-helpers'; 13import { isValidExternalURL, normalizedUrl } from '../helpers/url-helpers';
@@ -377,6 +378,10 @@ export default class Service {
377 return this.iconUrl; 378 return this.iconUrl;
378 } 379 }
379 380
381 if (this.recipe.defaultIcon) {
382 return this.recipe.defaultIcon;
383 }
384
380 return join(this.recipe.path, 'icon.svg'); 385 return join(this.recipe.path, 'icon.svg');
381 } 386 }
382 387
@@ -532,6 +537,18 @@ export default class Service {
532 }); 537 });
533 538
534 if (webviewWebContents) { 539 if (webviewWebContents) {
540 // TODO: Modify this logic once https://github.com/electron/electron/issues/40674 is fixed
541 // This is a workaround for the issue where the zoom in shortcut is not working
542 if (!isMac) {
543 webviewWebContents.on('before-input-event', (event, input) => {
544 if (input.control && input.key === '+' && input.type === 'keyDown') {
545 event.preventDefault();
546 const currentZoom = this.webview?.getZoomLevel();
547 this.webview?.setZoomLevel(currentZoom + 0.5);
548 }
549 });
550 }
551
535 webviewWebContents.session.on('will-download', (event, item) => { 552 webviewWebContents.session.on('will-download', (event, item) => {
536 event.preventDefault(); 553 event.preventDefault();
537 554
diff --git a/src/stores/ServicesStore.ts b/src/stores/ServicesStore.ts
index 9f2cfeca3..58c6b2a87 100644
--- a/src/stores/ServicesStore.ts
+++ b/src/stores/ServicesStore.ts
@@ -917,12 +917,13 @@ export default class ServicesStore extends TypedStore {
917 917
918 if (service.isNotificationEnabled) { 918 if (service.isNotificationEnabled) {
919 let title: string; 919 let title: string;
920 options.icon = service.iconUrl;
921 if (this.stores.settings.all.app.privateNotifications === true) { 920 if (this.stores.settings.all.app.privateNotifications === true) {
922 // Remove message data from notification in private mode 921 // Remove message data from notification in private mode
923 options.body = ''; 922 options.body = '';
923 options.icon = service.icon;
924 title = `Notification from ${service.name}`; 924 title = `Notification from ${service.name}`;
925 } else { 925 } else {
926 options.icon = options.icon || service.icon;
926 options.body = typeof options.body === 'string' ? options.body : ''; 927 options.body = typeof options.body === 'string' ? options.body : '';
927 title = 928 title =
928 typeof args[0].title === 'string' ? args[0].title : service.name; 929 typeof args[0].title === 'string' ? args[0].title : service.name;
diff --git a/src/webview/contextMenuBuilder.ts b/src/webview/contextMenuBuilder.ts
index 0a8b9c57b..d92e18aa9 100644
--- a/src/webview/contextMenuBuilder.ts
+++ b/src/webview/contextMenuBuilder.ts
@@ -130,8 +130,8 @@ interface ContextMenuStringTable {
130 translatorLanguage: string; 130 translatorLanguage: string;
131 }) => string; 131 }) => string;
132 openLinkUrl: () => string; 132 openLinkUrl: () => string;
133 openLinkInFerdiumUrl: () => string;
134 openInBrowser: () => string; 133 openInBrowser: () => string;
134 openInFerdium: () => string;
135 copyLinkUrl: () => string; 135 copyLinkUrl: () => string;
136 copyImageUrl: () => string; 136 copyImageUrl: () => string;
137 copyImage: () => string; 137 copyImage: () => string;
@@ -158,8 +158,8 @@ const contextMenuStringTable: ContextMenuStringTable = {
158 `Translate to ${translatorLanguage}`, 158 `Translate to ${translatorLanguage}`,
159 translateLanguage: ({ translatorLanguage }) => `${translatorLanguage}`, 159 translateLanguage: ({ translatorLanguage }) => `${translatorLanguage}`,
160 openLinkUrl: () => 'Open Link', 160 openLinkUrl: () => 'Open Link',
161 openLinkInFerdiumUrl: () => 'Open Link in Ferdium',
162 openInBrowser: () => 'Open in Browser', 161 openInBrowser: () => 'Open in Browser',
162 openInFerdium: () => 'Open in Ferdium',
163 copyLinkUrl: () => 'Copy Link', 163 copyLinkUrl: () => 'Copy Link',
164 copyImageUrl: () => 'Copy Image Address', 164 copyImageUrl: () => 'Copy Image Address',
165 copyImage: () => 'Copy Image', 165 copyImage: () => 'Copy Image',
@@ -299,10 +299,13 @@ export class ContextMenuBuilder {
299 this.addPastePlain(menu, menuInfo); 299 this.addPastePlain(menu, menuInfo);
300 this.addInspectElement(menu, menuInfo); 300 this.addInspectElement(menu, menuInfo);
301 this.processMenu(menu); 301 this.processMenu(menu);
302 302 this.addSeparator(menu);
303 this.copyPageUrl(menu, menuInfo); 303 this.copyPageUrl(menu, menuInfo);
304 this.goToHomePage(menu, menuInfo); 304 this.addSeparator(menu);
305 this.openInBrowser(menu, menuInfo); 305 this.openInBrowser(menu, menuInfo);
306 this.openInFerdium(menu, menuInfo);
307 this.addSeparator(menu);
308 this.goToHomePage(menu, menuInfo);
306 309
307 return menu; 310 return menu;
308 } 311 }
@@ -340,16 +343,8 @@ export class ContextMenuBuilder {
340 }, 343 },
341 }); 344 });
342 345
343 const openInFerdiumLink = new MenuItem({
344 label: this.stringTable.openLinkInFerdiumUrl(),
345 click: () => {
346 window.location.href = menuInfo.linkURL;
347 },
348 });
349
350 menu.append(copyLink); 346 menu.append(copyLink);
351 menu.append(openLink); 347 menu.append(openLink);
352 menu.append(openInFerdiumLink);
353 348
354 if (this.isSrcUrlValid(menuInfo)) { 349 if (this.isSrcUrlValid(menuInfo)) {
355 this.addSeparator(menu); 350 this.addSeparator(menu);
@@ -358,13 +353,15 @@ export class ContextMenuBuilder {
358 353
359 this.addInspectElement(menu, menuInfo); 354 this.addInspectElement(menu, menuInfo);
360 this.processMenu(menu); 355 this.processMenu(menu);
361
362 this.addSeparator(menu); 356 this.addSeparator(menu);
363 this.goBack(menu); 357 this.goBack(menu);
364 this.goForward(menu); 358 this.goForward(menu);
365 this.copyPageUrl(menu, menuInfo); 359 this.copyPageUrl(menu, menuInfo);
366 this.goToHomePage(menu, menuInfo); 360 this.addSeparator(menu);
367 this.openInBrowser(menu, menuInfo); 361 this.openInBrowser(menu, menuInfo);
362 this.openInFerdium(menu, menuInfo);
363 this.addSeparator(menu);
364 this.goToHomePage(menu, menuInfo);
368 365
369 return menu; 366 return menu;
370 } 367 }
@@ -384,16 +381,19 @@ export class ContextMenuBuilder {
384 this.addTranslateItems(menu, menuInfo); 381 this.addTranslateItems(menu, menuInfo);
385 } 382 }
386 this.addCopy(menu, menuInfo); 383 this.addCopy(menu, menuInfo);
387 this.addInspectElement(menu, menuInfo);
388 // @ts-expect-error Expected 1 arguments, but got 2.
389 this.processMenu(menu, menuInfo);
390 384
385 this.addInspectElement(menu, menuInfo);
386 this.processMenu(menu);
391 this.addSeparator(menu); 387 this.addSeparator(menu);
392 this.goBack(menu); 388 this.goBack(menu);
393 this.goForward(menu); 389 this.goForward(menu);
390 this.addSeparator(menu);
394 this.copyPageUrl(menu, menuInfo); 391 this.copyPageUrl(menu, menuInfo);
395 this.goToHomePage(menu, menuInfo); 392 this.addSeparator(menu);
396 this.openInBrowser(menu, menuInfo); 393 this.openInBrowser(menu, menuInfo);
394 this.openInFerdium(menu, menuInfo);
395 this.addSeparator(menu);
396 this.goToHomePage(menu, menuInfo);
397 397
398 return menu; 398 return menu;
399 } 399 }
@@ -412,8 +412,7 @@ export class ContextMenuBuilder {
412 this.addImageItems(menu, menuInfo); 412 this.addImageItems(menu, menuInfo);
413 } 413 }
414 this.addInspectElement(menu, menuInfo); 414 this.addInspectElement(menu, menuInfo);
415 // @ts-expect-error Expected 1 arguments, but got 2. 415 this.processMenu(menu);
416 this.processMenu(menu, menuInfo);
417 416
418 return menu; 417 return menu;
419 } 418 }
@@ -970,6 +969,26 @@ export class ContextMenuBuilder {
970 return menu; 969 return menu;
971 } 970 }
972 971
972 /**
973 * Adds the 'open in ferdium' menu item.
974 */
975 openInFerdium(
976 menu: Electron.CrossProcessExports.Menu,
977 menuInfo: IContextMenuParams,
978 ) {
979 menu.append(
980 new MenuItem({
981 label: this.stringTable.openInFerdium(),
982 enabled: true,
983 click: () => {
984 window.location.href = menuInfo.linkURL;
985 },
986 }),
987 );
988
989 return menu;
990 }
991
973 _sendNotificationOnClipboardEvent( 992 _sendNotificationOnClipboardEvent(
974 isDisabled: boolean, 993 isDisabled: boolean,
975 notificationText: () => string, 994 notificationText: () => string,
diff --git a/src/webview/notifications.ts b/src/webview/notifications.ts
index e4401ab6e..0da86fbba 100644
--- a/src/webview/notifications.ts
+++ b/src/webview/notifications.ts
@@ -31,52 +31,51 @@ export class NotificationsHandler {
31} 31}
32 32
33export const notificationsClassDefinition = `(() => { 33export const notificationsClassDefinition = `(() => {
34 class Notification { 34class Notification {
35 static permission = 'granted'; 35 static permission = 'granted';
36
37 constructor(title = '', options = {}) {
38 this.title = title;
39 this.options = options;
40 try {
41 window.ferdium.displayNotification(title, options)
42 .then(() => {
43 if (typeof (this.onClick) === 'function') {
44 this.onClick();
45 }
46 });
47 } catch(error) {
48 this.options.onClick = null;
49 window.ferdium.displayNotification(title, options)
50 .then(() => {
51 if (typeof (this.onClick) === 'function') {
52 this.onClick();
53 }
54 });
55 }
56 }
57 36
58 static requestPermission(cb = null) { 37 static _notification;
59 if (!cb) {
60 return new Promise((resolve) => {
61 resolve(Notification.permission);
62 });
63 }
64 38
65 if (typeof (cb) === 'function') { 39 constructor(title = '', options = {}) {
66 return cb(Notification.permission); 40 Notification._displayNotification(title, options);
67 } 41 }
68 42
69 return Notification.permission; 43 static _displayNotification(title, options) {
70 } 44 Notification._notification = window.ferdium
45 .displayNotification(title, options)
46 .then(() => {
47 // TODO: After several tries, we couldn't find a way to trigger the native notification onclick event.
48 // This was needed so that user could go to the specific context when clicking on the notification (it only goes to the service now).
49 // For now, we don't do anything here
50 });
51 }
71 52
72 onNotify(data) { 53 static requestPermission(cb) {
73 return data; 54 if (typeof cb === 'function') {
55 cb(Notification.permission);
74 } 56 }
75 57
76 onClick() {} 58 return Promise.resolve(Notification.permission);
59 }
60
61 onNotify(data) {
62 return data;
63 }
77 64
78 close() {} 65 close() {
66 if (Notification._notification) {
67 Notification._notification = null;
68 }
79 } 69 }
80 70
71 onclick() {}
72
73 onclose() {}
74
75 onerror() {}
76
77 onshow() {}
78}
79
81 window.Notification = Notification; 80 window.Notification = Notification;
82})();`; 81})();`;
diff --git a/src/webview/recipe.ts b/src/webview/recipe.ts
index a35a99699..ad2215ffd 100644
--- a/src/webview/recipe.ts
+++ b/src/webview/recipe.ts
@@ -121,7 +121,7 @@ contextBridge.exposeInMainWorld('ferdium', {
121 setDialogTitle: (title: string | null | undefined) => 121 setDialogTitle: (title: string | null | undefined) =>
122 dialogTitleHandler.setDialogTitle(title), 122 dialogTitleHandler.setDialogTitle(title),
123 displayNotification: (title: string, options: any) => { 123 displayNotification: (title: string, options: any) => {
124 notificationsHandler.displayNotification( 124 return notificationsHandler.displayNotification(
125 title, 125 title,
126 // The following line is needed so that a proper clone of the "options" object is made. 126 // The following line is needed so that a proper clone of the "options" object is made.
127 // This line was causing issues with some services. 127 // This line was causing issues with some services.
diff --git a/test/jsUtils.test.ts b/test/jsUtils.test.ts
index 508f5dd9f..b40b21b2a 100644
--- a/test/jsUtils.test.ts
+++ b/test/jsUtils.test.ts
@@ -180,23 +180,59 @@ describe('jsUtils', () => {
180 180
181 describe('acceleratorString', () => { 181 describe('acceleratorString', () => {
182 it('handles without prefix and suffix', () => { 182 it('handles without prefix and suffix', () => {
183 expect(jsUtils.acceleratorString(5, 'abc')).toEqual('(abc+5)'); 183 expect(
184 jsUtils.acceleratorString({
185 index: 5,
186 keyCombo: 'abc',
187 }),
188 ).toEqual('(abc+5)');
184 }); 189 });
185 190
186 it('handles index = 0', () => { 191 it('handles index = 0', () => {
187 expect(jsUtils.acceleratorString(0, 'abc')).toEqual('(abc+0)'); 192 expect(
193 jsUtils.acceleratorString({
194 index: 0,
195 keyCombo: 'abc',
196 }),
197 ).toEqual('(abc+0)');
188 }); 198 });
189 199
190 it('handles index = 1', () => { 200 it('handles index = 1', () => {
191 expect(jsUtils.acceleratorString(1, 'abc')).toEqual('(abc+1)'); 201 expect(
202 jsUtils.acceleratorString({
203 index: 1,
204 keyCombo: 'abc',
205 }),
206 ).toEqual('(abc+1)');
192 }); 207 });
193 208
194 it('handles index = 10', () => { 209 it('handles index = 10', () => {
195 expect(jsUtils.acceleratorString(10, 'abc')).toEqual('(abc+0)'); 210 expect(
211 jsUtils.acceleratorString({
212 index: 10,
213 keyCombo: 'abc',
214 maxIndex: 10,
215 }),
216 ).toEqual('(abc+0)');
196 }); 217 });
197 218
198 it('handles index = 11', () => { 219 it('handles index = 11', () => {
199 expect(jsUtils.acceleratorString(11, 'abc')).toEqual(''); 220 expect(
221 jsUtils.acceleratorString({
222 index: 11,
223 keyCombo: 'abc',
224 }),
225 ).toEqual('');
226 });
227
228 it('handles index = 9, maxIndex = 8', () => {
229 expect(
230 jsUtils.acceleratorString({
231 index: 9,
232 maxIndex: 8,
233 keyCombo: 'abc',
234 }),
235 ).toEqual('');
200 }); 236 });
201 }); 237 });
202 238