aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/settings/settings/EditSettingsForm.jsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/settings/settings/EditSettingsForm.jsx')
-rw-r--r--src/components/settings/settings/EditSettingsForm.jsx1039
1 files changed, 1039 insertions, 0 deletions
diff --git a/src/components/settings/settings/EditSettingsForm.jsx b/src/components/settings/settings/EditSettingsForm.jsx
new file mode 100644
index 000000000..a2168f4fc
--- /dev/null
+++ b/src/components/settings/settings/EditSettingsForm.jsx
@@ -0,0 +1,1039 @@
1import { systemPreferences } from '@electron/remote';
2import { Component } from 'react';
3import PropTypes from 'prop-types';
4import { observer } from 'mobx-react';
5import prettyBytes from 'pretty-bytes';
6import { defineMessages, injectIntl } from 'react-intl';
7
8import { mdiGithub, mdiOpenInNew, mdiPowerPlug } from '@mdi/js';
9
10import Form from '../../../lib/Form';
11import Button from '../../ui/button';
12import Toggle from '../../ui/Toggle';
13import Select from '../../ui/Select';
14import Input from '../../ui/Input';
15import ColorPickerInput from '../../ui/ColorPickerInput';
16import Infobox from '../../ui/Infobox';
17import { H1, H2, H3, H5 } from '../../ui/headline';
18
19import {
20 DEFAULT_APP_SETTINGS,
21 FRANZ_TRANSLATION,
22 GITHUB_FRANZ_URL,
23 SPLIT_COLUMNS_MAX,
24 SPLIT_COLUMNS_MIN,
25} from '../../../config';
26import { isMac, isWindows, lockFerdiumShortcutKey } from '../../../environment';
27import {
28 ferdiumVersion,
29 userDataPath,
30 userDataRecipesPath,
31} from '../../../environment-remote';
32import { openPath } from '../../../helpers/url-helpers';
33import globalMessages from '../../../i18n/globalMessages';
34import Icon from '../../ui/icon';
35import Slider from '../../ui/Slider';
36
37const debug = require('../../../preload-safe-debug')(
38 'Ferdium:EditSettingsForm',
39);
40
41const messages = defineMessages({
42 headlineGeneral: {
43 id: 'settings.app.headlineGeneral',
44 defaultMessage: 'General',
45 },
46 hibernateInfo: {
47 id: 'settings.app.hibernateInfo',
48 defaultMessage:
49 '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.',
50 },
51 inactivityLockInfo: {
52 id: 'settings.app.inactivityLockInfo',
53 defaultMessage:
54 'Minutes of inactivity, after which Ferdium should automatically lock. Use 0 to disable',
55 },
56 todoServerInfo: {
57 id: 'settings.app.todoServerInfo',
58 defaultMessage: 'This server will be used for the "Ferdium Todo" feature.',
59 },
60 lockedPassword: {
61 id: 'settings.app.lockedPassword',
62 defaultMessage: 'Password',
63 },
64 lockedPasswordInfo: {
65 id: 'settings.app.lockedPasswordInfo',
66 defaultMessage:
67 "Please make sure to set a password you'll remember.\nIf you loose this password, you will have to reinstall Ferdium.",
68 },
69 lockInfo: {
70 id: 'settings.app.lockInfo',
71 defaultMessage:
72 '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}.',
73 },
74 scheduledDNDTimeInfo: {
75 id: 'settings.app.scheduledDNDTimeInfo',
76 defaultMessage:
77 'Times in 24-Hour-Format. End time can be before start time (e.g. start 17:00, end 09:00) to enable Do-not-Disturb overnight.',
78 },
79 scheduledDNDInfo: {
80 id: 'settings.app.scheduledDNDInfo',
81 defaultMessage:
82 'Scheduled Do-not-Disturb allows you to define a period of time in which you do not want to get Notifications from Ferdium.',
83 },
84 headlineLanguage: {
85 id: 'settings.app.headlineLanguage',
86 defaultMessage: 'Language',
87 },
88 headlineUpdates: {
89 id: 'settings.app.headlineUpdates',
90 defaultMessage: 'Updates',
91 },
92 headlineAppearance: {
93 id: 'settings.app.headlineAppearance',
94 defaultMessage: 'Appearance',
95 },
96 sectionMain: {
97 id: 'settings.app.sectionMain',
98 defaultMessage: 'Main',
99 },
100 sectionHibernation: {
101 id: 'settings.app.sectionHibernation',
102 defaultMessage: 'Hibernation',
103 },
104 sectionGeneralUi: {
105 id: 'settings.app.sectionGeneralUi',
106 defaultMessage: 'General UI',
107 },
108 sectionSidebarSettings: {
109 id: 'settings.app.sectionSidebarSettings',
110 defaultMessage: 'Sidebar Settings',
111 },
112 sectionPrivacy: {
113 id: 'settings.app.sectionPrivacy',
114 defaultMessage: 'Privacy Settings',
115 },
116 sectionLanguage: {
117 id: 'settings.app.sectionLanguage',
118 defaultMessage: 'Language Settings',
119 },
120 sectionAdvanced: {
121 id: 'settings.app.sectionAdvanced',
122 defaultMessage: 'Advanced Settings',
123 },
124 sectionUpdates: {
125 id: 'settings.app.sectionUpdates',
126 defaultMessage: 'App Updates Settings',
127 },
128 sectionServiceIconsSettings: {
129 id: 'settings.app.sectionServiceIconsSettings',
130 defaultMessage: 'Service Icons Settings',
131 },
132 sectionAccentColorSettings: {
133 id: 'settings.app.sectionAccentColorSettings',
134 defaultMessage: 'Accent Color Settings',
135 },
136 accentColorInfo: {
137 id: 'settings.app.accentColorInfo',
138 defaultMessage:
139 'Write your color choice in a CSS-compatible format. (Default: {defaultAccentColor} or clear the input field)',
140 },
141 overallTheme: {
142 id: 'settings.app.overallTheme',
143 defaultMessage: 'Overall Theme',
144 },
145 progressbarTheme: {
146 id: 'settings.app.progressbarTheme',
147 defaultMessage: 'Progressbar Theme',
148 },
149 universalDarkModeInfo: {
150 id: 'settings.app.universalDarkModeInfo',
151 defaultMessage:
152 'Universal Dark Mode tries to dynamically generate dark mode styles for services that are otherwise not currently supported.',
153 },
154 headlinePrivacy: {
155 id: 'settings.app.headlinePrivacy',
156 defaultMessage: 'Privacy',
157 },
158 headlineAdvanced: {
159 id: 'settings.app.headlineAdvanced',
160 defaultMessage: 'Advanced',
161 },
162 translationHelp: {
163 id: 'settings.app.translationHelp',
164 defaultMessage: 'Help us to translate Ferdium into your language.',
165 },
166 spellCheckerLanguageInfo: {
167 id: 'settings.app.spellCheckerLanguageInfo',
168 defaultMessage:
169 "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.",
170 },
171 subheadlineCache: {
172 id: 'settings.app.subheadlineCache',
173 defaultMessage: 'Cache',
174 },
175 cacheInfo: {
176 id: 'settings.app.cacheInfo',
177 defaultMessage: 'Ferdium cache is currently using {size} of disk space.',
178 },
179 cacheNotCleared: {
180 id: 'settings.app.cacheNotCleared',
181 defaultMessage: "Couldn't clear all cache",
182 },
183 buttonClearAllCache: {
184 id: 'settings.app.buttonClearAllCache',
185 defaultMessage: 'Clear cache',
186 },
187 subheadlineFerdiumProfile: {
188 id: 'settings.app.subheadlineFerdiumProfile',
189 defaultMessage: 'Ferdium Profile',
190 },
191 buttonOpenFerdiumProfileFolder: {
192 id: 'settings.app.buttonOpenFerdiumProfileFolder',
193 defaultMessage: 'Open Profile folder',
194 },
195 buttonOpenFerdiumServiceRecipesFolder: {
196 id: 'settings.app.buttonOpenFerdiumServiceRecipesFolder',
197 defaultMessage: 'Open Service Recipes folder',
198 },
199 buttonSearchForUpdate: {
200 id: 'settings.app.buttonSearchForUpdate',
201 defaultMessage: 'Check for updates',
202 },
203 buttonInstallUpdate: {
204 id: 'settings.app.buttonInstallUpdate',
205 defaultMessage: 'Restart & install update',
206 },
207 updateStatusSearching: {
208 id: 'settings.app.updateStatusSearching',
209 defaultMessage: 'Searching for updates...',
210 },
211 updateStatusAvailable: {
212 id: 'settings.app.updateStatusAvailable',
213 defaultMessage: 'Update available, downloading...',
214 },
215 updateStatusUpToDate: {
216 id: 'settings.app.updateStatusUpToDate',
217 defaultMessage: 'You are using the latest version of Ferdium',
218 },
219 currentVersion: {
220 id: 'settings.app.currentVersion',
221 defaultMessage: 'Current version:',
222 },
223 appRestartRequired: {
224 id: 'settings.app.restartRequired',
225 defaultMessage: 'Changes require restart',
226 },
227 servicesUpdated: {
228 id: 'infobar.servicesUpdated',
229 defaultMessage: 'Your services have been updated.',
230 },
231 buttonReloadServices: {
232 id: 'infobar.buttonReloadServices',
233 defaultMessage: 'Reload services',
234 },
235 numberOfColumns: {
236 id: 'settings.app.form.splitColumns',
237 defaultMessage: 'Number of columns',
238 },
239});
240
241const Hr = () => (
242 <hr
243 className="settings__hr"
244 style={{ marginBottom: 20, borderStyle: 'dashed' }}
245 />
246);
247const HrSections = () => (
248 <hr
249 className="settings__hr-sections"
250 style={{ marginTop: 20, marginBottom: 40, borderStyle: 'solid' }}
251 />
252);
253
254class EditSettingsForm extends Component {
255 static propTypes = {
256 checkForUpdates: PropTypes.func.isRequired,
257 installUpdate: PropTypes.func.isRequired,
258 form: PropTypes.instanceOf(Form).isRequired,
259 onSubmit: PropTypes.func.isRequired,
260 isCheckingForUpdates: PropTypes.bool.isRequired,
261 isUpdateAvailable: PropTypes.bool.isRequired,
262 noUpdateAvailable: PropTypes.bool.isRequired,
263 updateIsReadyToInstall: PropTypes.bool.isRequired,
264 updateFailed: PropTypes.bool.isRequired,
265 isClearingAllCache: PropTypes.bool.isRequired,
266 onClearAllCache: PropTypes.func.isRequired,
267 getCacheSize: PropTypes.func.isRequired,
268 isTodosActivated: PropTypes.bool.isRequired,
269 automaticUpdates: PropTypes.bool.isRequired,
270 isDarkmodeEnabled: PropTypes.bool.isRequired,
271 isAdaptableDarkModeEnabled: PropTypes.bool.isRequired,
272 isUseGrayscaleServicesEnabled: PropTypes.bool.isRequired,
273 openProcessManager: PropTypes.func.isRequired,
274 isSplitModeEnabled: PropTypes.bool.isRequired,
275 isOnline: PropTypes.bool.isRequired,
276 };
277
278 constructor(props) {
279 super(props);
280
281 this.state = {
282 activeSetttingsTab: 'general',
283 clearCacheButtonClicked: false,
284 };
285 }
286
287 setActiveSettingsTab(tab) {
288 this.setState({
289 activeSetttingsTab: tab,
290 });
291 }
292
293 onClearCacheClicked = () => {
294 this.setState({ clearCacheButtonClicked: true });
295 };
296
297 submit(e) {
298 e.preventDefault();
299 this.props.form.submit({
300 onSuccess: form => {
301 const values = form.values();
302 this.props.onSubmit(values);
303 },
304 onError: () => {},
305 });
306 }
307
308 render() {
309 const {
310 checkForUpdates,
311 installUpdate,
312 form,
313 isCheckingForUpdates,
314 isAdaptableDarkModeEnabled,
315 isUseGrayscaleServicesEnabled,
316 isUpdateAvailable,
317 noUpdateAvailable,
318 updateIsReadyToInstall,
319 updateFailed,
320 showServicesUpdatedInfoBar,
321 isClearingAllCache,
322 onClearAllCache,
323 getCacheSize,
324 automaticUpdates,
325 isDarkmodeEnabled,
326 isSplitModeEnabled,
327 openProcessManager,
328 isTodosActivated,
329 isOnline,
330 } = this.props;
331 const { intl } = this.props;
332
333 let updateButtonLabelMessage = messages.buttonSearchForUpdate;
334 if (isCheckingForUpdates) {
335 updateButtonLabelMessage = messages.updateStatusSearching;
336 } else if (isUpdateAvailable) {
337 updateButtonLabelMessage = messages.updateStatusAvailable;
338 } else {
339 updateButtonLabelMessage = messages.buttonSearchForUpdate;
340 }
341
342 const { lockingFeatureEnabled, scheduledDNDEnabled, reloadAfterResume } =
343 window['ferdium'].stores.settings.all.app;
344
345 let cacheSize;
346 let notCleared;
347 if (this.state.activeSetttingsTab === 'advanced') {
348 const cacheSizeBytes = getCacheSize();
349 debug('cacheSizeBytes:', cacheSizeBytes);
350 if (typeof cacheSizeBytes === 'number') {
351 cacheSize = prettyBytes(cacheSizeBytes);
352 debug('cacheSize:', cacheSize);
353 notCleared =
354 this.state.clearCacheButtonClicked &&
355 isClearingAllCache === false &&
356 cacheSizeBytes !== 0;
357 } else {
358 cacheSize = '…';
359 notCleared = false;
360 }
361 }
362
363 const profileFolder = userDataPath();
364 const recipeFolder = userDataRecipesPath();
365
366 return (
367 <div className="settings__main">
368 <div className="settings__header">
369 <H1>{intl.formatMessage(globalMessages.settings)}</H1>
370 </div>
371 <div className="settings__body">
372 <form
373 onSubmit={e => this.submit(e)}
374 onChange={e => this.submit(e)}
375 id="form"
376 >
377 {/* Titles */}
378 <div className="recipes__navigation">
379 <H5
380 id="general"
381 className={
382 this.state.activeSetttingsTab === 'general'
383 ? 'badge badge--primary'
384 : 'badge'
385 }
386 onClick={() => {
387 this.setActiveSettingsTab('general');
388 }}
389 >
390 {intl.formatMessage(messages.headlineGeneral)}
391 </H5>
392 <H5
393 id="appearance"
394 className={
395 this.state.activeSetttingsTab === 'appearance'
396 ? 'badge badge--primary'
397 : 'badge'
398 }
399 onClick={() => {
400 this.setActiveSettingsTab('appearance');
401 }}
402 >
403 {intl.formatMessage(messages.headlineAppearance)}
404 </H5>
405 <H5
406 id="privacy"
407 className={
408 this.state.activeSetttingsTab === 'privacy'
409 ? 'badge badge--primary'
410 : 'badge'
411 }
412 onClick={() => {
413 this.setActiveSettingsTab('privacy');
414 }}
415 >
416 {intl.formatMessage(messages.headlinePrivacy)}
417 </H5>
418 <H5
419 id="language"
420 className={
421 this.state.activeSetttingsTab === 'language'
422 ? 'badge badge--primary'
423 : 'badge'
424 }
425 onClick={() => {
426 this.setActiveSettingsTab('language');
427 }}
428 >
429 {intl.formatMessage(messages.headlineLanguage)}
430 </H5>
431 <H5
432 id="advanced"
433 className={
434 this.state.activeSetttingsTab === 'advanced'
435 ? 'badge badge--primary'
436 : 'badge'
437 }
438 onClick={() => {
439 this.setActiveSettingsTab('advanced');
440 }}
441 >
442 {intl.formatMessage(messages.headlineAdvanced)}
443 </H5>
444 <H5
445 id="updates"
446 className={
447 this.state.activeSetttingsTab === 'updates'
448 ? 'badge badge--primary'
449 : 'badge'
450 }
451 onClick={() => {
452 this.setActiveSettingsTab('updates');
453 }}
454 >
455 {intl.formatMessage(messages.headlineUpdates)}
456 {automaticUpdates &&
457 (updateIsReadyToInstall ||
458 isUpdateAvailable ||
459 showServicesUpdatedInfoBar) && (
460 <span className="update-available">•</span>
461 )}
462 </H5>
463 </div>
464
465 {/* General */}
466 {this.state.activeSetttingsTab === 'general' && (
467 <div>
468 <H2 className="settings__section_header">
469 {intl.formatMessage(messages.sectionMain)}
470 </H2>
471 <Toggle field={form.$('autoLaunchOnStart')} />
472 <Toggle field={form.$('runInBackground')} />
473 <Toggle field={form.$('confirmOnQuit')} />
474 <Toggle field={form.$('enableSystemTray')} />
475 {reloadAfterResume && <Hr />}
476 <Toggle field={form.$('reloadAfterResume')} />
477 {reloadAfterResume && (
478 <div>
479 <Input field={form.$('reloadAfterResumeTime')} />
480 <Hr />
481 </div>
482 )}
483 <Toggle field={form.$('startMinimized')} />
484 {isWindows && <Toggle field={form.$('minimizeToSystemTray')} />}
485 {isWindows && <Toggle field={form.$('closeToSystemTray')} />}
486
487 <Toggle field={form.$('keepAllWorkspacesLoaded')} />
488
489 {isTodosActivated && <Hr />}
490 <Toggle field={form.$('enableTodos')} />
491 {isTodosActivated && (
492 <div>
493 <Select field={form.$('predefinedTodoServer')} />
494 {form.$('predefinedTodoServer').value ===
495 'isUsingCustomTodoService' && (
496 <div>
497 <Input
498 placeholder="Todo Server"
499 onChange={e => this.submit(e)}
500 field={form.$('customTodoServer')}
501 />
502 <p
503 className="settings__message"
504 style={{
505 borderTop: 0,
506 marginTop: 0,
507 paddingTop: 0,
508 marginBottom: '2rem',
509 }}
510 >
511 {intl.formatMessage(messages.todoServerInfo)}
512 </p>
513 </div>
514 )}
515 </div>
516 )}
517 {isTodosActivated && <Hr />}
518
519 {scheduledDNDEnabled && <Hr />}
520 <Toggle field={form.$('scheduledDNDEnabled')} />
521
522 {scheduledDNDEnabled && (
523 <>
524 <div
525 style={{
526 display: 'flex',
527 justifyContent: 'center',
528 }}
529 >
530 <div
531 style={{
532 padding: '0 1rem',
533 width: '100%',
534 }}
535 >
536 <Input
537 placeholder="17:00"
538 onChange={e => this.submit(e)}
539 field={form.$('scheduledDNDStart')}
540 type="time"
541 />
542 </div>
543 <div
544 style={{
545 padding: '0 1rem',
546 width: '100%',
547 }}
548 >
549 <Input
550 placeholder="09:00"
551 onChange={e => this.submit(e)}
552 field={form.$('scheduledDNDEnd')}
553 type="time"
554 />
555 </div>
556 </div>
557 <p>{intl.formatMessage(messages.scheduledDNDTimeInfo)}</p>
558 </>
559 )}
560 <p
561 className="settings__message"
562 style={{
563 borderTop: 0,
564 marginTop: 0,
565 paddingTop: 0,
566 marginBottom: '2rem',
567 }}
568 >
569 <span>{intl.formatMessage(messages.scheduledDNDInfo)}</span>
570 </p>
571
572 <Hr />
573
574 <Select field={form.$('navigationBarBehaviour')} />
575
576 <HrSections />
577
578 <H2 className="settings__section_header">
579 {intl.formatMessage(messages.sectionHibernation)}
580 </H2>
581 <Select field={form.$('hibernationStrategy')} />
582 <Toggle field={form.$('hibernateOnStartup')} />
583 <p
584 className="settings__message"
585 style={{
586 borderTop: 0,
587 marginTop: 0,
588 paddingTop: 0,
589 marginBottom: '2rem',
590 }}
591 >
592 <span>{intl.formatMessage(messages.hibernateInfo)}</span>
593 </p>
594
595 <Select field={form.$('wakeUpStrategy')} />
596 <Select field={form.$('wakeUpHibernationStrategy')} />
597 <Toggle field={form.$('wakeUpHibernationSplay')} />
598 </div>
599 )}
600
601 {/* Appearance */}
602 {this.state.activeSetttingsTab === 'appearance' && (
603 <div>
604 <H2 className="settings__section_header">
605 {intl.formatMessage(messages.sectionGeneralUi)}
606 </H2>
607 {isMac && <Toggle field={form.$('showDragArea')} />}
608
609 <Toggle field={form.$('adaptableDarkMode')} />
610 {!isAdaptableDarkModeEnabled && (
611 <Toggle field={form.$('darkMode')} />
612 )}
613 {(isDarkmodeEnabled || isAdaptableDarkModeEnabled) && (
614 <>
615 <Toggle field={form.$('universalDarkMode')} />
616 <p
617 className="settings__message"
618 style={{
619 borderTop: 0,
620 marginTop: 0,
621 paddingTop: 0,
622 marginBottom: '2rem',
623 }}
624 >
625 <span>
626 {intl.formatMessage(messages.universalDarkModeInfo)}
627 </span>
628 </p>
629 </>
630 )}
631
632 {isSplitModeEnabled && <Hr />}
633 <Toggle field={form.$('splitMode')} />
634 {isSplitModeEnabled && (
635 <Input
636 type="number"
637 min={SPLIT_COLUMNS_MIN}
638 max={SPLIT_COLUMNS_MAX}
639 placeholder={`${SPLIT_COLUMNS_MIN}-${SPLIT_COLUMNS_MAX}`}
640 onChange={e => this.submit(e)}
641 field={form.$('splitColumns')}
642 />
643 )}
644
645 <HrSections />
646 <H2 className="settings__section_header">
647 {intl.formatMessage(messages.sectionAccentColorSettings)}
648 </H2>
649 <p>
650 {intl.formatMessage(messages.accentColorInfo, {
651 defaultAccentColor: DEFAULT_APP_SETTINGS.accentColor,
652 })}
653 </p>
654 <p>
655 {intl.formatMessage(messages.overallTheme)}
656 <div className="settings__settings-group__apply-color">
657 <ColorPickerInput
658 onChange={e => this.submit(e)}
659 field={form.$('accentColor')}
660 className="color-picker-input"
661 />
662 </div>
663 </p>
664 <p>
665 {intl.formatMessage(messages.progressbarTheme)}
666 <div className="settings__settings-group__apply-color">
667 <ColorPickerInput
668 onChange={e => this.submit(e)}
669 field={form.$('progressbarAccentColor')}
670 className="color-picker-input"
671 />
672 </div>
673 </p>
674 <p>
675 <div className="settings__settings-group__apply-color">
676 <Button
677 buttonType="secondary"
678 className="settings__settings-group__apply-color__button"
679 label="Apply color"
680 onClick={e => {
681 this.submit(e);
682 }}
683 />
684 </div>
685 </p>
686 <HrSections />
687
688 <H2 className="settings__section_header">
689 {intl.formatMessage(messages.sectionSidebarSettings)}
690 </H2>
691
692 <Select field={form.$('serviceRibbonWidth')} />
693
694 <Select field={form.$('sidebarServicesLocation')} />
695
696 <Toggle field={form.$('useVerticalStyle')} />
697
698 <Toggle field={form.$('hideCollapseButton')} />
699
700 <Toggle field={form.$('hideRecipesButton')} />
701
702 <Toggle field={form.$('hideSplitModeButton')} />
703
704 <Toggle field={form.$('hideWorkspacesButton')} />
705
706 <Toggle field={form.$('hideNotificationsButton')} />
707
708 <Toggle field={form.$('hideSettingsButton')} />
709
710 <Toggle field={form.$('alwaysShowWorkspaces')} />
711
712 <HrSections />
713
714 <H2 className="settings__section_header">
715 {intl.formatMessage(messages.sectionServiceIconsSettings)}
716 </H2>
717
718 <Toggle field={form.$('showDisabledServices')} />
719 <Toggle field={form.$('showServiceName')} />
720
721 {isUseGrayscaleServicesEnabled && <Hr />}
722
723 <Toggle field={form.$('useGrayscaleServices')} />
724
725 {isUseGrayscaleServicesEnabled && (
726 <>
727 <Slider
728 type="number"
729 onChange={e => this.submit(e)}
730 field={form.$('grayscaleServicesDim')}
731 />
732 <Hr />
733 </>
734 )}
735
736 <Toggle field={form.$('showMessageBadgeWhenMuted')} />
737 <Toggle field={form.$('enableLongPressServiceHint')} />
738 <Select field={form.$('iconSize')} />
739 </div>
740 )}
741
742 {/* Privacy */}
743 {this.state.activeSetttingsTab === 'privacy' && (
744 <div>
745 <H2 className="settings__section_header">
746 {intl.formatMessage(messages.sectionPrivacy)}
747 </H2>
748
749 <Toggle field={form.$('privateNotifications')} />
750 <Toggle field={form.$('clipboardNotifications')} />
751 {(isWindows || isMac) && (
752 <Toggle field={form.$('notifyTaskBarOnMessage')} />
753 )}
754
755 <Hr />
756
757 <Select field={form.$('searchEngine')} />
758
759 <p className="settings__help">
760 {intl.formatMessage(messages.appRestartRequired)}
761 </p>
762
763 <Hr />
764
765 <Toggle field={form.$('lockingFeatureEnabled')} />
766 {lockingFeatureEnabled && (
767 <>
768 {isMac && systemPreferences.canPromptTouchID() && (
769 <Toggle field={form.$('useTouchIdToUnlock')} />
770 )}
771
772 <Input
773 placeholder={intl.formatMessage(messages.lockedPassword)}
774 onChange={e => this.submit(e)}
775 field={form.$('lockedPassword')}
776 type="password"
777 scorePassword
778 showPasswordToggle
779 />
780 <p>{intl.formatMessage(messages.lockedPasswordInfo)}</p>
781
782 <Input
783 placeholder="Lock after inactivity"
784 onChange={e => this.submit(e)}
785 field={form.$('inactivityLock')}
786 autoFocus
787 />
788 <p>{intl.formatMessage(messages.inactivityLockInfo)}</p>
789 </>
790 )}
791 <p
792 className="settings__message"
793 style={{
794 borderTop: 0,
795 marginTop: 0,
796 paddingTop: 0,
797 marginBottom: '2rem',
798 }}
799 >
800 <span>
801 {intl.formatMessage(messages.lockInfo, {
802 lockShortcut: `${lockFerdiumShortcutKey(false)}`,
803 })}
804 </span>
805 </p>
806 </div>
807 )}
808
809 {/* Language */}
810 {this.state.activeSetttingsTab === 'language' && (
811 <div>
812 <H2 className="settings__section_header">
813 {intl.formatMessage(messages.sectionLanguage)}
814 </H2>
815
816 <Select field={form.$('locale')} showLabel={false} />
817
818 <Hr />
819
820 <Toggle field={form.$('enableSpellchecking')} />
821 {!isMac && form.$('enableSpellchecking').value && (
822 <Select field={form.$('spellcheckerLanguage')} />
823 )}
824 {isMac && form.$('enableSpellchecking').value && (
825 <p className="settings__help">
826 {intl.formatMessage(messages.spellCheckerLanguageInfo)}
827 </p>
828 )}
829 <p className="settings__help">
830 {intl.formatMessage(messages.appRestartRequired)}
831 </p>
832
833 <Hr />
834
835 <a
836 href={FRANZ_TRANSLATION}
837 target="_blank"
838 className="link"
839 rel="noreferrer"
840 >
841 {intl.formatMessage(messages.translationHelp)}{' '}
842 <Icon icon={mdiOpenInNew} />
843 </a>
844 </div>
845 )}
846
847 {/* Advanced */}
848 {this.state.activeSetttingsTab === 'advanced' && (
849 <div>
850 <H2 className="settings__section_header">
851 {intl.formatMessage(messages.sectionAdvanced)}
852 </H2>
853
854 <Toggle field={form.$('enableGPUAcceleration')} />
855 <Toggle field={form.$('enableGlobalHideShortcut')} />
856 <p className="settings__help indented__help">
857 {intl.formatMessage(messages.appRestartRequired)}
858 </p>
859
860 <Hr />
861
862 <Input
863 placeholder="User Agent"
864 onChange={e => this.submit(e)}
865 field={form.$('userAgentPref')}
866 />
867 <p className="settings__help">
868 {intl.formatMessage(globalMessages.userAgentHelp)}
869 </p>
870 <p className="settings__help">
871 {intl.formatMessage(messages.appRestartRequired)}
872 </p>
873
874 <Hr />
875
876 <div className="settings__settings-group">
877 <H3>{intl.formatMessage(messages.subheadlineCache)}</H3>
878 <p>
879 {intl.formatMessage(messages.cacheInfo, {
880 size: cacheSize,
881 })}
882 </p>
883 {notCleared && (
884 <p>{intl.formatMessage(messages.cacheNotCleared)}</p>
885 )}
886 <div className="settings__settings-group">
887 <div className="settings__open-settings-cache-container">
888 <Button
889 buttonType="secondary"
890 label={intl.formatMessage(messages.buttonClearAllCache)}
891 className="settings__open-settings-cache-button"
892 onClick={() => {
893 onClearAllCache();
894 this.onClearCacheClicked();
895 }}
896 disabled={isClearingAllCache}
897 loaded={!isClearingAllCache}
898 />
899 <Button
900 buttonType="secondary"
901 label="Open Process Manager"
902 className="settings__open-settings-cache-button"
903 onClick={openProcessManager}
904 />
905 </div>
906 </div>
907 </div>
908
909 <Hr />
910
911 <div className="settings__settings-group">
912 <H3>
913 {intl.formatMessage(messages.subheadlineFerdiumProfile)}
914 </H3>
915 <p>
916 <div className="settings__open-settings-file-container">
917 <Button
918 buttonType="secondary"
919 label={intl.formatMessage(
920 messages.buttonOpenFerdiumProfileFolder,
921 )}
922 className="settings__open-settings-file-button"
923 onClick={() => openPath(profileFolder)}
924 />
925 <Button
926 buttonType="secondary"
927 label={intl.formatMessage(
928 messages.buttonOpenFerdiumServiceRecipesFolder,
929 )}
930 className="settings__open-settings-file-button"
931 onClick={() => openPath(recipeFolder)}
932 />
933 </div>
934 </p>
935 </div>
936 </div>
937 )}
938
939 {/* Updates */}
940 {this.state.activeSetttingsTab === 'updates' && (
941 <div>
942 <H2 className="settings__section_header">
943 {intl.formatMessage(messages.sectionUpdates)}
944 </H2>
945
946 <Toggle field={form.$('automaticUpdates')} />
947 {automaticUpdates && (
948 <>
949 <>
950 <div>
951 <Toggle field={form.$('beta')} />
952 {updateIsReadyToInstall ? (
953 <Button
954 label={intl.formatMessage(
955 messages.buttonInstallUpdate,
956 )}
957 onClick={installUpdate}
958 />
959 ) : (
960 <Button
961 buttonType="secondary"
962 label={intl.formatMessage(updateButtonLabelMessage)}
963 onClick={checkForUpdates}
964 disabled={
965 !automaticUpdates ||
966 isCheckingForUpdates ||
967 isUpdateAvailable ||
968 !isOnline
969 }
970 loaded={!isCheckingForUpdates || !isUpdateAvailable}
971 />
972 )}
973 <br />
974 </div>
975 <p>
976 {intl.formatMessage(messages.currentVersion)}{' '}
977 {ferdiumVersion}
978 </p>
979 {noUpdateAvailable && (
980 <p>
981 {intl.formatMessage(messages.updateStatusUpToDate)}.
982 </p>
983 )}
984 {updateFailed && (
985 <Infobox type="danger" icon="alert">
986 &nbsp;An error occurred (check the console for more
987 details)
988 </Infobox>
989 )}
990 </>
991 {showServicesUpdatedInfoBar ? (
992 <>
993 <p>
994 <Icon icon={mdiPowerPlug} />
995 {intl.formatMessage(messages.servicesUpdated)}
996 </p>
997 <Button
998 label={intl.formatMessage(
999 messages.buttonReloadServices,
1000 )}
1001 onClick={() => window.location.reload()}
1002 />
1003 </>
1004 ) : (
1005 <p>
1006 <Icon icon={mdiPowerPlug} />
1007 &nbsp;Your services are up-to-date.
1008 </p>
1009 )}
1010 </>
1011 )}
1012 <p className="settings__message">
1013 <Icon icon={mdiGithub} /> Ferdium is based on{' '}
1014 <a
1015 href={`${GITHUB_FRANZ_URL}/franz`}
1016 target="_blank"
1017 rel="noreferrer"
1018 >
1019 Franz
1020 </a>
1021 , a project published under the{' '}
1022 <a
1023 href={`${GITHUB_FRANZ_URL}/franz/blob/master/LICENSE`}
1024 target="_blank"
1025 rel="noreferrer"
1026 >
1027 Apache-2.0 License
1028 </a>
1029 </p>
1030 </div>
1031 )}
1032 </form>
1033 </div>
1034 </div>
1035 );
1036 }
1037}
1038
1039export default injectIntl(observer(EditSettingsForm));