aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/@types/stores.types.ts11
-rw-r--r--src/api/UserApi.ts4
-rw-r--r--src/api/server/ServerApi.ts36
-rw-r--r--src/components/layout/Sidebar.tsx2
-rw-r--r--src/components/settings/account/AccountDashboard.tsx8
-rw-r--r--src/components/settings/settings/EditSettingsForm.tsx100
-rw-r--r--src/components/settings/team/TeamDashboard.tsx4
-rw-r--r--src/components/ui/InfoBar.tsx7
-rw-r--r--src/components/ui/Infobox.tsx7
-rw-r--r--src/components/ui/button/index.tsx3
-rw-r--r--src/components/ui/loader/index.tsx5
-rw-r--r--src/config.ts23
-rw-r--r--src/containers/settings/EditServiceScreen.tsx4
-rw-r--r--src/containers/settings/EditSettingsScreen.tsx67
-rw-r--r--src/containers/settings/RecipesScreen.tsx4
-rw-r--r--src/environment-remote.ts11
-rw-r--r--src/features/workspaces/components/WorkspaceSwitchingIndicator.tsx3
-rw-r--r--src/features/workspaces/store.ts5
-rw-r--r--src/helpers/certs-helpers.ts22
-rw-r--r--src/i18n/locales/de.json7
-rw-r--r--src/i18n/locales/en-US.json7
-rw-r--r--src/i18n/locales/id.json40
-rw-r--r--src/i18n/locales/ja.json1
-rw-r--r--src/i18n/locales/ru.json28
-rw-r--r--src/i18n/locales/zh-HANS.json7
-rw-r--r--src/index.ts24
-rw-r--r--src/jsUtils.ts3
-rw-r--r--src/lib/Menu.ts4
-rw-r--r--src/lib/Tray.ts2
-rw-r--r--src/lib/dbus/Ferdium.ts8
-rw-r--r--src/models/Service.ts4
-rw-r--r--src/models/User.ts2
-rw-r--r--src/stores/AppStore.ts6
-rw-r--r--src/stores/ServicesStore.ts58
-rw-r--r--src/stores/SettingsStore.ts10
-rw-r--r--src/stores/UserStore.ts27
-rw-r--r--src/stores/lib/Request.ts9
-rw-r--r--src/themes/default/index.ts3
-rw-r--r--src/webview/lib/RecipeWebview.ts6
-rw-r--r--src/webview/notifications.ts4
-rw-r--r--src/webview/recipe.ts17
41 files changed, 440 insertions, 163 deletions
diff --git a/src/@types/stores.types.ts b/src/@types/stores.types.ts
index 973889802..c2d7bd78a 100644
--- a/src/@types/stores.types.ts
+++ b/src/@types/stores.types.ts
@@ -87,12 +87,14 @@ export interface AppStore extends TypedStore {
87 authRequestFailed: () => void; 87 authRequestFailed: () => void;
88 autoLaunchOnStart: () => void; 88 autoLaunchOnStart: () => void;
89 automaticUpdates: boolean; 89 automaticUpdates: boolean;
90 isTwoFactorAutoCatcherEnabled: boolean;
91 twoFactorAutoCatcherMatcher: string;
90 clearAppCacheRequest: () => void; 92 clearAppCacheRequest: () => void;
91 clipboardNotifications: boolean; 93 clipboardNotifications: boolean;
92 darkMode: boolean; 94 darkMode: boolean;
93 dictionaries: [];
94 enableSpellchecking: boolean; 95 enableSpellchecking: boolean;
95 enableTranslator: boolean; 96 enableTranslator: boolean;
97 useSelfSignedCertificates: boolean;
96 fetchDataInterval: 4; 98 fetchDataInterval: 4;
97 get(key: string): any; 99 get(key: string): any;
98 getAppCacheSizeRequest: () => void; 100 getAppCacheSizeRequest: () => void;
@@ -234,7 +236,6 @@ interface SettingsStore extends TypedStore {
234 remove: (value: any) => void; 236 remove: (value: any) => void;
235 fileSystemSettingsTypes: any[]; 237 fileSystemSettingsTypes: any[];
236 loaded: boolean; 238 loaded: boolean;
237 updateAppSettingsRequest: () => void;
238 _fileSystemSettingsCache: () => void; 239 _fileSystemSettingsCache: () => void;
239 all: ISettings; 240 all: ISettings;
240 app: AppStore; 241 app: AppStore;
@@ -304,7 +305,6 @@ interface UserStore extends TypedStore {
304 accountType: () => void; 305 accountType: () => void;
305 authToken: () => void; 306 authToken: () => void;
306 deleteAccountRequest: () => void; 307 deleteAccountRequest: () => void;
307 fetchUserInfoInterval: null;
308 getLegacyServicesRequest: () => void; 308 getLegacyServicesRequest: () => void;
309 getUserInfoRequest: CachedRequest; 309 getUserInfoRequest: CachedRequest;
310 hasCompletedSignup: () => void; 310 hasCompletedSignup: () => void;
@@ -327,15 +327,10 @@ interface UserStore extends TypedStore {
327 _retrievePassword: () => void; 327 _retrievePassword: () => void;
328 changeServerRoute: () => void; 328 changeServerRoute: () => void;
329 data: User; 329 data: User;
330 importRoute: string;
331 inviteRoute: string;
332 isLoggedIn: boolean; 330 isLoggedIn: boolean;
333 isTokenExpired: boolean; 331 isTokenExpired: boolean;
334 legacyServices: () => void;
335 loginRoute: string; 332 loginRoute: string;
336 logoutRoute: string;
337 passwordRoute: string; 333 passwordRoute: string;
338 setupRoute: string;
339 signupRoute: string; 334 signupRoute: string;
340 team: () => void; 335 team: () => void;
341} 336}
diff --git a/src/api/UserApi.ts b/src/api/UserApi.ts
index 9364b3383..38f489131 100644
--- a/src/api/UserApi.ts
+++ b/src/api/UserApi.ts
@@ -52,10 +52,6 @@ export default class UserApi {
52 return this.server.updateUserInfo(userData); 52 return this.server.updateUserInfo(userData);
53 } 53 }
54 54
55 getLegacyServices() {
56 return this.server.getLegacyServices();
57 }
58
59 delete() { 55 delete() {
60 return this.server.deleteAccount(); 56 return this.server.deleteAccount();
61 } 57 }
diff --git a/src/api/server/ServerApi.ts b/src/api/server/ServerApi.ts
index 1530dd478..9e7582e1e 100644
--- a/src/api/server/ServerApi.ts
+++ b/src/api/server/ServerApi.ts
@@ -22,7 +22,7 @@ import UserModel from '../../models/User';
22import sleep from '../../helpers/async-helpers'; 22import sleep from '../../helpers/async-helpers';
23 23
24import { SERVER_NOT_LOADED } from '../../config'; 24import { SERVER_NOT_LOADED } from '../../config';
25import { userDataRecipesPath, userDataPath } from '../../environment-remote'; 25import { userDataRecipesPath } from '../../environment-remote';
26import { asarRecipesPath } from '../../helpers/asar-helpers'; 26import { asarRecipesPath } from '../../helpers/asar-helpers';
27import apiBase from '../apiBase'; 27import apiBase from '../apiBase';
28import { 28import {
@@ -500,40 +500,6 @@ export default class ServerApi {
500 debug('ServerApi::healthCheck resolves'); 500 debug('ServerApi::healthCheck resolves');
501 } 501 }
502 502
503 async getLegacyServices() {
504 const file = userDataPath('settings', 'services.json');
505
506 try {
507 const config = readJsonSync(file);
508
509 if (Object.hasOwn(config, 'services')) {
510 const services = await Promise.all(
511 config.services.map(async (s: { service: any }) => {
512 const service = s;
513 const request = await sendAuthRequest(
514 `${apiBase()}/recipes/${s.service}`,
515 );
516
517 if (request.status === 200) {
518 const data = await request.json();
519 // @ts-expect-error Property 'recipe' does not exist on type '{ service: any; }'.
520 service.recipe = new RecipePreviewModel(data);
521 }
522
523 return service;
524 }),
525 );
526
527 debug('ServerApi::getLegacyServices resolves', services);
528 return services;
529 }
530 } catch {
531 console.error('ServerApi::getLegacyServices no config found');
532 }
533
534 return [];
535 }
536
537 // Helper 503 // Helper
538 async _mapServiceModels(services: any[]) { 504 async _mapServiceModels(services: any[]) {
539 const recipes = services.map((s: { recipeId: string }) => s.recipeId); 505 const recipes = services.map((s: { recipeId: string }) => s.recipeId);
diff --git a/src/components/layout/Sidebar.tsx b/src/components/layout/Sidebar.tsx
index e423e408b..1106113f0 100644
--- a/src/components/layout/Sidebar.tsx
+++ b/src/components/layout/Sidebar.tsx
@@ -318,7 +318,7 @@ class Sidebar extends Component<IProps, IState> {
318 <Icon icon={mdiCheckAll} size={1.5} /> 318 <Icon icon={mdiCheckAll} size={1.5} />
319 </button> 319 </button>
320 ) : null} 320 ) : null}
321 {stores!.settings.all.app.lockingFeatureEnabled ? ( 321 {stores!.settings.all.app.isLockingFeatureEnabled ? (
322 <button 322 <button
323 type="button" 323 type="button"
324 className="sidebar__button" 324 className="sidebar__button"
diff --git a/src/components/settings/account/AccountDashboard.tsx b/src/components/settings/account/AccountDashboard.tsx
index ffa684458..eab019084 100644
--- a/src/components/settings/account/AccountDashboard.tsx
+++ b/src/components/settings/account/AccountDashboard.tsx
@@ -7,7 +7,11 @@ import { H1, H2 } from '../../ui/headline';
7import Loader from '../../ui/loader'; 7import Loader from '../../ui/loader';
8import Button from '../../ui/button'; 8import Button from '../../ui/button';
9import Infobox from '../../ui/infobox/index'; 9import Infobox from '../../ui/infobox/index';
10import { LOCAL_SERVER, LIVE_FRANZ_API } from '../../../config'; 10import {
11 DEFAULT_LOADER_COLOR,
12 LOCAL_SERVER,
13 LIVE_FRANZ_API,
14} from '../../../config';
11import User from '../../../models/User'; 15import User from '../../../models/User';
12 16
13const messages = defineMessages({ 17const messages = defineMessages({
@@ -123,7 +127,7 @@ class AccountDashboard extends Component<IProp> {
123 )} 127 )}
124 {!isUsingWithoutAccount && ( 128 {!isUsingWithoutAccount && (
125 <> 129 <>
126 {isLoading && <Loader color="#FFFFFF" />} 130 {isLoading && <Loader color={DEFAULT_LOADER_COLOR} />}
127 131
128 {!isLoading && userInfoRequestFailed && ( 132 {!isLoading && userInfoRequestFailed && (
129 <Infobox 133 <Infobox
diff --git a/src/components/settings/settings/EditSettingsForm.tsx b/src/components/settings/settings/EditSettingsForm.tsx
index 1672a1411..81cfe8b12 100644
--- a/src/components/settings/settings/EditSettingsForm.tsx
+++ b/src/components/settings/settings/EditSettingsForm.tsx
@@ -15,6 +15,7 @@ import Infobox from '../../ui/Infobox';
15import { H1, H2, H3, H5 } from '../../ui/headline'; 15import { H1, H2, H3, H5 } from '../../ui/headline';
16import { 16import {
17 ferdiumVersion, 17 ferdiumVersion,
18 userDataCertsPath,
18 userDataPath, 19 userDataPath,
19 userDataRecipesPath, 20 userDataRecipesPath,
20} from '../../../environment-remote'; 21} from '../../../environment-remote';
@@ -238,6 +239,10 @@ const messages = defineMessages({
238 id: 'settings.app.updateStatusUpToDate', 239 id: 'settings.app.updateStatusUpToDate',
239 defaultMessage: 'You are using the latest version of Ferdium', 240 defaultMessage: 'You are using the latest version of Ferdium',
240 }, 241 },
242 servicesUpdateStatusUpToDate: {
243 id: 'settings.app.servicesUpdateStatusUpToDate',
244 defaultMessage: 'Your services are up-to-date',
245 },
241 currentVersion: { 246 currentVersion: {
242 id: 'settings.app.currentVersion', 247 id: 'settings.app.currentVersion',
243 defaultMessage: 'Current version:', 248 defaultMessage: 'Current version:',
@@ -258,6 +263,20 @@ const messages = defineMessages({
258 id: 'settings.app.form.splitColumns', 263 id: 'settings.app.form.splitColumns',
259 defaultMessage: 'Number of columns', 264 defaultMessage: 'Number of columns',
260 }, 265 },
266 warningSelfSignedCertificates: {
267 id: 'settings.app.warningSelfSignedCertificates',
268 defaultMessage:
269 'WARNING: Only enable this feature if you know what you are doing. Enabling this is a security risk and should only be used for testing purposes.',
270 },
271 infoOpenCertificatesFolder: {
272 id: 'settings.app.infoOpenCertificatesFolder',
273 defaultMessage:
274 'To install a certificate, click the button below to open the certificates folder and copy it into the folder. After that you can refresh the service (CTRL/CMD + R). To remove/uninstall, simply delete the certificate file and restart Ferdium.',
275 },
276 buttonOpenFerdiumCertsFolder: {
277 id: 'settings.app.buttonOpenFerdiumCertsFolder',
278 defaultMessage: 'Open certificates folder',
279 },
261}); 280});
262 281
263const Hr = (): ReactElement => ( 282const Hr = (): ReactElement => (
@@ -284,10 +303,12 @@ interface IProps extends WrappedComponentProps {
284 isClearingAllCache: boolean; 303 isClearingAllCache: boolean;
285 isTodosActivated: boolean; 304 isTodosActivated: boolean;
286 automaticUpdates: boolean; 305 automaticUpdates: boolean;
306 isTwoFactorAutoCatcherEnabled: boolean;
307 twoFactorAutoCatcherMatcher: string;
287 isDarkmodeEnabled: boolean; 308 isDarkmodeEnabled: boolean;
288 isAdaptableDarkModeEnabled: boolean; 309 isAdaptableDarkModeEnabled: boolean;
289 isUseGrayscaleServicesEnabled: boolean; 310 isUseGrayscaleServicesEnabled: boolean;
290 lockingFeatureEnabled: boolean; 311 isLockingFeatureEnabled: boolean;
291 isSplitModeEnabled: boolean; 312 isSplitModeEnabled: boolean;
292 isOnline: boolean; 313 isOnline: boolean;
293 showServicesUpdatedInfoBar: boolean; 314 showServicesUpdatedInfoBar: boolean;
@@ -335,7 +356,8 @@ class EditSettingsForm extends Component<IProps, IState> {
335 this.props.form.submit({ 356 this.props.form.submit({
336 onSuccess: (form: Form) => { 357 onSuccess: (form: Form) => {
337 const values = form.values(); 358 const values = form.values();
338 const { accentColor } = values; 359 const { accentColor, isTwoFactorAutoCatcherEnabled } = values;
360
339 if (accentColor.trim().length === 0) { 361 if (accentColor.trim().length === 0) {
340 values.accentColor = DEFAULT_ACCENT_COLOR; 362 values.accentColor = DEFAULT_ACCENT_COLOR;
341 } 363 }
@@ -343,6 +365,15 @@ class EditSettingsForm extends Component<IProps, IState> {
343 if (progressbarAccentColor.trim().length === 0) { 365 if (progressbarAccentColor.trim().length === 0) {
344 values.progressbarAccentColor = DEFAULT_ACCENT_COLOR; 366 values.progressbarAccentColor = DEFAULT_ACCENT_COLOR;
345 } 367 }
368
369 // set twoFactorAutoCatcherMatcher to the default value, if its get enabled the input is prefilled
370 if (
371 !isTwoFactorAutoCatcherEnabled &&
372 values.twoFactorAutoCatcherMatcher.length === 0
373 ) {
374 values.twoFactorAutoCatcherMatcher =
375 DEFAULT_APP_SETTINGS.twoFactorAutoCatcherMatcher;
376 }
346 this.props.onSubmit(values); 377 this.props.onSubmit(values);
347 }, 378 },
348 onError: noop, 379 onError: noop,
@@ -367,6 +398,7 @@ class EditSettingsForm extends Component<IProps, IState> {
367 onClearAllCache, 398 onClearAllCache,
368 getCacheSize, 399 getCacheSize,
369 automaticUpdates, 400 automaticUpdates,
401 isTwoFactorAutoCatcherEnabled,
370 isDarkmodeEnabled, 402 isDarkmodeEnabled,
371 isSplitModeEnabled, 403 isSplitModeEnabled,
372 openProcessManager, 404 openProcessManager,
@@ -383,8 +415,12 @@ class EditSettingsForm extends Component<IProps, IState> {
383 updateButtonLabelMessage = messages.updateStatusAvailable; 415 updateButtonLabelMessage = messages.updateStatusAvailable;
384 } 416 }
385 417
386 const { lockingFeatureEnabled, scheduledDNDEnabled, reloadAfterResume } = 418 const {
387 window['ferdium'].stores.settings.all.app; 419 isLockingFeatureEnabled,
420 scheduledDNDEnabled,
421 reloadAfterResume,
422 useSelfSignedCertificates,
423 } = window['ferdium'].stores.settings.all.app;
388 424
389 let cacheSize; 425 let cacheSize;
390 let notCleared; 426 let notCleared;
@@ -407,6 +443,7 @@ class EditSettingsForm extends Component<IProps, IState> {
407 443
408 const profileFolder = userDataPath(); 444 const profileFolder = userDataPath();
409 const recipeFolder = userDataRecipesPath(); 445 const recipeFolder = userDataRecipesPath();
446 const certsFolder = userDataCertsPath();
410 447
411 return ( 448 return (
412 <div className="settings__main"> 449 <div className="settings__main">
@@ -813,6 +850,15 @@ class EditSettingsForm extends Component<IProps, IState> {
813 <Toggle {...form.$('notifyTaskBarOnMessage').bind()} /> 850 <Toggle {...form.$('notifyTaskBarOnMessage').bind()} />
814 )} 851 )}
815 852
853 <Toggle {...form.$('isTwoFactorAutoCatcherEnabled').bind()} />
854
855 {isTwoFactorAutoCatcherEnabled && (
856 <Input
857 onChange={e => this.submit(e)}
858 {...form.$('twoFactorAutoCatcherMatcher').bind()}
859 />
860 )}
861
816 <Hr /> 862 <Hr />
817 863
818 <Select field={form.$('webRTCIPHandlingPolicy')} /> 864 <Select field={form.$('webRTCIPHandlingPolicy')} />
@@ -836,8 +882,8 @@ class EditSettingsForm extends Component<IProps, IState> {
836 882
837 <Hr /> 883 <Hr />
838 884
839 <Toggle {...form.$('lockingFeatureEnabled').bind()} /> 885 <Toggle {...form.$('isLockingFeatureEnabled').bind()} />
840 {lockingFeatureEnabled && ( 886 {isLockingFeatureEnabled && (
841 <> 887 <>
842 {isMac && systemPreferences.canPromptTouchID() && ( 888 {isMac && systemPreferences.canPromptTouchID() && (
843 <Toggle {...form.$('useTouchIdToUnlock').bind()} /> 889 <Toggle {...form.$('useTouchIdToUnlock').bind()} />
@@ -943,6 +989,43 @@ class EditSettingsForm extends Component<IProps, IState> {
943 {intl.formatMessage(messages.appRestartRequired)} 989 {intl.formatMessage(messages.appRestartRequired)}
944 </p> 990 </p>
945 991
992 <Toggle {...form.$('useSelfSignedCertificates').bind()} />
993
994 {useSelfSignedCertificates && (
995 <div className="settings__settings-group">
996 <p
997 style={{
998 padding: '0rem 0rem 1rem 0rem',
999 textAlign: 'justify',
1000 fontSize: '1.1rem',
1001 }}
1002 >
1003 {intl.formatMessage(messages.infoOpenCertificatesFolder)}
1004 </p>
1005 <div className="settings__open-settings-cache-container">
1006 <Button
1007 buttonType="secondary"
1008 label={intl.formatMessage(
1009 messages.buttonOpenFerdiumCertsFolder,
1010 )}
1011 className="settings__open-settings-file-button"
1012 onClick={() => openPath(certsFolder)}
1013 />
1014 </div>
1015 </div>
1016 )}
1017
1018 <p
1019 className="settings__help"
1020 style={{
1021 padding: useSelfSignedCertificates
1022 ? '1rem 0rem 0rem 0rem'
1023 : undefined,
1024 }}
1025 >
1026 {intl.formatMessage(messages.warningSelfSignedCertificates)}
1027 </p>
1028
946 <Hr /> 1029 <Hr />
947 1030
948 <Input 1031 <Input
@@ -1117,7 +1200,10 @@ class EditSettingsForm extends Component<IProps, IState> {
1117 ) : ( 1200 ) : (
1118 <p> 1201 <p>
1119 <Icon icon={mdiPowerPlug} /> 1202 <Icon icon={mdiPowerPlug} />
1120 &nbsp;Your services are up-to-date. 1203 &nbsp;
1204 {intl.formatMessage(
1205 messages.servicesUpdateStatusUpToDate,
1206 )}
1121 </p> 1207 </p>
1122 )} 1208 )}
1123 </> 1209 </>
diff --git a/src/components/settings/team/TeamDashboard.tsx b/src/components/settings/team/TeamDashboard.tsx
index 406656160..96613373e 100644
--- a/src/components/settings/team/TeamDashboard.tsx
+++ b/src/components/settings/team/TeamDashboard.tsx
@@ -10,7 +10,7 @@ import Loader from '../../ui/loader';
10import Button from '../../ui/button'; 10import Button from '../../ui/button';
11import Infobox from '../../ui/Infobox'; 11import Infobox from '../../ui/Infobox';
12import { H1 } from '../../ui/headline'; 12import { H1 } from '../../ui/headline';
13import { LIVE_FRANZ_API } from '../../../config'; 13import { DEFAULT_LOADER_COLOR, LIVE_FRANZ_API } from '../../../config';
14 14
15const messages = defineMessages({ 15const messages = defineMessages({
16 headline: { 16 headline: {
@@ -128,7 +128,7 @@ class TeamDashboard extends Component<IProps> {
128 </span> 128 </span>
129 </div> 129 </div>
130 <div className="settings__body"> 130 <div className="settings__body">
131 {isLoading && <Loader color="#FFFFFF" />} 131 {isLoading && <Loader color={DEFAULT_LOADER_COLOR} />}
132 132
133 {!isLoading && userInfoRequestFailed && ( 133 {!isLoading && userInfoRequestFailed && (
134 <Infobox 134 <Infobox
diff --git a/src/components/ui/InfoBar.tsx b/src/components/ui/InfoBar.tsx
index ae37546df..f3f1adbe7 100644
--- a/src/components/ui/InfoBar.tsx
+++ b/src/components/ui/InfoBar.tsx
@@ -8,6 +8,7 @@ import { noop } from 'lodash';
8import Loader from './loader/index'; 8import Loader from './loader/index';
9import Appear from './effects/Appear'; 9import Appear from './effects/Appear';
10import Icon from './icon'; 10import Icon from './icon';
11import { DEFAULT_LOADER_COLOR } from '../../config';
11 12
12const messages = defineMessages({ 13const messages = defineMessages({
13 hide: { 14 hide: {
@@ -71,7 +72,11 @@ class InfoBar extends Component<IProps> {
71 className="contentWrapper" 72 className="contentWrapper"
72 style={{ display: 'flex', gap: '8px' }} 73 style={{ display: 'flex', gap: '8px' }}
73 > 74 >
74 <Loader size={18} loaded={!ctaLoading} color="#FFFFFF" /> 75 <Loader
76 size={18}
77 loaded={!ctaLoading}
78 color={DEFAULT_LOADER_COLOR}
79 />
75 {ctaLabel} 80 {ctaLabel}
76 </div> 81 </div>
77 </button> 82 </button>
diff --git a/src/components/ui/Infobox.tsx b/src/components/ui/Infobox.tsx
index 742717ed7..14e1a581c 100644
--- a/src/components/ui/Infobox.tsx
+++ b/src/components/ui/Infobox.tsx
@@ -6,6 +6,7 @@ import { noop } from 'lodash';
6import { observer } from 'mobx-react'; 6import { observer } from 'mobx-react';
7import Loader from './loader/index'; 7import Loader from './loader/index';
8import Icon from './icon'; 8import Icon from './icon';
9import { DEFAULT_LOADER_COLOR } from '../../config';
9 10
10const icons = { 11const icons = {
11 'checkbox-marked-circle-outline': mdiCheckboxMarkedCircleOutline, 12 'checkbox-marked-circle-outline': mdiCheckboxMarkedCircleOutline,
@@ -84,7 +85,11 @@ class Infobox extends Component<IProps, IState> {
84 className="contentWrapper" 85 className="contentWrapper"
85 style={{ display: 'flex', gap: '8px' }} 86 style={{ display: 'flex', gap: '8px' }}
86 > 87 >
87 <Loader size={18} loaded={!ctaLoading} color="#FFFFFF" /> 88 <Loader
89 size={18}
90 loaded={!ctaLoading}
91 color={DEFAULT_LOADER_COLOR}
92 />
88 {ctaLabel} 93 {ctaLabel}
89 </div> 94 </div>
90 </button> 95 </button>
diff --git a/src/components/ui/button/index.tsx b/src/components/ui/button/index.tsx
index a2194e34d..3247072a9 100644
--- a/src/components/ui/button/index.tsx
+++ b/src/components/ui/button/index.tsx
@@ -8,6 +8,7 @@ import withStyles, { WithStylesProps } from 'react-jss';
8import Loader from '../loader/index'; 8import Loader from '../loader/index';
9import { Theme } from '../../../themes'; 9import { Theme } from '../../../themes';
10import { IFormField } from '../typings/generic'; 10import { IFormField } from '../typings/generic';
11import { DEFAULT_LOADER_COLOR } from '../../../config';
11 12
12type ButtonType = 13type ButtonType =
13 | 'primary' 14 | 'primary'
@@ -194,7 +195,7 @@ class ButtonComponent extends Component<IProps, IState> {
194 <> 195 <>
195 {showLoader && ( 196 {showLoader && (
196 <div className={classes.loaderContainer}> 197 <div className={classes.loaderContainer}>
197 <Loader size={18} color="#FFFFFF" /> 198 <Loader size={18} color={DEFAULT_LOADER_COLOR} />
198 </div> 199 </div>
199 )} 200 )}
200 <div className={classes.label}> 201 <div className={classes.label}>
diff --git a/src/components/ui/loader/index.tsx b/src/components/ui/loader/index.tsx
index 2cee00d96..c0ae15028 100644
--- a/src/components/ui/loader/index.tsx
+++ b/src/components/ui/loader/index.tsx
@@ -4,6 +4,7 @@ import injectStyle, { WithStylesProps } from 'react-jss';
4import { Oval } from 'react-loader-spinner'; 4import { Oval } from 'react-loader-spinner';
5import { inject } from 'mobx-react'; 5import { inject } from 'mobx-react';
6import { FerdiumStores } from '../../../@types/stores.types'; 6import { FerdiumStores } from '../../../@types/stores.types';
7import { DEFAULT_LOADER_COLOR } from '../../../config';
7 8
8const styles = () => ({ 9const styles = () => ({
9 container: { 10 container: {
@@ -29,11 +30,11 @@ class LoaderComponent extends Component<IProps> {
29 const { 30 const {
30 classes, 31 classes,
31 className, 32 className,
32 size = 36, 33 size = 100,
33 color = this.props.stores?.settings.app.accentColor, 34 color = this.props.stores?.settings.app.accentColor,
34 loaded = false, 35 loaded = false,
35 } = this.props; 36 } = this.props;
36 const loaderColor = color || '#FFFFFF'; 37 const loaderColor = color ?? DEFAULT_LOADER_COLOR;
37 38
38 return ( 39 return (
39 <div 40 <div
diff --git a/src/config.ts b/src/config.ts
index d8b028104..5b9a5eaba 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -27,12 +27,8 @@ export const LIVE_API_FERDIUM_WEBSITE = 'https://ferdium.org';
27export const LIVE_API_FERDIUM_LIBRETRANSLATE = 27export const LIVE_API_FERDIUM_LIBRETRANSLATE =
28 'https://translator.ferdium.org/translate'; 28 'https://translator.ferdium.org/translate';
29 29
30export const STATS_API = 'https://stats.franzinfra.com';
31
32export const LOCAL_TODOS_FRONTEND_URL = 'http://localhost:4000'; 30export const LOCAL_TODOS_FRONTEND_URL = 'http://localhost:4000';
33export const PRODUCTION_TODOS_FRONTEND_URL = 'https://app.franztodos.com'; 31export const PRODUCTION_TODOS_FRONTEND_URL = 'https://app.franztodos.com';
34export const DEVELOPMENT_TODOS_FRONTEND_URL =
35 'https://development--franz-todos.netlify.com';
36 32
37export const CDN_URL = 'https://cdn.franzinfra.com'; 33export const CDN_URL = 'https://cdn.franzinfra.com';
38 34
@@ -282,11 +278,6 @@ export const TODO_APPS = {
282 [CUSTOM_TODO_SERVICE]: 'Other service', 278 [CUSTOM_TODO_SERVICE]: 'Other service',
283}; 279};
284 280
285export const DEFAULT_TODO_SERVICE = TODO_TODOIST_URL;
286export const DEFAULT_TODO_RECIPE_ID =
287 TODO_SERVICE_RECIPE_IDS[DEFAULT_TODO_SERVICE];
288export const DEFAULT_TODO_SERVICE_NAME = TODO_APPS[DEFAULT_TODO_SERVICE];
289
290export const SIDEBAR_WIDTH = { 281export const SIDEBAR_WIDTH = {
291 35: 'Extremely slim sidebar', 282 35: 'Extremely slim sidebar',
292 45: 'Very slim sidebar', 283 45: 'Very slim sidebar',
@@ -329,7 +320,8 @@ export const GITHUB_FRANZ_URL = 'https://github.com/meetfranz';
329export const GITHUB_FERDIUM_URL = 'https://github.com/ferdium'; 320export const GITHUB_FERDIUM_URL = 'https://github.com/ferdium';
330export const FERDIUM_SERVICE_REQUEST = `${GITHUB_FERDIUM_URL}/ferdium-app/issues`; 321export const FERDIUM_SERVICE_REQUEST = `${GITHUB_FERDIUM_URL}/ferdium-app/issues`;
331export const FERDIUM_TRANSLATION = 'https://crowdin.com/project/ferdium-app'; 322export const FERDIUM_TRANSLATION = 'https://crowdin.com/project/ferdium-app';
332export const FRANZ_DEV_DOCS = 'http://bit.ly/franz-dev-hub'; 323export const FERDIUM_DEV_DOCS =
324 'https://github.com/ferdium/ferdium-recipes/blob/main/docs/integration.md';
333 325
334export const FILE_SYSTEM_SETTINGS_TYPES = ['app', 'proxy']; 326export const FILE_SYSTEM_SETTINGS_TYPES = ['app', 'proxy'];
335 327
@@ -351,6 +343,8 @@ export const DEFAULT_SERVICE_ORDER = 99; // something high enough that it gets a
351export const SPLIT_COLUMNS_MIN = 1; 343export const SPLIT_COLUMNS_MIN = 1;
352export const SPLIT_COLUMNS_MAX = 5; 344export const SPLIT_COLUMNS_MAX = 5;
353 345
346export const DEFAULT_LOADER_COLOR = '#FFFFFF';
347
354export const DEFAULT_APP_SETTINGS = { 348export const DEFAULT_APP_SETTINGS = {
355 autoLaunchOnStart: false, 349 autoLaunchOnStart: false,
356 autoLaunchInBackground: false, 350 autoLaunchInBackground: false,
@@ -366,6 +360,8 @@ export const DEFAULT_APP_SETTINGS = {
366 clipboardNotifications: true, 360 clipboardNotifications: true,
367 notifyTaskBarOnMessage: false, 361 notifyTaskBarOnMessage: false,
368 showDisabledServices: true, 362 showDisabledServices: true,
363 isTwoFactorAutoCatcherEnabled: false,
364 twoFactorAutoCatcherMatcher: 'token, code, sms, verify',
369 showServiceName: false, 365 showServiceName: false,
370 showMessageBadgeWhenMuted: true, 366 showMessageBadgeWhenMuted: true,
371 showDragArea: false, 367 showDragArea: false,
@@ -384,9 +380,9 @@ export const DEFAULT_APP_SETTINGS = {
384 380
385 // Ferdium specific options 381 // Ferdium specific options
386 server: LIVE_FERDIUM_API, 382 server: LIVE_FERDIUM_API,
387 predefinedTodoServer: DEFAULT_TODO_SERVICE, 383 predefinedTodoServer: TODO_TODOIST_URL,
388 autohideMenuBar: false, 384 autohideMenuBar: false,
389 lockingFeatureEnabled: false, 385 isLockingFeatureEnabled: false,
390 locked: false, 386 locked: false,
391 lockedPassword: '', 387 lockedPassword: '',
392 useTouchIdToUnlock: true, 388 useTouchIdToUnlock: true,
@@ -432,6 +428,7 @@ export const DEFAULT_APP_SETTINGS = {
432 customTodoServer: '', 428 customTodoServer: '',
433 locale: 'en-US', 429 locale: 'en-US',
434 keepAllWorkspacesLoaded: false, 430 keepAllWorkspacesLoaded: false,
431 useSelfSignedCertificates: false,
435}; 432};
436 433
437export const DEFAULT_SERVICE_SETTINGS = { 434export const DEFAULT_SERVICE_SETTINGS = {
@@ -457,7 +454,7 @@ export const DEFAULT_SERVICE_SETTINGS = {
457 disablewebsecurity: false, 454 disablewebsecurity: false,
458 spellcheckerLanguage: false, 455 spellcheckerLanguage: false,
459 onlyShowFavoritesInUnreadCount: false, 456 onlyShowFavoritesInUnreadCount: false,
460 proxyFeatureEnabled: false, 457 isProxyFeatureEnabled: false,
461 proxyHost: '', 458 proxyHost: '',
462 proxyPort: 0, 459 proxyPort: 0,
463 proxyUser: '', 460 proxyUser: '',
diff --git a/src/containers/settings/EditServiceScreen.tsx b/src/containers/settings/EditServiceScreen.tsx
index 946ec09d3..3c65877c8 100644
--- a/src/containers/settings/EditServiceScreen.tsx
+++ b/src/containers/settings/EditServiceScreen.tsx
@@ -409,9 +409,9 @@ class EditServiceScreen extends Component<IProps> {
409 label: intl.formatMessage(messages.enableProxy), 409 label: intl.formatMessage(messages.enableProxy),
410 value: ifUndefined<boolean>( 410 value: ifUndefined<boolean>(
411 serviceProxyConfig.isEnabled, 411 serviceProxyConfig.isEnabled,
412 DEFAULT_SERVICE_SETTINGS.proxyFeatureEnabled, 412 DEFAULT_SERVICE_SETTINGS.isProxyFeatureEnabled,
413 ), 413 ),
414 default: DEFAULT_SERVICE_SETTINGS.proxyFeatureEnabled, 414 default: DEFAULT_SERVICE_SETTINGS.isProxyFeatureEnabled,
415 type: 'checkbox', 415 type: 'checkbox',
416 }, 416 },
417 host: { 417 host: {
diff --git a/src/containers/settings/EditSettingsScreen.tsx b/src/containers/settings/EditSettingsScreen.tsx
index 8190bef3e..5d1b09296 100644
--- a/src/containers/settings/EditSettingsScreen.tsx
+++ b/src/containers/settings/EditSettingsScreen.tsx
@@ -99,6 +99,16 @@ const messages = defineMessages({
99 id: 'settings.app.form.notifyTaskBarOnMessage', 99 id: 'settings.app.form.notifyTaskBarOnMessage',
100 defaultMessage: 'Notify TaskBar/Dock on new message', 100 defaultMessage: 'Notify TaskBar/Dock on new message',
101 }, 101 },
102 isTwoFactorAutoCatcherEnabled: {
103 id: 'settings.app.form.isTwoFactorAutoCatcherEnabled',
104 defaultMessage:
105 'Auto-catch two-factor codes from notifications (Ex.: android messages) and copy to clipboard',
106 },
107 twoFactorAutoCatcherMatcher: {
108 id: 'settings.app.form.twoFactorAutoCatcherMatcher',
109 defaultMessage:
110 'Comma-separated and case-insensitive words/expressions to catch two-factor codes from. Ex.: token, code, sms, verify',
111 },
102 navigationBarBehaviour: { 112 navigationBarBehaviour: {
103 id: 'settings.app.form.navigationBarBehaviour', 113 id: 'settings.app.form.navigationBarBehaviour',
104 defaultMessage: 'Navigation bar behaviour', 114 defaultMessage: 'Navigation bar behaviour',
@@ -295,6 +305,10 @@ const messages = defineMessages({
295 id: 'settings.app.form.enableTranslator', 305 id: 'settings.app.form.enableTranslator',
296 defaultMessage: 'Enable Translator', 306 defaultMessage: 'Enable Translator',
297 }, 307 },
308 useSelfSignedCertificates: {
309 id: 'settings.app.form.useSelfSignedCertificates',
310 defaultMessage: 'Enable self-signed certificates',
311 },
298 enableGPUAcceleration: { 312 enableGPUAcceleration: {
299 id: 'settings.app.form.enableGPUAcceleration', 313 id: 'settings.app.form.enableGPUAcceleration',
300 defaultMessage: 'Enable GPU Acceleration', 314 defaultMessage: 'Enable GPU Acceleration',
@@ -379,6 +393,10 @@ class EditSettingsScreen extends Component<
379 privateNotifications: Boolean(settingsData.privateNotifications), 393 privateNotifications: Boolean(settingsData.privateNotifications),
380 clipboardNotifications: Boolean(settingsData.clipboardNotifications), 394 clipboardNotifications: Boolean(settingsData.clipboardNotifications),
381 notifyTaskBarOnMessage: Boolean(settingsData.notifyTaskBarOnMessage), 395 notifyTaskBarOnMessage: Boolean(settingsData.notifyTaskBarOnMessage),
396 isTwoFactorAutoCatcherEnabled: Boolean(
397 settingsData.isTwoFactorAutoCatcherEnabled,
398 ),
399 twoFactorAutoCatcherMatcher: settingsData.twoFactorAutoCatcherMatcher,
382 navigationBarBehaviour: settingsData.navigationBarBehaviour, 400 navigationBarBehaviour: settingsData.navigationBarBehaviour,
383 webRTCIPHandlingPolicy: settingsData.webRTCIPHandlingPolicy, 401 webRTCIPHandlingPolicy: settingsData.webRTCIPHandlingPolicy,
384 searchEngine: settingsData.searchEngine, 402 searchEngine: settingsData.searchEngine,
@@ -394,7 +412,7 @@ class EditSettingsScreen extends Component<
394 wakeUpHibernationSplay: Boolean(settingsData.wakeUpHibernationSplay), 412 wakeUpHibernationSplay: Boolean(settingsData.wakeUpHibernationSplay),
395 predefinedTodoServer: settingsData.predefinedTodoServer, 413 predefinedTodoServer: settingsData.predefinedTodoServer,
396 customTodoServer: settingsData.customTodoServer, 414 customTodoServer: settingsData.customTodoServer,
397 lockingFeatureEnabled: Boolean(settingsData.lockingFeatureEnabled), 415 isLockingFeatureEnabled: Boolean(settingsData.isLockingFeatureEnabled),
398 lockedPassword: useOriginalPassword 416 lockedPassword: useOriginalPassword
399 ? this.props.stores.settings.all.app.lockedPassword 417 ? this.props.stores.settings.all.app.lockedPassword
400 : hash(String(settingsData.lockedPassword)), 418 : hash(String(settingsData.lockedPassword)),
@@ -439,6 +457,9 @@ class EditSettingsScreen extends Component<
439 showDragArea: Boolean(settingsData.showDragArea), 457 showDragArea: Boolean(settingsData.showDragArea),
440 enableSpellchecking: Boolean(settingsData.enableSpellchecking), 458 enableSpellchecking: Boolean(settingsData.enableSpellchecking),
441 enableTranslator: Boolean(settingsData.enableTranslator), 459 enableTranslator: Boolean(settingsData.enableTranslator),
460 useSelfSignedCertificates: Boolean(
461 settingsData.useSelfSignedCertificates,
462 ),
442 spellcheckerLanguage: settingsData.spellcheckerLanguage, 463 spellcheckerLanguage: settingsData.spellcheckerLanguage,
443 userAgentPref: settingsData.userAgentPref, 464 userAgentPref: settingsData.userAgentPref,
444 beta: Boolean(settingsData.beta), // we need this info in the main process as well 465 beta: Boolean(settingsData.beta), // we need this info in the main process as well
@@ -673,6 +694,23 @@ class EditSettingsScreen extends Component<
673 default: DEFAULT_APP_SETTINGS.notifyTaskBarOnMessage, 694 default: DEFAULT_APP_SETTINGS.notifyTaskBarOnMessage,
674 type: 'checkbox', 695 type: 'checkbox',
675 }, 696 },
697 isTwoFactorAutoCatcherEnabled: {
698 label: intl.formatMessage(messages.isTwoFactorAutoCatcherEnabled),
699 value: ifUndefined<boolean>(
700 settings.all.app.isTwoFactorAutoCatcherEnabled,
701 DEFAULT_APP_SETTINGS.isTwoFactorAutoCatcherEnabled,
702 ),
703 default: DEFAULT_APP_SETTINGS.isTwoFactorAutoCatcherEnabled,
704 type: 'checkbox',
705 },
706 twoFactorAutoCatcherMatcher: {
707 label: intl.formatMessage(messages.twoFactorAutoCatcherMatcher),
708 value: ifUndefined<string>(
709 settings.all.app.twoFactorAutoCatcherMatcher,
710 DEFAULT_APP_SETTINGS.twoFactorAutoCatcherMatcher,
711 ),
712 default: DEFAULT_APP_SETTINGS.twoFactorAutoCatcherMatcher,
713 },
676 navigationBarBehaviour: { 714 navigationBarBehaviour: {
677 label: intl.formatMessage(messages.navigationBarBehaviour), 715 label: intl.formatMessage(messages.navigationBarBehaviour),
678 value: ifUndefined<string>( 716 value: ifUndefined<string>(
@@ -789,13 +827,13 @@ class EditSettingsScreen extends Component<
789 ), 827 ),
790 default: DEFAULT_APP_SETTINGS.customTodoServer, 828 default: DEFAULT_APP_SETTINGS.customTodoServer,
791 }, 829 },
792 lockingFeatureEnabled: { 830 isLockingFeatureEnabled: {
793 label: intl.formatMessage(messages.enableLock), 831 label: intl.formatMessage(messages.enableLock),
794 value: ifUndefined<boolean>( 832 value: ifUndefined<boolean>(
795 settings.all.app.lockingFeatureEnabled, 833 settings.all.app.isLockingFeatureEnabled,
796 DEFAULT_APP_SETTINGS.lockingFeatureEnabled, 834 DEFAULT_APP_SETTINGS.isLockingFeatureEnabled,
797 ), 835 ),
798 default: DEFAULT_APP_SETTINGS.lockingFeatureEnabled, 836 default: DEFAULT_APP_SETTINGS.isLockingFeatureEnabled,
799 type: 'checkbox', 837 type: 'checkbox',
800 }, 838 },
801 lockedPassword: { 839 lockedPassword: {
@@ -906,6 +944,15 @@ class EditSettingsScreen extends Component<
906 default: DEFAULT_APP_SETTINGS.enableTranslator, 944 default: DEFAULT_APP_SETTINGS.enableTranslator,
907 type: 'checkbox', 945 type: 'checkbox',
908 }, 946 },
947 useSelfSignedCertificates: {
948 label: intl.formatMessage(messages.useSelfSignedCertificates),
949 value: ifUndefined<boolean>(
950 settings.all.app.useSelfSignedCertificates,
951 DEFAULT_APP_SETTINGS.useSelfSignedCertificates,
952 ),
953 default: DEFAULT_APP_SETTINGS.useSelfSignedCertificates,
954 type: 'checkbox',
955 },
909 spellcheckerLanguage: { 956 spellcheckerLanguage: {
910 label: intl.formatMessage(globalMessages.spellcheckerLanguage), 957 label: intl.formatMessage(globalMessages.spellcheckerLanguage),
911 value: ifUndefined<string>( 958 value: ifUndefined<string>(
@@ -1207,7 +1254,7 @@ class EditSettingsScreen extends Component<
1207 updateVersion, 1254 updateVersion,
1208 updateStatusTypes, 1255 updateStatusTypes,
1209 isClearingAllCache, 1256 isClearingAllCache,
1210 lockingFeatureEnabled, 1257 isLockingFeatureEnabled,
1211 } = app; 1258 } = app;
1212 const { checkForUpdates, installUpdate, clearAllCache } = 1259 const { checkForUpdates, installUpdate, clearAllCache } =
1213 this.props.actions.app; 1260 this.props.actions.app;
@@ -1231,7 +1278,7 @@ class EditSettingsScreen extends Component<
1231 getCacheSize={() => app.cacheSize} 1278 getCacheSize={() => app.cacheSize}
1232 isClearingAllCache={isClearingAllCache} 1279 isClearingAllCache={isClearingAllCache}
1233 onClearAllCache={clearAllCache} 1280 onClearAllCache={clearAllCache}
1234 lockingFeatureEnabled={lockingFeatureEnabled} 1281 isLockingFeatureEnabled={isLockingFeatureEnabled}
1235 automaticUpdates={this.props.stores.settings.app.automaticUpdates} 1282 automaticUpdates={this.props.stores.settings.app.automaticUpdates}
1236 isDarkmodeEnabled={this.props.stores.settings.app.darkMode} 1283 isDarkmodeEnabled={this.props.stores.settings.app.darkMode}
1237 isAdaptableDarkModeEnabled={ 1284 isAdaptableDarkModeEnabled={
@@ -1241,6 +1288,12 @@ class EditSettingsScreen extends Component<
1241 this.props.stores.settings.app.useGrayscaleServices 1288 this.props.stores.settings.app.useGrayscaleServices
1242 } 1289 }
1243 isSplitModeEnabled={this.props.stores.settings.app.splitMode} 1290 isSplitModeEnabled={this.props.stores.settings.app.splitMode}
1291 isTwoFactorAutoCatcherEnabled={
1292 this.props.stores.settings.app.isTwoFactorAutoCatcherEnabled
1293 }
1294 twoFactorAutoCatcherMatcher={
1295 this.props.stores.settings.app.twoFactorAutoCatcherMatcher
1296 }
1244 isTodosActivated={this.props.stores.todos.isFeatureEnabledByUser} 1297 isTodosActivated={this.props.stores.todos.isFeatureEnabledByUser}
1245 openProcessManager={() => this.openProcessManager()} 1298 openProcessManager={() => this.openProcessManager()}
1246 isOnline={app.isOnline} 1299 isOnline={app.isOnline}
diff --git a/src/containers/settings/RecipesScreen.tsx b/src/containers/settings/RecipesScreen.tsx
index 1fb2673a8..a46510d54 100644
--- a/src/containers/settings/RecipesScreen.tsx
+++ b/src/containers/settings/RecipesScreen.tsx
@@ -8,7 +8,7 @@ import Recipe from '../../models/Recipe';
8import { StoresProps } from '../../@types/ferdium-components.types'; 8import { StoresProps } from '../../@types/ferdium-components.types';
9import RecipesDashboard from '../../components/settings/recipes/RecipesDashboard'; 9import RecipesDashboard from '../../components/settings/recipes/RecipesDashboard';
10import ErrorBoundary from '../../components/util/ErrorBoundary'; 10import ErrorBoundary from '../../components/util/ErrorBoundary';
11import { CUSTOM_WEBSITE_RECIPE_ID, FRANZ_DEV_DOCS } from '../../config'; 11import { CUSTOM_WEBSITE_RECIPE_ID, FERDIUM_DEV_DOCS } from '../../config';
12import { userDataRecipesPath } from '../../environment-remote'; 12import { userDataRecipesPath } from '../../environment-remote';
13import { asarRecipesPath } from '../../helpers/asar-helpers'; 13import { asarRecipesPath } from '../../helpers/asar-helpers';
14import { communityRecipesStore } from '../../features/communityRecipes'; 14import { communityRecipesStore } from '../../features/communityRecipes';
@@ -176,7 +176,7 @@ class RecipesScreen extends Component<IProps, IState> {
176 recipeDirectory={recipeDirectory} 176 recipeDirectory={recipeDirectory}
177 openRecipeDirectory={() => openPath(recipeDirectory)} 177 openRecipeDirectory={() => openPath(recipeDirectory)}
178 openDevDocs={() => 178 openDevDocs={() =>
179 appActions.openExternalUrl({ url: FRANZ_DEV_DOCS }) 179 appActions.openExternalUrl({ url: FERDIUM_DEV_DOCS })
180 } 180 }
181 /> 181 />
182 </ErrorBoundary> 182 </ErrorBoundary>
diff --git a/src/environment-remote.ts b/src/environment-remote.ts
index da1477346..346a75e97 100644
--- a/src/environment-remote.ts
+++ b/src/environment-remote.ts
@@ -10,8 +10,6 @@ import {
10 LIVE_WS_API, 10 LIVE_WS_API,
11 LOCAL_WS_API, 11 LOCAL_WS_API,
12 DEV_WS_API, 12 DEV_WS_API,
13 LOCAL_TODOS_FRONTEND_URL,
14 PRODUCTION_TODOS_FRONTEND_URL,
15} from './config'; 13} from './config';
16import { isWindows } from './environment'; 14import { isWindows } from './environment';
17 15
@@ -50,34 +48,33 @@ export function userDataRecipesPath(...segments: string[]): string {
50 return userDataPath('recipes', ...[segments].flat()); 48 return userDataPath('recipes', ...[segments].flat());
51} 49}
52 50
51export function userDataCertsPath(...segments: string[]): string {
52 return userDataPath('certs', ...[segments].flat());
53}
54
53const useLocalAPI = process.env.USE_LOCAL_API; 55const useLocalAPI = process.env.USE_LOCAL_API;
54export const useLiveAPI = process.env.USE_LIVE_API; 56export const useLiveAPI = process.env.USE_LIVE_API;
55 57
56let api: string; 58let api: string;
57let wsApi: string; 59let wsApi: string;
58let web: string; 60let web: string;
59let todos: string;
60if (!isDevMode || (isDevMode && useLiveAPI)) { 61if (!isDevMode || (isDevMode && useLiveAPI)) {
61 api = LIVE_FERDIUM_API; 62 api = LIVE_FERDIUM_API;
62 wsApi = LIVE_WS_API; 63 wsApi = LIVE_WS_API;
63 web = LIVE_API_FERDIUM_WEBSITE; 64 web = LIVE_API_FERDIUM_WEBSITE;
64 todos = PRODUCTION_TODOS_FRONTEND_URL;
65} else if (isDevMode && useLocalAPI) { 65} else if (isDevMode && useLocalAPI) {
66 api = LOCAL_API; 66 api = LOCAL_API;
67 wsApi = LOCAL_WS_API; 67 wsApi = LOCAL_WS_API;
68 web = LOCAL_API_WEBSITE; 68 web = LOCAL_API_WEBSITE;
69 todos = LOCAL_TODOS_FRONTEND_URL;
70} else { 69} else {
71 api = DEV_FRANZ_API; 70 api = DEV_FRANZ_API;
72 wsApi = DEV_WS_API; 71 wsApi = DEV_WS_API;
73 web = DEV_API_FRANZ_WEBSITE; 72 web = DEV_API_FRANZ_WEBSITE;
74 todos = PRODUCTION_TODOS_FRONTEND_URL;
75} 73}
76 74
77export const API: string = api; 75export const API: string = api;
78export const API_VERSION: string = 'v1'; 76export const API_VERSION: string = 'v1';
79export const WS_API: string = wsApi; 77export const WS_API: string = wsApi;
80export const WEBSITE: string = web; 78export const WEBSITE: string = web;
81export const TODOS_FRONTEND: string = todos;
82// For deeplink protocol: 'ferdium' or 'ferdium-dev' if we want '{DEEPLINK_PROTOCOL_CLIENT}://' 79// For deeplink protocol: 'ferdium' or 'ferdium-dev' if we want '{DEEPLINK_PROTOCOL_CLIENT}://'
83export const protocolClient = isDevMode ? 'ferdium-dev' : 'ferdium'; 80export const protocolClient = isDevMode ? 'ferdium-dev' : 'ferdium';
diff --git a/src/features/workspaces/components/WorkspaceSwitchingIndicator.tsx b/src/features/workspaces/components/WorkspaceSwitchingIndicator.tsx
index 0fce811e5..19dd9037d 100644
--- a/src/features/workspaces/components/WorkspaceSwitchingIndicator.tsx
+++ b/src/features/workspaces/components/WorkspaceSwitchingIndicator.tsx
@@ -5,6 +5,7 @@ import classnames from 'classnames';
5import { defineMessages, injectIntl, WrappedComponentProps } from 'react-intl'; 5import { defineMessages, injectIntl, WrappedComponentProps } from 'react-intl';
6import Loader from '../../../components/ui/loader'; 6import Loader from '../../../components/ui/loader';
7import { workspaceStore } from '../index'; 7import { workspaceStore } from '../index';
8import { DEFAULT_LOADER_COLOR } from '../../../config';
8 9
9const messages = defineMessages({ 10const messages = defineMessages({
10 switchingTo: { 11 switchingTo: {
@@ -70,7 +71,7 @@ class WorkspaceSwitchingIndicator extends Component<IProps> {
70 return ( 71 return (
71 <div className={classnames([classes.wrapper])}> 72 <div className={classnames([classes.wrapper])}>
72 <div className={classes.component}> 73 <div className={classes.component}>
73 <Loader className={classes.spinner} color="#FFFFFF" /> 74 <Loader className={classes.spinner} color={DEFAULT_LOADER_COLOR} />
74 <p className={classes.message}> 75 <p className={classes.message}>
75 {`${intl.formatMessage(messages.switchingTo)} ${nextWorkspaceName}`} 76 {`${intl.formatMessage(messages.switchingTo)} ${nextWorkspaceName}`}
76 </p> 77 </p>
diff --git a/src/features/workspaces/store.ts b/src/features/workspaces/store.ts
index 34a4126c8..f97009186 100644
--- a/src/features/workspaces/store.ts
+++ b/src/features/workspaces/store.ts
@@ -51,11 +51,6 @@ export default class WorkspacesStore extends FeatureStore {
51 return getUserWorkspacesRequest.result || []; 51 return getUserWorkspacesRequest.result || [];
52 } 52 }
53 53
54 @computed get isLoadingWorkspaces() {
55 if (!this.isFeatureActive) return false;
56 return getUserWorkspacesRequest.isExecutingFirstTime;
57 }
58
59 @computed get settings() { 54 @computed get settings() {
60 return localStorage.getItem('workspaces') || {}; 55 return localStorage.getItem('workspaces') || {};
61 } 56 }
diff --git a/src/helpers/certs-helpers.ts b/src/helpers/certs-helpers.ts
new file mode 100644
index 000000000..a6c83f5c4
--- /dev/null
+++ b/src/helpers/certs-helpers.ts
@@ -0,0 +1,22 @@
1import { readdirSync, readFileSync, ensureDirSync } from 'fs-extra';
2import { join } from 'node:path';
3import { userDataCertsPath } from '../environment-remote';
4import { removeNewLines } from '../jsUtils';
5
6export function checkIfCertIsPresent(certData: string): boolean {
7 const certsFolder = userDataCertsPath();
8
9 ensureDirSync(certsFolder);
10
11 const certs: string[] = [];
12
13 for (const file of readdirSync(certsFolder)) {
14 const cert = readFileSync(join(certsFolder, file), {
15 encoding: 'utf8',
16 flag: 'r',
17 });
18 certs.push(removeNewLines(cert));
19 }
20
21 return certs.length > 0 && certs.includes(removeNewLines(certData));
22}
diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json
index 66514ad8f..fda047798 100644
--- a/src/i18n/locales/de.json
+++ b/src/i18n/locales/de.json
@@ -187,6 +187,7 @@
187 "settings.account.yourLicense": "Ihre Ferdium-Lizenz:", 187 "settings.account.yourLicense": "Ihre Ferdium-Lizenz:",
188 "settings.app.accentColorInfo": "Geben Sie Ihre Farbwahl in einem CSS-kompatiblen Format an. (Standardwert: {defaultAccentColor} oder leeren Sie das Eingabefeld)", 188 "settings.app.accentColorInfo": "Geben Sie Ihre Farbwahl in einem CSS-kompatiblen Format an. (Standardwert: {defaultAccentColor} oder leeren Sie das Eingabefeld)",
189 "settings.app.buttonInstallUpdate": "Neu starten und Aktualisierungen installieren", 189 "settings.app.buttonInstallUpdate": "Neu starten und Aktualisierungen installieren",
190 "settings.app.buttonOpenFerdiumCertsFolder": "Ordner „Zertifikate” öffnen",
190 "settings.app.buttonOpenFerdiumProfileFolder": "Profilordner anzeigen", 191 "settings.app.buttonOpenFerdiumProfileFolder": "Profilordner anzeigen",
191 "settings.app.buttonOpenFerdiumServiceRecipesFolder": "Rezeptordner öffnen", 192 "settings.app.buttonOpenFerdiumServiceRecipesFolder": "Rezeptordner öffnen",
192 "settings.app.buttonOpenImportExport": "Importieren/Exportieren", 193 "settings.app.buttonOpenImportExport": "Importieren/Exportieren",
@@ -228,6 +229,7 @@
228 "settings.app.form.hideWorkspacesButton": "Schaltfläche „Arbeitsbereich” ausblenden", 229 "settings.app.form.hideWorkspacesButton": "Schaltfläche „Arbeitsbereich” ausblenden",
229 "settings.app.form.iconSize": "Symbolgröße des Dienstes", 230 "settings.app.form.iconSize": "Symbolgröße des Dienstes",
230 "settings.app.form.inactivityLock": "Nach Inaktivität sperren", 231 "settings.app.form.inactivityLock": "Nach Inaktivität sperren",
232 "settings.app.form.isTwoFactorAutoCatcherEnabled": "Automatisches Erfassen von Zwei-Faktor-Codes aus Benachrichtigungen (z. B.: Android-Nachrichten) und Kopieren in die Zwischenablage",
231 "settings.app.form.keepAllWorkspacesLoaded": "Alle Arbeitsbereiche geladen lassen", 233 "settings.app.form.keepAllWorkspacesLoaded": "Alle Arbeitsbereiche geladen lassen",
232 "settings.app.form.language": "Sprache", 234 "settings.app.form.language": "Sprache",
233 "settings.app.form.lockPassword": "Passwort", 235 "settings.app.form.lockPassword": "Passwort",
@@ -257,9 +259,11 @@
257 "settings.app.form.startMinimized": "Minimiert starten", 259 "settings.app.form.startMinimized": "Minimiert starten",
258 "settings.app.form.translatorEngine": "Übersetzungsmaschine", 260 "settings.app.form.translatorEngine": "Übersetzungsmaschine",
259 "settings.app.form.translatorLanguage": "Standard-Übersetzungssprache", 261 "settings.app.form.translatorLanguage": "Standard-Übersetzungssprache",
262 "settings.app.form.twoFactorAutoCatcherMatcher": "Durch Kommata getrennte Wörter/Ausdrücke ohne Berücksichtigung der Groß-/Kleinschreibung, um Zwei-Faktor-Codes abzufangen. Bsp.: Token, Code, SMS, Verifizieren",
260 "settings.app.form.universalDarkMode": "Universellen Dunkelmodus aktivieren", 263 "settings.app.form.universalDarkMode": "Universellen Dunkelmodus aktivieren",
261 "settings.app.form.useGrayscaleServices": "Graustufendienste verwenden", 264 "settings.app.form.useGrayscaleServices": "Graustufendienste verwenden",
262 "settings.app.form.useHorizontalStyle": "Horizontalen Stil verwenden", 265 "settings.app.form.useHorizontalStyle": "Horizontalen Stil verwenden",
266 "settings.app.form.useSelfSignedCertificates": "Selbstsignierte Zertifikate aktivieren",
263 "settings.app.form.useTouchIdToUnlock": "Verwenden von Touch ID zum Entsperren von Ferdium erlauben", 267 "settings.app.form.useTouchIdToUnlock": "Verwenden von Touch ID zum Entsperren von Ferdium erlauben",
264 "settings.app.form.wakeUpHibernationSplay": "Splay Ruhe/Weckzyklen, um die Last zu reduzieren", 268 "settings.app.form.wakeUpHibernationSplay": "Splay Ruhe/Weckzyklen, um die Last zu reduzieren",
265 "settings.app.form.wakeUpHibernationStrategy": "Ruhezustand Strategie nach automatischem Aufwachen", 269 "settings.app.form.wakeUpHibernationStrategy": "Ruhezustand Strategie nach automatischem Aufwachen",
@@ -274,6 +278,7 @@
274 "settings.app.headlineUpdates": "Updates", 278 "settings.app.headlineUpdates": "Updates",
275 "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.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.",
276 "settings.app.inactivityLockInfo": "Minuten der Inaktivität, nach denen Ferdium automatisch sperren soll. Verwenden Sie 0, um dies zu deaktivieren", 280 "settings.app.inactivityLockInfo": "Minuten der Inaktivität, nach denen Ferdium automatisch sperren soll. Verwenden Sie 0, um dies zu deaktivieren",
281 "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.",
277 "settings.app.lockInfo": "Die Passwort-Sperre erlaubt es dir, deine Nachrichten zu schützen.\nMit der Passwort-Sperre wirst du sowohl beim Starten von Ferdium als auch wenn du das Programm manuell sperrst darum gebeten, dein Passwort einzugeben.\nDu kannst Ferdium über das Sperrsymbol in der unteren linken Ecke oder mit dem Shortcut {lockShortcut} sperren.", 282 "settings.app.lockInfo": "Die Passwort-Sperre erlaubt es dir, deine Nachrichten zu schützen.\nMit der Passwort-Sperre wirst du sowohl beim Starten von Ferdium als auch wenn du das Programm manuell sperrst darum gebeten, dein Passwort einzugeben.\nDu kannst Ferdium über das Sperrsymbol in der unteren linken Ecke oder mit dem Shortcut {lockShortcut} sperren.",
278 "settings.app.lockedPassword": "Passwort", 283 "settings.app.lockedPassword": "Passwort",
279 "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.", 284 "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.",
@@ -294,6 +299,7 @@
294 "settings.app.sectionUpdates": "App-Aktualisierungseinstellungen", 299 "settings.app.sectionUpdates": "App-Aktualisierungseinstellungen",
295 "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!", 300 "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!",
296 "settings.app.serverHelp": "Verbunden mit dem Server unter {serverURL}", 301 "settings.app.serverHelp": "Verbunden mit dem Server unter {serverURL}",
302 "settings.app.servicesUpdateStatusUpToDate": "Ihre Dienste sind auf dem neuesten Stand",
297 "settings.app.spellCheckerLanguageInfo": "Ferdium verwendet den eingebauten Rechtschreibprüfer deines Macs, um nach Tippfehlern zu suchen. Wenn du die zu überprüfenden Sprachen ändern möchtest, kannst du das in deinen Systemeinstellungen tun.", 303 "settings.app.spellCheckerLanguageInfo": "Ferdium verwendet den eingebauten Rechtschreibprüfer deines Macs, um nach Tippfehlern zu suchen. Wenn du die zu überprüfenden Sprachen ändern möchtest, kannst du das in deinen Systemeinstellungen tun.",
298 "settings.app.subheadlineCache": "Cache", 304 "settings.app.subheadlineCache": "Cache",
299 "settings.app.subheadlineFerdiumProfile": "Ferdium Profil", 305 "settings.app.subheadlineFerdiumProfile": "Ferdium Profil",
@@ -303,6 +309,7 @@
303 "settings.app.updateStatusAvailable": "Update verfügbar, lädt herunter...", 309 "settings.app.updateStatusAvailable": "Update verfügbar, lädt herunter...",
304 "settings.app.updateStatusSearching": "Suche nach Updates...", 310 "settings.app.updateStatusSearching": "Suche nach Updates...",
305 "settings.app.updateStatusUpToDate": "Sie verwenden die neueste Version von Ferdium", 311 "settings.app.updateStatusUpToDate": "Sie verwenden die neueste Version von Ferdium",
312 "settings.app.warningSelfSignedCertificates": "Warnhinweis: Aktivieren Sie diese Funktion nur, wenn Sie wissen, was Sie tun. Das Aktivieren dieser Funktion stellt ein Sicherheitsrisiko dar und sollte nur zu Testzwecken verwendet werden.",
306 "settings.invite.headline": "Lade drei Deiner Freunde ein", 313 "settings.invite.headline": "Lade drei Deiner Freunde ein",
307 "settings.navigation.account": "Konto", 314 "settings.navigation.account": "Konto",
308 "settings.navigation.availableServices": "Verfügbare Dienste", 315 "settings.navigation.availableServices": "Verfügbare Dienste",
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json
index da6d825b6..90a45e83c 100644
--- a/src/i18n/locales/en-US.json
+++ b/src/i18n/locales/en-US.json
@@ -188,6 +188,7 @@
188 "settings.account.yourLicense": "Your Ferdium License:", 188 "settings.account.yourLicense": "Your Ferdium License:",
189 "settings.app.accentColorInfo": "Write your color choice in a CSS-compatible format. (Default: {defaultAccentColor} or clear the input field)", 189 "settings.app.accentColorInfo": "Write your color choice in a CSS-compatible format. (Default: {defaultAccentColor} or clear the input field)",
190 "settings.app.buttonInstallUpdate": "Restart & install update", 190 "settings.app.buttonInstallUpdate": "Restart & install update",
191 "settings.app.buttonOpenFerdiumCertsFolder": "Open certificates folder",
191 "settings.app.buttonOpenFerdiumProfileFolder": "Open Profile folder", 192 "settings.app.buttonOpenFerdiumProfileFolder": "Open Profile folder",
192 "settings.app.buttonOpenFerdiumServiceRecipesFolder": "Open Service Recipes folder", 193 "settings.app.buttonOpenFerdiumServiceRecipesFolder": "Open Service Recipes folder",
193 "settings.app.buttonOpenImportExport": "Import / Export", 194 "settings.app.buttonOpenImportExport": "Import / Export",
@@ -230,6 +231,7 @@
230 "settings.app.form.hideWorkspacesButton": "Hide Workspace Drawer button", 231 "settings.app.form.hideWorkspacesButton": "Hide Workspace Drawer button",
231 "settings.app.form.iconSize": "Service icon size", 232 "settings.app.form.iconSize": "Service icon size",
232 "settings.app.form.inactivityLock": "Lock after inactivity", 233 "settings.app.form.inactivityLock": "Lock after inactivity",
234 "settings.app.form.isTwoFactorAutoCatcherEnabled": "Auto-catch two-factor codes from notifications (Ex.: android messages) and copy to clipboard",
233 "settings.app.form.keepAllWorkspacesLoaded": "Keep all workspaces loaded", 235 "settings.app.form.keepAllWorkspacesLoaded": "Keep all workspaces loaded",
234 "settings.app.form.language": "Language", 236 "settings.app.form.language": "Language",
235 "settings.app.form.lockPassword": "Password", 237 "settings.app.form.lockPassword": "Password",
@@ -259,9 +261,11 @@
259 "settings.app.form.startMinimized": "Start minimized", 261 "settings.app.form.startMinimized": "Start minimized",
260 "settings.app.form.translatorEngine": "Translator Engine", 262 "settings.app.form.translatorEngine": "Translator Engine",
261 "settings.app.form.translatorLanguage": "Default Translator language", 263 "settings.app.form.translatorLanguage": "Default Translator language",
264 "settings.app.form.twoFactorAutoCatcherMatcher": "Comma-separated and case-insensitive words/expressions to catch two-factor codes from. Ex.: token, code, sms, verify",
262 "settings.app.form.universalDarkMode": "Enable universal Dark Mode", 265 "settings.app.form.universalDarkMode": "Enable universal Dark Mode",
263 "settings.app.form.useGrayscaleServices": "Use grayscale services", 266 "settings.app.form.useGrayscaleServices": "Use grayscale services",
264 "settings.app.form.useHorizontalStyle": "Use horizontal style", 267 "settings.app.form.useHorizontalStyle": "Use horizontal style",
268 "settings.app.form.useSelfSignedCertificates": "Enable self-signed certificates",
265 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdium", 269 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdium",
266 "settings.app.form.wakeUpHibernationSplay": "Splay hibernate/wake cycles to reduce load", 270 "settings.app.form.wakeUpHibernationSplay": "Splay hibernate/wake cycles to reduce load",
267 "settings.app.form.wakeUpHibernationStrategy": "Hibernation strategy after automatic wake up", 271 "settings.app.form.wakeUpHibernationStrategy": "Hibernation strategy after automatic wake up",
@@ -276,6 +280,7 @@
276 "settings.app.headlineUpdates": "Updates", 280 "settings.app.headlineUpdates": "Updates",
277 "settings.app.hibernateInfo": "By default, Ferdium will keep all your services open and loaded in the background so they are ready when you want to use them. Service Hibernation will unload your services after a specified amount. This is useful to save RAM or keeping services from slowing down your computer.", 281 "settings.app.hibernateInfo": "By default, Ferdium will keep all your services open and loaded in the background so they are ready when you want to use them. Service Hibernation will unload your services after a specified amount. This is useful to save RAM or keeping services from slowing down your computer.",
278 "settings.app.inactivityLockInfo": "Minutes of inactivity, after which Ferdium should automatically lock. Use 0 to disable", 282 "settings.app.inactivityLockInfo": "Minutes of inactivity, after which Ferdium should automatically lock. Use 0 to disable",
283 "settings.app.infoOpenCertificatesFolder": "To install a certificate, click the button below to open the certificates folder and copy it into the folder. After that you can refresh the service (CTRL/CMD + R). To remove/uninstall, simply delete the certificate file and restart Ferdium.",
279 "settings.app.lockInfo": "Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdium or lock Ferdium yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.", 284 "settings.app.lockInfo": "Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdium or lock Ferdium yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.",
280 "settings.app.lockedPassword": "Password", 285 "settings.app.lockedPassword": "Password",
281 "settings.app.lockedPasswordInfo": "Please make sure to set a password you'll remember.\nIf you loose this password, you will have to reinstall Ferdium.", 286 "settings.app.lockedPasswordInfo": "Please make sure to set a password you'll remember.\nIf you loose this password, you will have to reinstall Ferdium.",
@@ -296,6 +301,7 @@
296 "settings.app.sectionUpdates": "App Updates Settings", 301 "settings.app.sectionUpdates": "App Updates Settings",
297 "settings.app.sentryInfo": "Sending telemetry data allows us to find errors in Ferdium - we will not send any personal information like your message data!", 302 "settings.app.sentryInfo": "Sending telemetry data allows us to find errors in Ferdium - we will not send any personal information like your message data!",
298 "settings.app.serverHelp": "Connected to server at {serverURL}", 303 "settings.app.serverHelp": "Connected to server at {serverURL}",
304 "settings.app.servicesUpdateStatusUpToDate": "Your services are up-to-date",
299 "settings.app.spellCheckerLanguageInfo": "Ferdium uses your Mac's build-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.", 305 "settings.app.spellCheckerLanguageInfo": "Ferdium uses your Mac's build-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.",
300 "settings.app.subheadlineCache": "Cache", 306 "settings.app.subheadlineCache": "Cache",
301 "settings.app.subheadlineFerdiumProfile": "Ferdium Profile", 307 "settings.app.subheadlineFerdiumProfile": "Ferdium Profile",
@@ -305,6 +311,7 @@
305 "settings.app.updateStatusAvailable": "Update available, downloading...", 311 "settings.app.updateStatusAvailable": "Update available, downloading...",
306 "settings.app.updateStatusSearching": "Searching for updates...", 312 "settings.app.updateStatusSearching": "Searching for updates...",
307 "settings.app.updateStatusUpToDate": "You are using the latest version of Ferdium", 313 "settings.app.updateStatusUpToDate": "You are using the latest version of Ferdium",
314 "settings.app.warningSelfSignedCertificates": "WARNING: Only enable this feature if you know what you are doing. Enabling this is a security risk and should only be used for testing purposes.",
308 "settings.invite.headline": "Invite Friends", 315 "settings.invite.headline": "Invite Friends",
309 "settings.navigation.account": "Account", 316 "settings.navigation.account": "Account",
310 "settings.navigation.availableServices": "Available services", 317 "settings.navigation.availableServices": "Available services",
diff --git a/src/i18n/locales/id.json b/src/i18n/locales/id.json
index b87168320..7017f3e75 100644
--- a/src/i18n/locales/id.json
+++ b/src/i18n/locales/id.json
@@ -9,6 +9,8 @@
9 "connectionLostBanner.cta": "Muat ulang Layanan", 9 "connectionLostBanner.cta": "Muat ulang Layanan",
10 "connectionLostBanner.informationLink": "Ada apa ini?", 10 "connectionLostBanner.informationLink": "Ada apa ini?",
11 "connectionLostBanner.message": "Yah! Ferdium terputus dari {name}.", 11 "connectionLostBanner.message": "Yah! Ferdium terputus dari {name}.",
12 "downloadManager.empty": "Daftar unduhan Anda kosong.",
13 "downloadManager.headline": "Pengelola unduhan",
12 "feature.basicAuth.signIn": "Masuk", 14 "feature.basicAuth.signIn": "Masuk",
13 "feature.publishDebugInfo.error": "Ada kesalahan saat mencoba memublikasikan informasi debug. Silakan coba lagi nanti atau lihat konsol untuk informasi lebih lanjut.", 15 "feature.publishDebugInfo.error": "Ada kesalahan saat mencoba memublikasikan informasi debug. Silakan coba lagi nanti atau lihat konsol untuk informasi lebih lanjut.",
14 "feature.publishDebugInfo.info": "Mempublikasikan informasi debug Anda membantu kami menemukan masalah dan kesalahan di Ferdium. Dengan mempublikasikan informasi debug anda, Anda menerima kebijakan privasi dan persyaratan layanan Ferdium Debugger", 16 "feature.publishDebugInfo.info": "Mempublikasikan informasi debug Anda membantu kami menemukan masalah dan kesalahan di Ferdium. Dengan mempublikasikan informasi debug anda, Anda menerima kebijakan privasi dan persyaratan layanan Ferdium Debugger",
@@ -21,6 +23,9 @@
21 "feature.quickSwitch.search": "Mencari...", 23 "feature.quickSwitch.search": "Mencari...",
22 "global.api.unhealthy": "Tidak dapat terhubung ke layanan {serverNameParse}", 24 "global.api.unhealthy": "Tidak dapat terhubung ke layanan {serverNameParse}",
23 "global.cancel": "Batalkan", 25 "global.cancel": "Batalkan",
26 "global.clearCache": "Hapus cache",
27 "global.downloads": "Unduhan",
28 "global.edit": "Edit",
24 "global.no": "Tidak", 29 "global.no": "Tidak",
25 "global.notConnectedToTheInternet": "Anda tidak tersambung ke internet.", 30 "global.notConnectedToTheInternet": "Anda tidak tersambung ke internet.",
26 "global.ok": "Oke", 31 "global.ok": "Oke",
@@ -35,6 +40,7 @@
35 "global.submit": "Kirim", 40 "global.submit": "Kirim",
36 "global.userAgentHelp": "Gunakan 'https://whatmyuseragent.com/' (untuk menemukan) atau 'https://developers.whatismybrowser.com/useragents/explore/' (untuk memilih) agen pengguna yang Anda inginkan dan salin di sini.", 41 "global.userAgentHelp": "Gunakan 'https://whatmyuseragent.com/' (untuk menemukan) atau 'https://developers.whatismybrowser.com/useragents/explore/' (untuk memilih) agen pengguna yang Anda inginkan dan salin di sini.",
37 "global.yes": "Ya", 42 "global.yes": "Ya",
43 "infobar.authRequestFailed": "Terjadi kesalahan saat mencoba melakukan permintaan yang diautentikasi. Silakan coba logout dan login kembali jika kesalahan ini berlanjut.",
38 "infobar.buttonChangelog": "Yang baru", 44 "infobar.buttonChangelog": "Yang baru",
39 "infobar.buttonInstallUpdate": "Mulai ulang & instal pembaruan", 45 "infobar.buttonInstallUpdate": "Mulai ulang & instal pembaruan",
40 "infobar.buttonReloadServices": "Muat ulang layanan", 46 "infobar.buttonReloadServices": "Muat ulang layanan",
@@ -42,6 +48,7 @@
42 "infobar.requiredRequestsFailed": "Gagal memuat layanan dan informasi pengguna", 48 "infobar.requiredRequestsFailed": "Gagal memuat layanan dan informasi pengguna",
43 "infobar.servicesUpdated": "Layanan Anda telah diperbarui.", 49 "infobar.servicesUpdated": "Layanan Anda telah diperbarui.",
44 "infobar.updateAvailable": "Versi baru Ferdium tersedia.", 50 "infobar.updateAvailable": "Versi baru Ferdium tersedia.",
51 "infobox.dismiss": "Menolak",
45 "invite.email.label": "Alamat email", 52 "invite.email.label": "Alamat email",
46 "invite.headline.friends": "Undang 3 teman atau kolega Anda", 53 "invite.headline.friends": "Undang 3 teman atau kolega Anda",
47 "invite.name.label": "Nama", 54 "invite.name.label": "Nama",
@@ -93,18 +100,29 @@
93 "menu.file": "Berkas", 100 "menu.file": "Berkas",
94 "menu.help": "Bantuan", 101 "menu.help": "Bantuan",
95 "menu.help.changelog": "Log Perubahan", 102 "menu.help.changelog": "Log Perubahan",
103 "menu.help.debugInfo": "Salin Informasi Debug",
104 "menu.help.debugInfoCopiedBody": "Informasi Debug Anda telah disalin ke clipboard Anda.",
105 "menu.help.debugInfoCopiedHeadline": "Informasi Debug Ferdium",
106 "menu.help.importExportData": "Impor/Ekspor Data Konfigurasi",
96 "menu.help.learnMore": "Pelajari Lebih Lanjut", 107 "menu.help.learnMore": "Pelajari Lebih Lanjut",
97 "menu.help.privacy": "Pernyataan Privasi", 108 "menu.help.privacy": "Pernyataan Privasi",
109 "menu.help.publishDebugInfo": "Publikasikan Informasi Debug",
98 "menu.help.support": "Dukungan", 110 "menu.help.support": "Dukungan",
99 "menu.help.tos": "Ketentuan Layanan", 111 "menu.help.tos": "Ketentuan Layanan",
100 "menu.services": "Layanan", 112 "menu.services": "Layanan",
101 "menu.services.activatePreviousService": "Aktifkan layanan sebelumnya", 113 "menu.services.activatePreviousService": "Aktifkan layanan sebelumnya",
102 "menu.services.addNewService": "Tambahkan Layanan Baru...", 114 "menu.services.addNewService": "Tambahkan Layanan Baru...",
115 "menu.services.copyToClipboard": "Salin ke clipboard",
116 "menu.services.goHome": "Beranda",
103 "menu.services.setNextServiceActive": "Aktifkan layanan berikutnya", 117 "menu.services.setNextServiceActive": "Aktifkan layanan berikutnya",
104 "menu.view": "Tampilan", 118 "menu.view": "Tampilan",
119 "menu.view.back": "Kembali",
120 "menu.view.forward": "Maju",
121 "menu.view.lockFerdium": "Kunci Ferdium",
105 "menu.view.reloadFerdium": "Muat Ulang Ferdium", 122 "menu.view.reloadFerdium": "Muat Ulang Ferdium",
106 "menu.view.reloadService": "Muat ulang Layanan", 123 "menu.view.reloadService": "Muat ulang Layanan",
107 "menu.view.resetZoom": "Ukuran Sebenarnya", 124 "menu.view.resetZoom": "Ukuran Sebenarnya",
125 "menu.view.toggleDarkMode": "Aktifkan Mode Gelap",
108 "menu.view.toggleDevTools": "Aktif/Nonaktifkan alat pengembang", 126 "menu.view.toggleDevTools": "Aktif/Nonaktifkan alat pengembang",
109 "menu.view.toggleFullScreen": "Aktif/Nonaktifkan Layar Penuh", 127 "menu.view.toggleFullScreen": "Aktif/Nonaktifkan Layar Penuh",
110 "menu.view.toggleServiceDevTools": "Aktif/Nonaktifkan layanan alat pengembang", 128 "menu.view.toggleServiceDevTools": "Aktif/Nonaktifkan layanan alat pengembang",
@@ -123,6 +141,7 @@
123 "password.link.login": "Masuk ke akun Anda", 141 "password.link.login": "Masuk ke akun Anda",
124 "password.link.signup": "Buat akun gratis", 142 "password.link.signup": "Buat akun gratis",
125 "password.noUser": "Tidak ditemukan pengguna dengan email tersebut", 143 "password.noUser": "Tidak ditemukan pengguna dengan email tersebut",
144 "password.successInfo": "Kata sandi baru Anda telah dikirim ke alamat email Anda",
126 "service.crashHandler.action": "Muat Ulang {name}", 145 "service.crashHandler.action": "Muat Ulang {name}",
127 "service.crashHandler.autoReload": "Mencoba memulihkan {name} secara otomatis dalam {seconds} detik", 146 "service.crashHandler.autoReload": "Mencoba memulihkan {name} secara otomatis dalam {seconds} detik",
128 "service.crashHandler.headline": "Ya Ampun!", 147 "service.crashHandler.headline": "Ya Ampun!",
@@ -130,11 +149,18 @@
130 "service.disabledHandler.action": "Aktifkan {name}", 149 "service.disabledHandler.action": "Aktifkan {name}",
131 "service.disabledHandler.headline": "{name} dinonaktifkan", 150 "service.disabledHandler.headline": "{name} dinonaktifkan",
132 "service.errorHandler.action": "Muat Ulang {name}", 151 "service.errorHandler.action": "Muat Ulang {name}",
152 "service.errorHandler.editAction": "Edit {name}",
133 "service.errorHandler.headline": "Ya Ampun!", 153 "service.errorHandler.headline": "Ya Ampun!",
134 "service.errorHandler.message": "Kesalahan", 154 "service.errorHandler.message": "Kesalahan",
135 "service.errorHandler.text": "{name} gagal dimuat", 155 "service.errorHandler.text": "{name} gagal dimuat",
156 "service.webviewLoader.loading": "Memuat {service}",
136 "services.getStarted": "Memulai", 157 "services.getStarted": "Memulai",
158 "services.login": "Silahkan login untuk menggunakan Ferdium.",
159 "services.serverInfo": "Sebagai pilihan, Anda dapat mengubah server Ferdium dengan mengeklik roda gigi di pojok kiri bawah. Jika Anda beralih (dari salah satu server yang dihosting) untuk menggunakan Ferdium tanpa akun, mohon diperhatikan bahwa Anda dapat mengekspor data Anda dari server itu dan kemudian mengimpornya menggunakan menu Bantuan untuk menggunakan kembali semua ruang kerja dan layanan yang dikonfigurasi!",
160 "services.serverless": "Gunakan Ferdium tanpa Akun",
137 "settings.account.account.editButton": "Edit akun", 161 "settings.account.account.editButton": "Edit akun",
162 "settings.account.accountUnavailable": "Akun tidak tersedia",
163 "settings.account.accountUnavailableInfo": "Anda menggunakan Ferdium tanpa akun. Jika Anda ingin menggunakan Ferdium dengan akun dan menjaga layanan Anda tetap tersinkronisasi di seluruh instalasi, silahkan pilih server di tab Pengaturan lalu login.",
138 "settings.account.buttonSave": "Perbarui profil", 164 "settings.account.buttonSave": "Perbarui profil",
139 "settings.account.deleteAccount": "Hapus akun", 165 "settings.account.deleteAccount": "Hapus akun",
140 "settings.account.deleteEmailSent": "Anda menerima email dengan tautan untuk mengonfirmasi penghapusan akun. Akun dan data Anda tidak bisa dipulihkan!", 166 "settings.account.deleteEmailSent": "Anda menerima email dengan tautan untuk mengonfirmasi penghapusan akun. Akun dan data Anda tidak bisa dipulihkan!",
@@ -149,12 +175,26 @@
149 "settings.account.tryReloadServices": "Coba lagi", 175 "settings.account.tryReloadServices": "Coba lagi",
150 "settings.account.tryReloadUserInfoRequest": "Coba lagi", 176 "settings.account.tryReloadUserInfoRequest": "Coba lagi",
151 "settings.account.userInfoRequestFailed": "Gagal memuat informasi pengguna", 177 "settings.account.userInfoRequestFailed": "Gagal memuat informasi pengguna",
178 "settings.account.yourLicense": "Lisensi Ferdium Anda:",
179 "settings.app.accentColorInfo": "Tulis pilihan warna Anda dalam format yang kompatibel dengan CSS. (Default: {defaultAccentColor} atau kosongkan kolom input)",
152 "settings.app.buttonInstallUpdate": "Mulai ulang & instal pembaruan", 180 "settings.app.buttonInstallUpdate": "Mulai ulang & instal pembaruan",
181 "settings.app.buttonOpenFerdiumCertsFolder": "Buka folder sertifikat",
182 "settings.app.buttonOpenFerdiumProfileFolder": "Buka folder Profil",
183 "settings.app.buttonOpenImportExport": "Impor / Ekspor",
153 "settings.app.buttonSearchForUpdate": "Periksa versi baru", 184 "settings.app.buttonSearchForUpdate": "Periksa versi baru",
185 "settings.app.buttonShowChangelog": "Tampilkan daftar perubahan",
154 "settings.app.cacheInfo": "Singgahan Ferdium sedang menggunakan ruang disk {size}.", 186 "settings.app.cacheInfo": "Singgahan Ferdium sedang menggunakan ruang disk {size}.",
187 "settings.app.cacheNotCleared": "Tidak dapat menghapus semua cache",
188 "settings.app.closeSettings": "Tutup pengaturan",
155 "settings.app.currentVersion": "Versi saat ini:", 189 "settings.app.currentVersion": "Versi saat ini:",
190 "settings.app.form.accentColor": "Warna aksen",
191 "settings.app.form.adaptableDarkMode": "Sinkronkan mode gelap dengan pengaturan mode gelap OS saya",
192 "settings.app.form.alwaysShowWorkspaces": "Selalu tampilkan laci ruang kerja",
156 "settings.app.form.autoLaunchInBackground": "Buka di latar belakang", 193 "settings.app.form.autoLaunchInBackground": "Buka di latar belakang",
157 "settings.app.form.autoLaunchOnStart": "Jalankan Ferdium saat komputer dimulai", 194 "settings.app.form.autoLaunchOnStart": "Jalankan Ferdium saat komputer dimulai",
195 "settings.app.form.automaticUpdates": "Aktifkan pembaruan",
196 "settings.app.form.beta": "Sertakan pra-rilis",
197 "settings.app.form.confirmOnQuit": "Konfirmasikan saat keluar dari Ferdium",
158 "settings.app.form.darkMode": "Aktifkan Mode Gelap", 198 "settings.app.form.darkMode": "Aktifkan Mode Gelap",
159 "settings.app.form.enableGPUAcceleration": "Aktifkan Akselerasi GPU", 199 "settings.app.form.enableGPUAcceleration": "Aktifkan Akselerasi GPU",
160 "settings.app.form.enableLock": "Aktifkan Kunci Kata Sandi", 200 "settings.app.form.enableLock": "Aktifkan Kunci Kata Sandi",
diff --git a/src/i18n/locales/ja.json b/src/i18n/locales/ja.json
index ed2c60736..b9bf4def7 100644
--- a/src/i18n/locales/ja.json
+++ b/src/i18n/locales/ja.json
@@ -296,6 +296,7 @@
296 "settings.app.sectionUpdates": "アプリのアップデート設定", 296 "settings.app.sectionUpdates": "アプリのアップデート設定",
297 "settings.app.sentryInfo": "統計情報を送信すると開発者がFerdiumのエラーを発見するのに役立ちます。メッセージのデータのような個人情報は一切送信しません。", 297 "settings.app.sentryInfo": "統計情報を送信すると開発者がFerdiumのエラーを発見するのに役立ちます。メッセージのデータのような個人情報は一切送信しません。",
298 "settings.app.serverHelp": "{serverURL}でサーバーに接続しました", 298 "settings.app.serverHelp": "{serverURL}でサーバーに接続しました",
299 "settings.app.servicesUpdateStatusUpToDate": "サービスは最新です",
299 "settings.app.spellCheckerLanguageInfo": "FerdiumはスペルチェックにmacOSシステムのスペルチェッカーを使用しています。スペルチェッカーでチェックする言語を変更するには、macOSのシステム環境設定から行ってください。", 300 "settings.app.spellCheckerLanguageInfo": "FerdiumはスペルチェックにmacOSシステムのスペルチェッカーを使用しています。スペルチェッカーでチェックする言語を変更するには、macOSのシステム環境設定から行ってください。",
300 "settings.app.subheadlineCache": "キャッシュ", 301 "settings.app.subheadlineCache": "キャッシュ",
301 "settings.app.subheadlineFerdiumProfile": "Ferdiumプロフィール", 302 "settings.app.subheadlineFerdiumProfile": "Ferdiumプロフィール",
diff --git a/src/i18n/locales/ru.json b/src/i18n/locales/ru.json
index 110341565..317b1eda2 100644
--- a/src/i18n/locales/ru.json
+++ b/src/i18n/locales/ru.json
@@ -9,6 +9,8 @@
9 "connectionLostBanner.cta": "Перезапустить сервис", 9 "connectionLostBanner.cta": "Перезапустить сервис",
10 "connectionLostBanner.informationLink": "Что случилось?", 10 "connectionLostBanner.informationLink": "Что случилось?",
11 "connectionLostBanner.message": "О нет! Ferdium потерял связь с {name}.", 11 "connectionLostBanner.message": "О нет! Ferdium потерял связь с {name}.",
12 "downloadManager.empty": "Ваш список загрузок пуст.",
13 "downloadManager.headline": "Менеджер загрузок",
12 "feature.basicAuth.signIn": "Войти", 14 "feature.basicAuth.signIn": "Войти",
13 "feature.publishDebugInfo.error": "При попытке опубликовать отладочную информацию произошла ошибка. Пожалуйста, повторите попытку позже или просмотрите консоль для получения дополнительной информации.", 15 "feature.publishDebugInfo.error": "При попытке опубликовать отладочную информацию произошла ошибка. Пожалуйста, повторите попытку позже или просмотрите консоль для получения дополнительной информации.",
14 "feature.publishDebugInfo.info": "Публикация вашей отладочной информации помогает нам найти проблемы и ошибки в Ferdium. Публикуя вашу отладочную информацию, вы принимаете политику конфиденциальности Ferdium Debugger'ов и условия предоставления услуг", 16 "feature.publishDebugInfo.info": "Публикация вашей отладочной информации помогает нам найти проблемы и ошибки в Ferdium. Публикуя вашу отладочную информацию, вы принимаете политику конфиденциальности Ferdium Debugger'ов и условия предоставления услуг",
@@ -20,10 +22,14 @@
20 "feature.quickSwitch.info": "Выберите сервис с Tab, вверх и вниз. Откройте сервис нажав на ENTER.", 22 "feature.quickSwitch.info": "Выберите сервис с Tab, вверх и вниз. Откройте сервис нажав на ENTER.",
21 "feature.quickSwitch.search": "Поиск...", 23 "feature.quickSwitch.search": "Поиск...",
22 "feature.quickSwitch.title": "Быстрое переключение", 24 "feature.quickSwitch.title": "Быстрое переключение",
25 "global.api.unhealthy": "Не удается подключиться к онлайн-сервисам {serverNameParse}",
23 "global.cancel": "Отмена", 26 "global.cancel": "Отмена",
27 "global.clearCache": "Очистить кэш",
28 "global.downloads": "Загрузки",
24 "global.edit": "Правка", 29 "global.edit": "Правка",
25 "global.no": "Нет", 30 "global.no": "Нет",
26 "global.notConnectedToTheInternet": "Вы не подключены к сети Интернет.", 31 "global.notConnectedToTheInternet": "Вы не подключены к сети Интернет.",
32 "global.ok": "Ok",
27 "global.quit": "Выйти", 33 "global.quit": "Выйти",
28 "global.quitConfirmation": "Вы действительно хотите выйти из Ferdium?", 34 "global.quitConfirmation": "Вы действительно хотите выйти из Ferdium?",
29 "global.save": "Сохранить", 35 "global.save": "Сохранить",
@@ -57,6 +63,7 @@
57 "locked.submit.label": "Разблокировать", 63 "locked.submit.label": "Разблокировать",
58 "locked.touchId": "Разблокировать с Touch ID", 64 "locked.touchId": "Разблокировать с Touch ID",
59 "locked.unlockWithPassword": "Разблокировать паролем", 65 "locked.unlockWithPassword": "Разблокировать паролем",
66 "login.customServerQuestion": "Использовать пользовательский сервер Ferdium?",
60 "login.email.label": "Адрес электронной почты", 67 "login.email.label": "Адрес электронной почты",
61 "login.headline": "Вход", 68 "login.headline": "Вход",
62 "login.invalidCredentials": "Неправильный адрес электронной почты или пароль", 69 "login.invalidCredentials": "Неправильный адрес электронной почты или пароль",
@@ -104,9 +111,11 @@
104 "menu.services": "Сервис", 111 "menu.services": "Сервис",
105 "menu.services.activatePreviousService": "Активировать предыдущий сервис", 112 "menu.services.activatePreviousService": "Активировать предыдущий сервис",
106 "menu.services.addNewService": "Добавить новый сервис...", 113 "menu.services.addNewService": "Добавить новый сервис...",
114 "menu.services.copyToClipboard": "Копировать в буфер обмена",
107 "menu.services.goHome": "Домой", 115 "menu.services.goHome": "Домой",
108 "menu.services.setNextServiceActive": "Активировать следующий сервис", 116 "menu.services.setNextServiceActive": "Активировать следующий сервис",
109 "menu.todos": "Задачи", 117 "menu.todos": "Задачи",
118 "menu.todos.disableTodos": "Отключить задачи",
110 "menu.todos.enableTodos": "Включить задачи", 119 "menu.todos.enableTodos": "Включить задачи",
111 "menu.view": "Вид", 120 "menu.view": "Вид",
112 "menu.view.back": "Назад", 121 "menu.view.back": "Назад",
@@ -175,7 +184,9 @@
175 "settings.app.buttonInstallUpdate": "Перезапустить и установить обновления", 184 "settings.app.buttonInstallUpdate": "Перезапустить и установить обновления",
176 "settings.app.buttonOpenFerdiumProfileFolder": "Открыть папку профиля", 185 "settings.app.buttonOpenFerdiumProfileFolder": "Открыть папку профиля",
177 "settings.app.buttonOpenFerdiumServiceRecipesFolder": "Открыть папку сервисных протоколов", 186 "settings.app.buttonOpenFerdiumServiceRecipesFolder": "Открыть папку сервисных протоколов",
187 "settings.app.buttonOpenImportExport": "Импорт / Экспорт",
178 "settings.app.buttonSearchForUpdate": "Проверить обновления", 188 "settings.app.buttonSearchForUpdate": "Проверить обновления",
189 "settings.app.buttonShowChangelog": "Показать историю изменений",
179 "settings.app.cacheInfo": "Кэш занимает {size} на диске.", 190 "settings.app.cacheInfo": "Кэш занимает {size} на диске.",
180 "settings.app.cacheNotCleared": "Не удалось очистить весь кэш", 191 "settings.app.cacheNotCleared": "Не удалось очистить весь кэш",
181 "settings.app.closeSettings": "Закрыть настройки", 192 "settings.app.closeSettings": "Закрыть настройки",
@@ -202,6 +213,9 @@
202 "settings.app.form.enableTodos": "Включить задания Ferdium", 213 "settings.app.form.enableTodos": "Включить задания Ferdium",
203 "settings.app.form.hibernateOnStartup": "Оставлять сервисы в состоянии глубокого сна во время запуска", 214 "settings.app.form.hibernateOnStartup": "Оставлять сервисы в состоянии глубокого сна во время запуска",
204 "settings.app.form.hibernationStrategy": "Стратегия гибернации", 215 "settings.app.form.hibernationStrategy": "Стратегия гибернации",
216 "settings.app.form.hideDownloadButton": "Скрыть кнопку \"Загрузки\"",
217 "settings.app.form.hideNotificationsButton": "Скрыть кнопки уведомлений и звука",
218 "settings.app.form.hideSettingsButton": "Скрыть кнопку настроек",
205 "settings.app.form.iconSize": "Размер иконки сервиса", 219 "settings.app.form.iconSize": "Размер иконки сервиса",
206 "settings.app.form.inactivityLock": "Заблокировать после бездействия", 220 "settings.app.form.inactivityLock": "Заблокировать после бездействия",
207 "settings.app.form.keepAllWorkspacesLoaded": "Сохранить все рабочие окружения загруженными", 221 "settings.app.form.keepAllWorkspacesLoaded": "Сохранить все рабочие окружения загруженными",
@@ -219,6 +233,7 @@
219 "settings.app.form.scheduledDNDEnd": "Кому", 233 "settings.app.form.scheduledDNDEnd": "Кому",
220 "settings.app.form.scheduledDNDStart": "От", 234 "settings.app.form.scheduledDNDStart": "От",
221 "settings.app.form.searchEngine": "Поисковая система", 235 "settings.app.form.searchEngine": "Поисковая система",
236 "settings.app.form.sentry": "Отправить данные телеметрии",
222 "settings.app.form.serviceRibbonWidth": "Ширина боковой панели", 237 "settings.app.form.serviceRibbonWidth": "Ширина боковой панели",
223 "settings.app.form.showDisabledServices": "Показывать вкладки отключённых служб", 238 "settings.app.form.showDisabledServices": "Показывать вкладки отключённых служб",
224 "settings.app.form.showDragArea": "Показать перетаскиваемую область в окне", 239 "settings.app.form.showDragArea": "Показать перетаскиваемую область в окне",
@@ -246,6 +261,11 @@
246 "settings.app.restartRequired": "Изменения требуют перезагрузки приложения", 261 "settings.app.restartRequired": "Изменения требуют перезагрузки приложения",
247 "settings.app.scheduledDNDInfo": "Запланированный режим \"не беспокоить\" позволяет вам определить период времени, в течение которого вы не желаете получать уведомления от Ferdium.", 262 "settings.app.scheduledDNDInfo": "Запланированный режим \"не беспокоить\" позволяет вам определить период времени, в течение которого вы не желаете получать уведомления от Ferdium.",
248 "settings.app.scheduledDNDTimeInfo": "Время в 24-часовом формате. Время окончания может быть раньше времени начала (например, начало 17:00, конец 09:00), чтобы включить ночной режим \"не беспокоить\".", 263 "settings.app.scheduledDNDTimeInfo": "Время в 24-часовом формате. Время окончания может быть раньше времени начала (например, начало 17:00, конец 09:00), чтобы включить ночной режим \"не беспокоить\".",
264 "settings.app.sectionLanguage": "Настройка языка",
265 "settings.app.sectionUpdates": "Настройки обновления приложения",
266 "settings.app.sentryInfo": "Отправка телеметрии позволяет нам находить ошибки в Ferdium - мы не будем отправлять никакой личной информации, включая ваши сообщения!",
267 "settings.app.serverHelp": "Подключен к серверу {serverURL}",
268 "settings.app.servicesUpdateStatusUpToDate": "Ваши сервисы актуальны",
249 "settings.app.spellCheckerLanguageInfo": "Ferdium использует встроенную проверку орфографии вашего устройства. Если вы желаете изменить язык проверки орфографии, вы можете произвести это в системных настройках вашего устройства.", 269 "settings.app.spellCheckerLanguageInfo": "Ferdium использует встроенную проверку орфографии вашего устройства. Если вы желаете изменить язык проверки орфографии, вы можете произвести это в системных настройках вашего устройства.",
250 "settings.app.subheadlineCache": "Кэш", 270 "settings.app.subheadlineCache": "Кэш",
251 "settings.app.subheadlineFerdiumProfile": "Профиль Ferdium", 271 "settings.app.subheadlineFerdiumProfile": "Профиль Ferdium",
@@ -255,10 +275,12 @@
255 "settings.app.updateStatusAvailable": "Доступно обновление, идёт загрузка...", 275 "settings.app.updateStatusAvailable": "Доступно обновление, идёт загрузка...",
256 "settings.app.updateStatusSearching": "Поиск обновлений...", 276 "settings.app.updateStatusSearching": "Поиск обновлений...",
257 "settings.app.updateStatusUpToDate": "Вы используете актуальную версию Ferdium", 277 "settings.app.updateStatusUpToDate": "Вы используете актуальную версию Ferdium",
278 "settings.app.warningSelfSignedCertificates": "ВНИМАНИЕ: Включите эту функцию, только если вы знаете, что делаете. Включение этой опции представляет собой угрозу безопасности и должно использоваться только в целях тестирования.",
258 "settings.invite.headline": "Пригласить друзей", 279 "settings.invite.headline": "Пригласить друзей",
259 "settings.navigation.account": "Учетная запись", 280 "settings.navigation.account": "Учетная запись",
260 "settings.navigation.availableServices": "Доступные сервисы", 281 "settings.navigation.availableServices": "Доступные сервисы",
261 "settings.navigation.logout": "Выход", 282 "settings.navigation.logout": "Выход",
283 "settings.navigation.releaseNotes": "Информация о выпуске",
262 "settings.navigation.supportFerdium": "О Ferdium", 284 "settings.navigation.supportFerdium": "О Ferdium",
263 "settings.navigation.team": "Управление Командой", 285 "settings.navigation.team": "Управление Командой",
264 "settings.navigation.yourServices": "Ваши сервисы", 286 "settings.navigation.yourServices": "Ваши сервисы",
@@ -275,6 +297,7 @@
275 "settings.recipes.missingService": "Не можете найти сервис?", 297 "settings.recipes.missingService": "Не можете найти сервис?",
276 "settings.recipes.nothingFound": "Извините, но сервис не соответствует вашему поисковому запросу - но вы все еще можете добавить его, используя опцию \"Пользовательский сайт\". Пожалуйста, обратите внимание, что на сайте может отображаться больше служб, которые могли быть добавлены в новых версиях Ferdium. Для получения новых сервисов, пожалуйста, обновите Ferdium до актуальной версии.", 298 "settings.recipes.nothingFound": "Извините, но сервис не соответствует вашему поисковому запросу - но вы все еще можете добавить его, используя опцию \"Пользовательский сайт\". Пожалуйста, обратите внимание, что на сайте может отображаться больше служб, которые могли быть добавлены в новых версиях Ferdium. Для получения новых сервисов, пожалуйста, обновите Ferdium до актуальной версии.",
277 "settings.recipes.servicesSuccessfulAddedInfo": "Сервис успешно добавлен", 299 "settings.recipes.servicesSuccessfulAddedInfo": "Сервис успешно добавлен",
300 "settings.releasenotes.headline": "Информация о выпуске",
278 "settings.searchService": "Найти сервис", 301 "settings.searchService": "Найти сервис",
279 "settings.service.error.goBack": "Вернуться к сервисам", 302 "settings.service.error.goBack": "Вернуться к сервисам",
280 "settings.service.error.headline": "Ошибка", 303 "settings.service.error.headline": "Ошибка",
@@ -306,6 +329,8 @@
306 "settings.service.form.indirectMessages": "Показывать значок уведомлений для всех новых сообщений", 329 "settings.service.form.indirectMessages": "Показывать значок уведомлений для всех новых сообщений",
307 "settings.service.form.isHibernatedEnabledInfo": "Когда включено, служба будет отключена по истечении времени, чтобы сохранить системные ресурсы.", 330 "settings.service.form.isHibernatedEnabledInfo": "Когда включено, служба будет отключена по истечении времени, чтобы сохранить системные ресурсы.",
308 "settings.service.form.isMutedInfo": "Когда выключено, все звуковые уведомления будут отключены", 331 "settings.service.form.isMutedInfo": "Когда выключено, все звуковые уведомления будут отключены",
332 "settings.service.form.maxFileSize": "Максимальный размер файла:",
333 "settings.service.form.maxFileSizeError": "Файл, который вы пытаетесь отправить, слишком большой.",
309 "settings.service.form.name": "Имя", 334 "settings.service.form.name": "Имя",
310 "settings.service.form.onlyShowFavoritesInUnreadCount": "Отображение только \"Избранного\" в количестве непрочитанного", 335 "settings.service.form.onlyShowFavoritesInUnreadCount": "Отображение только \"Избранного\" в количестве непрочитанного",
311 "settings.service.form.openDarkmodeCss": "Открыть darkmode.css", 336 "settings.service.form.openDarkmodeCss": "Открыть darkmode.css",
@@ -326,6 +351,7 @@
326 "settings.service.form.team": "Команда", 351 "settings.service.form.team": "Команда",
327 "settings.service.form.useHostedService": "Использовать собственный сервис {name}.", 352 "settings.service.form.useHostedService": "Использовать собственный сервис {name}.",
328 "settings.service.form.yourServices": "Ваши сервисы", 353 "settings.service.form.yourServices": "Ваши сервисы",
354 "settings.service.reloadRequired": "Изменения требуют перезагрузки службы",
329 "settings.services.deletedInfo": "Сервис был удален", 355 "settings.services.deletedInfo": "Сервис был удален",
330 "settings.services.discoverServices": "Найти сервисы", 356 "settings.services.discoverServices": "Найти сервисы",
331 "settings.services.headline": "Ваши сервисы", 357 "settings.services.headline": "Ваши сервисы",
@@ -346,6 +372,7 @@
346 "settings.team.manageAction": "Управляйте вашей командой на meetfranz.com", 372 "settings.team.manageAction": "Управляйте вашей командой на meetfranz.com",
347 "settings.team.teamsUnavailable": "Команды недоступны", 373 "settings.team.teamsUnavailable": "Команды недоступны",
348 "settings.team.teamsUnavailableInfo": "Команды на текущий момент доступны только при использовании сервера Franz и после приобретения Franz Professional. Пожалуйста, измените Ваш сервер на https://api.franzinfra.com для использования Teams.", 374 "settings.team.teamsUnavailableInfo": "Команды на текущий момент доступны только при использовании сервера Franz и после приобретения Franz Professional. Пожалуйста, измените Ваш сервер на https://api.franzinfra.com для использования Teams.",
375 "settings.team.tryReloadUserInfoRequest": "Попробуйте перезагрузить",
349 "settings.user.form.accountType.company": "Компания", 376 "settings.user.form.accountType.company": "Компания",
350 "settings.user.form.accountType.individual": "Индивидуальный", 377 "settings.user.form.accountType.individual": "Индивидуальный",
351 "settings.user.form.accountType.label": "Тип аккаунта", 378 "settings.user.form.accountType.label": "Тип аккаунта",
@@ -377,6 +404,7 @@
377 "setupAssistant.submit.label": "Начнем", 404 "setupAssistant.submit.label": "Начнем",
378 "sidebar.muteApp": "Отключить уведомления и звук", 405 "sidebar.muteApp": "Отключить уведомления и звук",
379 "sidebar.unmuteApp": "Включить уведомления и звук", 406 "sidebar.unmuteApp": "Включить уведомления и звук",
407 "signup.company.label": "Компания",
380 "signup.email.label": "Адрес электронной почты", 408 "signup.email.label": "Адрес электронной почты",
381 "signup.emailDuplicate": "Пользователь с таким адресом электронной почты уже существует", 409 "signup.emailDuplicate": "Пользователь с таким адресом электронной почты уже существует",
382 "signup.firstname.label": "Имя", 410 "signup.firstname.label": "Имя",
diff --git a/src/i18n/locales/zh-HANS.json b/src/i18n/locales/zh-HANS.json
index 8aa0e15f6..ab76b9141 100644
--- a/src/i18n/locales/zh-HANS.json
+++ b/src/i18n/locales/zh-HANS.json
@@ -9,6 +9,8 @@
9 "connectionLostBanner.cta": "重启服务", 9 "connectionLostBanner.cta": "重启服务",
10 "connectionLostBanner.informationLink": "发生了什么?", 10 "connectionLostBanner.informationLink": "发生了什么?",
11 "connectionLostBanner.message": "不好!Ferdium失去了与 {name} 的连接。", 11 "connectionLostBanner.message": "不好!Ferdium失去了与 {name} 的连接。",
12 "downloadManager.empty": "您的下载列表是空的。",
13 "downloadManager.headline": "下载管理器",
12 "feature.basicAuth.signIn": "登入", 14 "feature.basicAuth.signIn": "登入",
13 "feature.publishDebugInfo.error": "试图发布调试信息时出错。请稍后再试或查看控制台以获取更多信息。", 15 "feature.publishDebugInfo.error": "试图发布调试信息时出错。请稍后再试或查看控制台以获取更多信息。",
14 "feature.publishDebugInfo.info": "发布您的调试信息有助于我们在 Ferdium 中找到问题和错误。 通过发布您的调试信息,您接受 Ferdium 调试器的隐私政策和服务条款", 16 "feature.publishDebugInfo.info": "发布您的调试信息有助于我们在 Ferdium 中找到问题和错误。 通过发布您的调试信息,您接受 Ferdium 调试器的隐私政策和服务条款",
@@ -22,6 +24,8 @@
22 "feature.quickSwitch.title": "快速切换", 24 "feature.quickSwitch.title": "快速切换",
23 "global.api.unhealthy": "无法连接 {serverNameParse} 在线服务", 25 "global.api.unhealthy": "无法连接 {serverNameParse} 在线服务",
24 "global.cancel": "取消", 26 "global.cancel": "取消",
27 "global.clearCache": "清除缓存",
28 "global.downloads": "下载",
25 "global.edit": "编辑", 29 "global.edit": "编辑",
26 "global.no": "否", 30 "global.no": "否",
27 "global.notConnectedToTheInternet": "没有网络服务", 31 "global.notConnectedToTheInternet": "没有网络服务",
@@ -218,6 +222,7 @@
218 "settings.app.form.hibernateOnStartup": "启动时保持休眠服务", 222 "settings.app.form.hibernateOnStartup": "启动时保持休眠服务",
219 "settings.app.form.hibernationStrategy": "休眠策略", 223 "settings.app.form.hibernationStrategy": "休眠策略",
220 "settings.app.form.hideCollapseButton": "隐藏折叠按钮", 224 "settings.app.form.hideCollapseButton": "隐藏折叠按钮",
225 "settings.app.form.hideDownloadButton": "隐藏下载按钮",
221 "settings.app.form.hideNotificationsButton": "隐藏通知和声音按钮", 226 "settings.app.form.hideNotificationsButton": "隐藏通知和声音按钮",
222 "settings.app.form.hideRecipesButton": "隐藏配方按钮", 227 "settings.app.form.hideRecipesButton": "隐藏配方按钮",
223 "settings.app.form.hideSettingsButton": "隐藏设置按钮", 228 "settings.app.form.hideSettingsButton": "隐藏设置按钮",
@@ -271,6 +276,8 @@
271 "settings.app.headlineUpdates": "更新", 276 "settings.app.headlineUpdates": "更新",
272 "settings.app.hibernateInfo": "默认情况下,Ferdium将保持您所有的服务在后台打开并加载,这样当您想要使用它们时他们就可以了。 服务休眠将在指定数量后卸载您的服务。这有助于保存内存或保持服务以减慢您的计算机速度。", 277 "settings.app.hibernateInfo": "默认情况下,Ferdium将保持您所有的服务在后台打开并加载,这样当您想要使用它们时他们就可以了。 服务休眠将在指定数量后卸载您的服务。这有助于保存内存或保持服务以减慢您的计算机速度。",
273 "settings.app.inactivityLockInfo": "停止活动的分钟,然后Ferdium将自动锁定。使用 0 禁用。", 278 "settings.app.inactivityLockInfo": "停止活动的分钟,然后Ferdium将自动锁定。使用 0 禁用。",
279 "settings.app.lockInfo": "密码锁可以使您的消息受到保护。\n\n使用密码锁,每当您启动Ferdium或使用锁定符号 {lockShortcut} 在左下角或快捷键中锁定Ferdium时,都会提示您输入密码。",
280 "settings.app.lockedPassword": "密码",
274 "settings.app.restartRequired": "重启后生效", 281 "settings.app.restartRequired": "重启后生效",
275 "settings.app.subheadlineCache": "缓存", 282 "settings.app.subheadlineCache": "缓存",
276 "settings.app.translationHelp": "帮助我们将Ferdium翻译至您的语言。", 283 "settings.app.translationHelp": "帮助我们将Ferdium翻译至您的语言。",
diff --git a/src/index.ts b/src/index.ts
index e466b4ab1..fe254b4f6 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -50,6 +50,7 @@ import { openExternalUrl } from './helpers/url-helpers';
50import userAgent from './helpers/userAgent-helpers'; 50import userAgent from './helpers/userAgent-helpers';
51import { translateTo } from './helpers/translation-helpers'; 51import { translateTo } from './helpers/translation-helpers';
52import { darkThemeGrayDarkest } from './themes/legacy'; 52import { darkThemeGrayDarkest } from './themes/legacy';
53import { checkIfCertIsPresent } from './helpers/certs-helpers';
53 54
54const debug = require('./preload-safe-debug')('Ferdium:App'); 55const debug = require('./preload-safe-debug')('Ferdium:App');
55 56
@@ -752,3 +753,26 @@ app.on('will-finish-launching', () => {
752 }); 753 });
753 }); 754 });
754}); 755});
756
757app.on(
758 'certificate-error',
759 (event, _webContents, _url, _error, certificate, callback) => {
760 // On certificate error we disable default behaviour (stop loading the page)
761 // and we then say "it is all fine - true" to the callback
762 event.preventDefault();
763
764 const useSelfSignedCertificates =
765 retrieveSettingValue(
766 'useSelfSignedCertificates',
767 DEFAULT_APP_SETTINGS.useSelfSignedCertificates,
768 ) === true;
769
770 // Check if the certificate is trusted
771 if (!useSelfSignedCertificates) {
772 callback(false);
773 return;
774 }
775
776 callback(checkIfCertIsPresent(certificate.data));
777 },
778);
diff --git a/src/jsUtils.ts b/src/jsUtils.ts
index 0095028ef..31d6a2121 100644
--- a/src/jsUtils.ts
+++ b/src/jsUtils.ts
@@ -30,3 +30,6 @@ export const acceleratorString = (
30 prefix: string = '(', 30 prefix: string = '(',
31 suffix: string = ')', 31 suffix: string = ')',
32) => (index <= 10 ? `${prefix}${keyCombo}+${index % 10}${suffix}` : ''); 32) => (index <= 10 ? `${prefix}${keyCombo}+${index % 10}${suffix}` : '');
33
34export const removeNewLines = (input: string): string =>
35 input.replaceAll(/\r?\n|\r/g, '');
diff --git a/src/lib/Menu.ts b/src/lib/Menu.ts
index 8ad4441d2..12dc1e42c 100644
--- a/src/lib/Menu.ts
+++ b/src/lib/Menu.ts
@@ -709,7 +709,7 @@ class FranzMenu implements StoresProps {
709 const { intl } = window['ferdium']; 709 const { intl } = window['ferdium'];
710 const locked = 710 const locked =
711 this.stores.settings.app.locked && 711 this.stores.settings.app.locked &&
712 this.stores.settings.app.lockingFeatureEnabled && 712 this.stores.settings.app.isLockingFeatureEnabled &&
713 this.stores.user.isLoggedIn; 713 this.stores.user.isLoggedIn;
714 const { actions } = this; 714 const { actions } = this;
715 const tpl = titleBarTemplateFactory(intl, locked); 715 const tpl = titleBarTemplateFactory(intl, locked);
@@ -847,7 +847,7 @@ class FranzMenu implements StoresProps {
847 accelerator: `${lockFerdiumShortcutKey()}`, 847 accelerator: `${lockFerdiumShortcutKey()}`,
848 enabled: 848 enabled:
849 this.stores.user.isLoggedIn && 849 this.stores.user.isLoggedIn &&
850 this.stores.settings.app.lockingFeatureEnabled, 850 this.stores.settings.app.isLockingFeatureEnabled,
851 click() { 851 click() {
852 actions.settings.update({ 852 actions.settings.update({
853 type: 'app', 853 type: 'app',
diff --git a/src/lib/Tray.ts b/src/lib/Tray.ts
index d83f91478..726d32b23 100644
--- a/src/lib/Tray.ts
+++ b/src/lib/Tray.ts
@@ -208,7 +208,7 @@ export default class TrayIcon {
208 if (indicator === '•') { 208 if (indicator === '•') {
209 assetFromIndicator = INDICATOR_TRAY_INDIRECT; 209 assetFromIndicator = INDICATOR_TRAY_INDIRECT;
210 } 210 }
211 if (indicator !== 0) { 211 if (indicator !== 0 && indicator !== '•') {
212 assetFromIndicator = INDICATOR_TRAY_UNREAD; 212 assetFromIndicator = INDICATOR_TRAY_UNREAD;
213 } 213 }
214 return assetFromIndicator; 214 return assetFromIndicator;
diff --git a/src/lib/dbus/Ferdium.ts b/src/lib/dbus/Ferdium.ts
index b2a9105f4..853be68e1 100644
--- a/src/lib/dbus/Ferdium.ts
+++ b/src/lib/dbus/Ferdium.ts
@@ -31,6 +31,10 @@ export default class Ferdium extends dbus.interface.Interface {
31 this.dbus.trayIcon._toggleWindow(); 31 this.dbus.trayIcon._toggleWindow();
32 } 32 }
33 33
34 ToggleToTalk(): void {
35 this.dbus.trayIcon.mainWindow?.webContents.send('toggle-to-talk');
36 }
37
34 emitUnreadChanged(): void { 38 emitUnreadChanged(): void {
35 Ferdium.emitPropertiesChanged( 39 Ferdium.emitPropertiesChanged(
36 this, 40 this,
@@ -66,6 +70,10 @@ Ferdium.configureMembers({
66 inSignature: '', 70 inSignature: '',
67 outSignature: '', 71 outSignature: '',
68 }, 72 },
73 ToggleToTalk: {
74 inSignature: '',
75 outSignature: '',
76 },
69 }, 77 },
70 properties: { 78 properties: {
71 Muted: { 79 Muted: {
diff --git a/src/models/Service.ts b/src/models/Service.ts
index b1f0bc271..da9fa43dd 100644
--- a/src/models/Service.ts
+++ b/src/models/Service.ts
@@ -641,4 +641,8 @@ export default class Service {
641 this.unreadDirectMessageCount = 0; 641 this.unreadDirectMessageCount = 0;
642 this.unreadIndirectMessageCount = 0; 642 this.unreadIndirectMessageCount = 0;
643 } 643 }
644
645 toggleToTalk(): void {
646 this.webview?.send('toggle-to-talk');
647 }
644} 648}
diff --git a/src/models/User.ts b/src/models/User.ts
index 6540a14e9..f89ea0465 100644
--- a/src/models/User.ts
+++ b/src/models/User.ts
@@ -27,8 +27,6 @@ export default class User {
27 27
28 @observable accountType: string | null = null; 28 @observable accountType: string | null = null;
29 29
30 @observable emailIsConfirmed = true;
31
32 // Note: Kept around to be able to handle the response from Franz server 30 // Note: Kept around to be able to handle the response from Franz server
33 // better assume it's confirmed to avoid noise 31 // better assume it's confirmed to avoid noise
34 @observable subscription = {}; 32 @observable subscription = {};
diff --git a/src/stores/AppStore.ts b/src/stores/AppStore.ts
index 9af0a9a4f..b8356bd56 100644
--- a/src/stores/AppStore.ts
+++ b/src/stores/AppStore.ts
@@ -121,13 +121,11 @@ export default class AppStore extends TypedStore {
121 121
122 @observable isFocused = true; 122 @observable isFocused = true;
123 123
124 @observable lockingFeatureEnabled = 124 @observable isLockingFeatureEnabled =
125 DEFAULT_APP_SETTINGS.lockingFeatureEnabled; 125 DEFAULT_APP_SETTINGS.isLockingFeatureEnabled;
126 126
127 @observable launchInBackground = DEFAULT_APP_SETTINGS.autoLaunchInBackground; 127 @observable launchInBackground = DEFAULT_APP_SETTINGS.autoLaunchInBackground;
128 128
129 dictionaries = [];
130
131 fetchDataInterval: NodeJS.Timeout | null = null; 129 fetchDataInterval: NodeJS.Timeout | null = null;
132 130
133 @observable downloads: Download[] = []; 131 @observable downloads: Download[] = [];
diff --git a/src/stores/ServicesStore.ts b/src/stores/ServicesStore.ts
index 95aae6ccb..d7804a3fe 100644
--- a/src/stores/ServicesStore.ts
+++ b/src/stores/ServicesStore.ts
@@ -1,5 +1,5 @@
1import { join } from 'node:path'; 1import { join } from 'node:path';
2import { ipcRenderer, shell } from 'electron'; 2import { clipboard, ipcRenderer, shell } from 'electron';
3import { action, reaction, computed, observable, makeObservable } from 'mobx'; 3import { action, reaction, computed, observable, makeObservable } from 'mobx';
4import { debounce, remove } from 'lodash'; 4import { debounce, remove } from 'lodash';
5import ms from 'ms'; 5import ms from 'ms';
@@ -65,6 +65,8 @@ export default class ServicesStore extends TypedStore {
65 // No service ID should be in the list multiple times, not all service IDs have to be in the list 65 // No service ID should be in the list multiple times, not all service IDs have to be in the list
66 @observable lastUsedServices: string[] = []; 66 @observable lastUsedServices: string[] = [];
67 67
68 private toggleToTalkCallback = () => this.active?.toggleToTalk();
69
68 constructor(stores: Stores, api: ApiInterface, actions: Actions) { 70 constructor(stores: Stores, api: ApiInterface, actions: Actions) {
69 super(stores, api, actions); 71 super(stores, api, actions);
70 72
@@ -239,6 +241,8 @@ export default class ServicesStore extends TypedStore {
239 initialize() { 241 initialize() {
240 super.initialize(); 242 super.initialize();
241 243
244 ipcRenderer.on('toggle-to-talk', this.toggleToTalkCallback);
245
242 // Check services to become hibernated 246 // Check services to become hibernated
243 this.serviceMaintenanceTick(); 247 this.serviceMaintenanceTick();
244 } 248 }
@@ -246,6 +250,8 @@ export default class ServicesStore extends TypedStore {
246 teardown() { 250 teardown() {
247 super.teardown(); 251 super.teardown();
248 252
253 ipcRenderer.off('toggle-to-talk', this.toggleToTalkCallback);
254
249 // Stop checking services for hibernation 255 // Stop checking services for hibernation
250 this.serviceMaintenanceTick.cancel(); 256 this.serviceMaintenanceTick.cancel();
251 } 257 }
@@ -828,6 +834,54 @@ export default class ServicesStore extends TypedStore {
828 break; 834 break;
829 } 835 }
830 case 'notification': { 836 case 'notification': {
837 const { notificationId, options } = args[0];
838
839 const { isTwoFactorAutoCatcherEnabled, twoFactorAutoCatcherMatcher } =
840 this.stores.settings.all.app;
841
842 debug(
843 'Settings for catch tokens',
844 isTwoFactorAutoCatcherEnabled,
845 twoFactorAutoCatcherMatcher,
846 );
847
848 if (isTwoFactorAutoCatcherEnabled) {
849 /*
850 parse the token digits from sms body, find "token" or "code" in options.body which reflect the sms content
851 ---
852 Token: 03624 / SMS-Code = PIN Token
853 ---
854 Prüfcode 010313 für Microsoft-Authentifizierung verwenden.
855 ---
856 483133 is your GitHub authentication code. @github.com #483133
857 ---
858 eBay: Ihr Sicherheitscode lautet 080090. \nEr läuft in 15 Minuten ab. Geben Sie den Code nicht an andere weiter.
859 ---
860 PayPal: Ihr Sicherheitscode lautet: 989605. Geben Sie diesen Code nicht weiter.
861 */
862
863 const rawBody = options.body;
864 const { 0: token } = /\d{5,6}/.exec(options.body) || [];
865
866 const wordsToCatch = twoFactorAutoCatcherMatcher
867 .replaceAll(', ', ',')
868 .split(',');
869
870 debug('wordsToCatch', wordsToCatch);
871
872 if (
873 token &&
874 wordsToCatch.some(a =>
875 options.body.toLowerCase().includes(a.toLowerCase()),
876 )
877 ) {
878 // with the extra "+ " it shows its copied to clipboard in the notification
879 options.body = `+ ${rawBody}`;
880 clipboard.writeText(token);
881 debug('Token parsed and copied to clipboard');
882 }
883 }
884
831 // Check if we are in scheduled Do-not-Disturb time 885 // Check if we are in scheduled Do-not-Disturb time
832 const { scheduledDNDEnabled, scheduledDNDStart, scheduledDNDEnd } = 886 const { scheduledDNDEnabled, scheduledDNDStart, scheduledDNDEnd } =
833 this.stores.settings.all.app; 887 this.stores.settings.all.app;
@@ -839,8 +893,6 @@ export default class ServicesStore extends TypedStore {
839 return; 893 return;
840 } 894 }
841 895
842 const { notificationId, options } = args[0];
843
844 if (service.isMuted || this.stores.settings.all.app.isAppMuted) { 896 if (service.isMuted || this.stores.settings.all.app.isAppMuted) {
845 Object.assign(options, { 897 Object.assign(options, {
846 silent: true, 898 silent: true,
diff --git a/src/stores/SettingsStore.ts b/src/stores/SettingsStore.ts
index 90cd82690..010290a4a 100644
--- a/src/stores/SettingsStore.ts
+++ b/src/stores/SettingsStore.ts
@@ -11,17 +11,11 @@ import {
11 LOCAL_SERVER, 11 LOCAL_SERVER,
12} from '../config'; 12} from '../config';
13import { hash } from '../helpers/password-helpers'; 13import { hash } from '../helpers/password-helpers';
14import Request from './lib/Request';
15import TypedStore from './lib/TypedStore'; 14import TypedStore from './lib/TypedStore';
16 15
17const debug = require('../preload-safe-debug')('Ferdium:SettingsStore'); 16const debug = require('../preload-safe-debug')('Ferdium:SettingsStore');
18 17
19export default class SettingsStore extends TypedStore { 18export default class SettingsStore extends TypedStore {
20 @observable updateAppSettingsRequest = new Request(
21 this.api.local,
22 'updateAppSettings',
23 );
24
25 @observable loaded: boolean = false; 19 @observable loaded: boolean = false;
26 20
27 fileSystemSettingsTypes = FILE_SYSTEM_SETTINGS_TYPES; 21 fileSystemSettingsTypes = FILE_SYSTEM_SETTINGS_TYPES;
@@ -67,7 +61,7 @@ export default class SettingsStore extends TypedStore {
67 let inactivityTimer; 61 let inactivityTimer;
68 getCurrentWindow().on('blur', () => { 62 getCurrentWindow().on('blur', () => {
69 if ( 63 if (
70 this.all.app.lockingFeatureEnabled && 64 this.all.app.isLockingFeatureEnabled &&
71 this.all.app.inactivityLock !== 0 65 this.all.app.inactivityLock !== 0
72 ) { 66 ) {
73 inactivityTimer = setTimeout( 67 inactivityTimer = setTimeout(
@@ -94,7 +88,7 @@ export default class SettingsStore extends TypedStore {
94 if ( 88 if (
95 !this.loaded && 89 !this.loaded &&
96 resp.type === 'app' && 90 resp.type === 'app' &&
97 resp.data.lockingFeatureEnabled 91 resp.data.isLockingFeatureEnabled
98 ) { 92 ) {
99 process.nextTick(() => { 93 process.nextTick(() => {
100 if (!this.all.app.locked) { 94 if (!this.all.app.locked) {
diff --git a/src/stores/UserStore.ts b/src/stores/UserStore.ts
index f98f7d340..9c3fcd3b9 100644
--- a/src/stores/UserStore.ts
+++ b/src/stores/UserStore.ts
@@ -60,11 +60,6 @@ export default class UserStore extends TypedStore {
60 'updateInfo', 60 'updateInfo',
61 ); 61 );
62 62
63 @observable getLegacyServicesRequest: CachedRequest = new CachedRequest(
64 this.api.user,
65 'getLegacyServices',
66 );
67
68 @observable deleteAccountRequest: CachedRequest = new CachedRequest( 63 @observable deleteAccountRequest: CachedRequest = new CachedRequest(
69 this.api.user, 64 this.api.user,
70 'delete', 65 'delete',
@@ -93,8 +88,6 @@ export default class UserStore extends TypedStore {
93 88
94 @observable logoutReason: string | null = null; 89 @observable logoutReason: string | null = null;
95 90
96 fetchUserInfoInterval = null;
97
98 constructor(stores: Stores, api: ApiInterface, actions: Actions) { 91 constructor(stores: Stores, api: ApiInterface, actions: Actions) {
99 super(stores, api, actions); 92 super(stores, api, actions);
100 93
@@ -132,26 +125,10 @@ export default class UserStore extends TypedStore {
132 return this.LOGIN_ROUTE; 125 return this.LOGIN_ROUTE;
133 } 126 }
134 127
135 get logoutRoute(): string {
136 return this.LOGOUT_ROUTE;
137 }
138
139 get signupRoute(): string { 128 get signupRoute(): string {
140 return this.SIGNUP_ROUTE; 129 return this.SIGNUP_ROUTE;
141 } 130 }
142 131
143 get setupRoute(): string {
144 return this.SETUP_ROUTE;
145 }
146
147 get inviteRoute(): string {
148 return this.INVITE_ROUTE;
149 }
150
151 get importRoute(): string {
152 return this.IMPORT_ROUTE;
153 }
154
155 get passwordRoute(): string { 132 get passwordRoute(): string {
156 return this.PASSWORD_ROUTE; 133 return this.PASSWORD_ROUTE;
157 } 134 }
@@ -191,10 +168,6 @@ export default class UserStore extends TypedStore {
191 return this.data.team || null; 168 return this.data.team || null;
192 } 169 }
193 170
194 @computed get legacyServices(): any {
195 return this.getLegacyServicesRequest.execute() || {};
196 }
197
198 // Actions 171 // Actions
199 @action async _login({ email, password }): Promise<void> { 172 @action async _login({ email, password }): Promise<void> {
200 const authToken = await this.loginRequest.execute(email, password).promise; 173 const authToken = await this.loginRequest.execute(email, password).promise;
diff --git a/src/stores/lib/Request.ts b/src/stores/lib/Request.ts
index 911c5ccfb..587af87d7 100644
--- a/src/stores/lib/Request.ts
+++ b/src/stores/lib/Request.ts
@@ -1,5 +1,4 @@
1import { observable, action, computed, makeObservable } from 'mobx'; 1import { observable, action, computed, makeObservable } from 'mobx';
2import { isEqual } from 'lodash/fp';
3 2
4// eslint-disable-next-line no-use-before-define 3// eslint-disable-next-line no-use-before-define
5type Hook = (request: Request) => void; 4type Hook = (request: Request) => void;
@@ -123,14 +122,6 @@ export default class Request {
123 return this.execute(...args); 122 return this.execute(...args);
124 } 123 }
125 124
126 isExecutingWithArgs(...args: any[]): boolean {
127 return (
128 this.isExecuting &&
129 this.currentApiCall &&
130 isEqual(this.currentApiCall.args, args)
131 );
132 }
133
134 @computed get isExecutingFirstTime(): boolean { 125 @computed get isExecutingFirstTime(): boolean {
135 return !this.wasExecuted && this.isExecuting; 126 return !this.wasExecuted && this.isExecuting;
136 } 127 }
diff --git a/src/themes/default/index.ts b/src/themes/default/index.ts
index cc886f299..ac04a6e3b 100644
--- a/src/themes/default/index.ts
+++ b/src/themes/default/index.ts
@@ -3,6 +3,7 @@ import { cloneDeep } from 'lodash';
3 3
4import * as legacyStyles from '../legacy'; 4import * as legacyStyles from '../legacy';
5import type IStyleTypes from '../IStyleTypes'; 5import type IStyleTypes from '../IStyleTypes';
6import { DEFAULT_LOADER_COLOR } from '../../config';
6 7
7export default (brandPrimary: string) => { 8export default (brandPrimary: string) => {
8 if (!brandPrimary) { 9 if (!brandPrimary) {
@@ -14,7 +15,7 @@ export default (brandPrimary: string) => {
14 const brandDanger = '#d9534f'; 15 const brandDanger = '#d9534f';
15 const uiFontSize = 14; 16 const uiFontSize = 14;
16 const colorBackground = legacyStyles.themeGrayLighter; 17 const colorBackground = legacyStyles.themeGrayLighter;
17 const colorContentBackground = '#FFFFFF'; 18 const colorContentBackground = DEFAULT_LOADER_COLOR;
18 const colorText = legacyStyles.themeGrayDark; 19 const colorText = legacyStyles.themeGrayDark;
19 const inputColor = legacyStyles.themeGray; 20 const inputColor = legacyStyles.themeGray;
20 const inputBackground = legacyStyles.themeGrayLightest; 21 const inputBackground = legacyStyles.themeGrayLightest;
diff --git a/src/webview/lib/RecipeWebview.ts b/src/webview/lib/RecipeWebview.ts
index 44b3c5ab4..31e9a288d 100644
--- a/src/webview/lib/RecipeWebview.ts
+++ b/src/webview/lib/RecipeWebview.ts
@@ -40,6 +40,8 @@ class RecipeWebview {
40 40
41 loopFunc = () => null; 41 loopFunc = () => null;
42 42
43 toggleToTalkFunc = () => null;
44
43 darkModeHandler: ((darkMode: boolean, config: any) => void) | null = null; 45 darkModeHandler: ((darkMode: boolean, config: any) => void) | null = null;
44 46
45 // TODO Remove this once we implement a proper wrapper. 47 // TODO Remove this once we implement a proper wrapper.
@@ -199,6 +201,10 @@ class RecipeWebview {
199 openNewWindow(url) { 201 openNewWindow(url) {
200 ipcRenderer.sendToHost('new-window', url); 202 ipcRenderer.sendToHost('new-window', url);
201 } 203 }
204
205 toggleToTalk(fn) {
206 this.toggleToTalkFunc = fn;
207 }
202} 208}
203 209
204export default RecipeWebview; 210export default RecipeWebview;
diff --git a/src/webview/notifications.ts b/src/webview/notifications.ts
index aa88f13a2..e4401ab6e 100644
--- a/src/webview/notifications.ts
+++ b/src/webview/notifications.ts
@@ -37,7 +37,7 @@ export const notificationsClassDefinition = `(() => {
37 constructor(title = '', options = {}) { 37 constructor(title = '', options = {}) {
38 this.title = title; 38 this.title = title;
39 this.options = options; 39 this.options = options;
40 try{ 40 try {
41 window.ferdium.displayNotification(title, options) 41 window.ferdium.displayNotification(title, options)
42 .then(() => { 42 .then(() => {
43 if (typeof (this.onClick) === 'function') { 43 if (typeof (this.onClick) === 'function') {
@@ -51,7 +51,7 @@ export const notificationsClassDefinition = `(() => {
51 if (typeof (this.onClick) === 'function') { 51 if (typeof (this.onClick) === 'function') {
52 this.onClick(); 52 this.onClick();
53 } 53 }
54 }); 54 });
55 } 55 }
56 } 56 }
57 57
diff --git a/src/webview/recipe.ts b/src/webview/recipe.ts
index b394f1517..148ea6fab 100644
--- a/src/webview/recipe.ts
+++ b/src/webview/recipe.ts
@@ -44,7 +44,7 @@ import {
44} from './spellchecker'; 44} from './spellchecker';
45 45
46import { DEFAULT_APP_SETTINGS } from '../config'; 46import { DEFAULT_APP_SETTINGS } from '../config';
47import { ifUndefined, safeParseInt } from '../jsUtils'; 47import { cleanseJSObject, ifUndefined, safeParseInt } from '../jsUtils';
48import { AppStore } from '../@types/stores.types'; 48import { AppStore } from '../@types/stores.types';
49import Service from '../models/Service'; 49import Service from '../models/Service';
50 50
@@ -124,8 +124,14 @@ contextBridge.exposeInMainWorld('ferdium', {
124 safeParseInt(text), 124 safeParseInt(text),
125 setDialogTitle: (title: string | null | undefined) => 125 setDialogTitle: (title: string | null | undefined) =>
126 dialogTitleHandler.setDialogTitle(title), 126 dialogTitleHandler.setDialogTitle(title),
127 displayNotification: (title: string, options: any) => 127 displayNotification: (title: string, options: any) => {
128 notificationsHandler.displayNotification(title, options), 128 notificationsHandler.displayNotification(
129 title,
130 // The following line is needed so that a proper clone of the "options" object is made.
131 // This line was causing issues with some services.
132 cleanseJSObject(options),
133 );
134 },
129 getDisplayMediaSelector, 135 getDisplayMediaSelector,
130}); 136});
131 137
@@ -158,6 +164,7 @@ class RecipeController {
158 'service-settings-update': 'updateServiceSettings', 164 'service-settings-update': 'updateServiceSettings',
159 'get-service-id': 'serviceIdEcho', 165 'get-service-id': 'serviceIdEcho',
160 'find-in-page': 'openFindInPage', 166 'find-in-page': 'openFindInPage',
167 'toggle-to-talk': 'toggleToTalk',
161 }; 168 };
162 169
163 universalDarkModeInjected = false; 170 universalDarkModeInjected = false;
@@ -483,6 +490,10 @@ class RecipeController {
483 }, 225), 490 }, 225),
484 ); 491 );
485 } 492 }
493
494 toggleToTalk() {
495 this.recipe?.toggleToTalkFunc?.();
496 }
486} 497}
487 498
488/* eslint-disable no-new */ 499/* eslint-disable no-new */