aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Stefan Malzner <stefan@adlk.io>2018-12-07 20:25:42 +0100
committerLibravatar Stefan Malzner <stefan@adlk.io>2018-12-07 20:25:42 +0100
commitbaf7d60af40e9cc3ce5403c5e109331098d5e1d6 (patch)
tree1973e6304b04088dc6ff9324b7e73fb52c400c9e
parentUpdate package-lock.json (diff)
downloadferdium-app-baf7d60af40e9cc3ce5403c5e109331098d5e1d6.tar.gz
ferdium-app-baf7d60af40e9cc3ce5403c5e109331098d5e1d6.tar.zst
ferdium-app-baf7d60af40e9cc3ce5403c5e109331098d5e1d6.zip
feat(Service): Add option to change spellchecking language by service
-rw-r--r--src/components/settings/services/EditServiceForm.js7
-rw-r--r--src/components/ui/Select.js9
-rw-r--r--src/containers/settings/EditServiceScreen.js24
-rw-r--r--src/containers/settings/EditSettingsScreen.js18
-rw-r--r--src/helpers/i18n-helpers.js26
-rw-r--r--src/models/Service.js3
-rw-r--r--src/styles/select.scss4
-rw-r--r--src/webview/plugin.js31
-rw-r--r--src/webview/spellchecker.js2
9 files changed, 105 insertions, 19 deletions
diff --git a/src/components/settings/services/EditServiceForm.js b/src/components/settings/services/EditServiceForm.js
index d16ec35b8..0c869c16d 100644
--- a/src/components/settings/services/EditServiceForm.js
+++ b/src/components/settings/services/EditServiceForm.js
@@ -14,6 +14,7 @@ import Input from '../../ui/Input';
14import Toggle from '../../ui/Toggle'; 14import Toggle from '../../ui/Toggle';
15import Button from '../../ui/Button'; 15import Button from '../../ui/Button';
16import ImageUpload from '../../ui/ImageUpload'; 16import ImageUpload from '../../ui/ImageUpload';
17import Select from '../../ui/Select';
17 18
18import PremiumFeatureContainer from '../../ui/PremiumFeatureContainer'; 19import PremiumFeatureContainer from '../../ui/PremiumFeatureContainer';
19 20
@@ -333,6 +334,12 @@ export default @observer class EditServiceForm extends Component {
333 </div> 334 </div>
334 </div> 335 </div>
335 336
337 <PremiumFeatureContainer>
338 <div className="settings__settings-group">
339 <Select field={form.$('spellcheckerLanguage')} />
340 </div>
341 </PremiumFeatureContainer>
342
336 {isProxyFeatureEnabled && ( 343 {isProxyFeatureEnabled && (
337 <PremiumFeatureContainer condition={isProxyFeaturePremiumFeature}> 344 <PremiumFeatureContainer condition={isProxyFeaturePremiumFeature}>
338 <div className="settings__settings-group"> 345 <div className="settings__settings-group">
diff --git a/src/components/ui/Select.js b/src/components/ui/Select.js
index abcad417e..102737bec 100644
--- a/src/components/ui/Select.js
+++ b/src/components/ui/Select.js
@@ -9,12 +9,14 @@ export default @observer class Select extends Component {
9 field: PropTypes.instanceOf(Field).isRequired, 9 field: PropTypes.instanceOf(Field).isRequired,
10 className: PropTypes.string, 10 className: PropTypes.string,
11 showLabel: PropTypes.bool, 11 showLabel: PropTypes.bool,
12 disabled: PropTypes.bool,
12 }; 13 };
13 14
14 static defaultProps = { 15 static defaultProps = {
15 className: null, 16 className: null,
16 focus: false, 17 focus: false,
17 showLabel: true, 18 showLabel: true,
19 disabled: false,
18 }; 20 };
19 21
20 render() { 22 render() {
@@ -22,13 +24,17 @@ export default @observer class Select extends Component {
22 field, 24 field,
23 className, 25 className,
24 showLabel, 26 showLabel,
27 disabled,
25 } = this.props; 28 } = this.props;
26 29
30 console.log('disabled', disabled);
31
27 return ( 32 return (
28 <div 33 <div
29 className={classnames({ 34 className={classnames({
30 'franz-form__field': true, 35 'franz-form__field': true,
31 'has-error': field.error, 36 'has-error': field.error,
37 'is-disabled': disabled,
32 [`${className}`]: className, 38 [`${className}`]: className,
33 })} 39 })}
34 > 40 >
@@ -45,12 +51,13 @@ export default @observer class Select extends Component {
45 id={field.id} 51 id={field.id}
46 defaultValue={field.value} 52 defaultValue={field.value}
47 className="franz-form__select" 53 className="franz-form__select"
54 disabled={field.disabled || disabled}
48 > 55 >
49 {field.options.map(type => ( 56 {field.options.map(type => (
50 <option 57 <option
51 key={type.value} 58 key={type.value}
52 value={type.value} 59 value={type.value}
53 // selected={field.value === } 60 disabled={type.disabled}
54 > 61 >
55 {type.label} 62 {type.label}
56 </option> 63 </option>
diff --git a/src/containers/settings/EditServiceScreen.js b/src/containers/settings/EditServiceScreen.js
index 639e8b070..f4915f68b 100644
--- a/src/containers/settings/EditServiceScreen.js
+++ b/src/containers/settings/EditServiceScreen.js
@@ -14,9 +14,12 @@ import { gaPage } from '../../lib/analytics';
14import ServiceError from '../../components/settings/services/ServiceError'; 14import ServiceError from '../../components/settings/services/ServiceError';
15import EditServiceForm from '../../components/settings/services/EditServiceForm'; 15import EditServiceForm from '../../components/settings/services/EditServiceForm';
16import { required, url, oneRequired } from '../../helpers/validation-helpers'; 16import { required, url, oneRequired } from '../../helpers/validation-helpers';
17import { getSelectOptions } from '../../helpers/i18n-helpers';
17 18
18import { config as proxyFeature } from '../../features/serviceProxy'; 19import { config as proxyFeature } from '../../features/serviceProxy';
19 20
21import { SPELLCHECKER_LOCALES } from '../../i18n/languages';
22
20const messages = defineMessages({ 23const messages = defineMessages({
21 name: { 24 name: {
22 id: 'settings.service.form.name', 25 id: 'settings.service.form.name',
@@ -74,6 +77,14 @@ const messages = defineMessages({
74 id: 'settings.service.form.proxy.password', 77 id: 'settings.service.form.proxy.password',
75 defaultMessage: '!!!Password', 78 defaultMessage: '!!!Password',
76 }, 79 },
80 spellcheckerLanguage: {
81 id: 'settings.service.form.spellcheckerLanguage',
82 defaultMessage: '!!!Spell checking Language',
83 },
84 spellcheckerSystemDefault: {
85 id: 'settings.service.form.spellcheckerLanguage.default',
86 defaultMessage: '!!!Use System Default ({default})',
87 },
77}); 88});
78 89
79export default @inject('stores', 'actions') @observer class EditServiceScreen extends Component { 90export default @inject('stores', 'actions') @observer class EditServiceScreen extends Component {
@@ -101,6 +112,11 @@ export default @inject('stores', 'actions') @observer class EditServiceScreen ex
101 } 112 }
102 113
103 prepareForm(recipe, service, proxy) { 114 prepareForm(recipe, service, proxy) {
115 const spellcheckerLanguage = getSelectOptions({
116 locales: SPELLCHECKER_LOCALES,
117 resetToDefaultText: this.context.intl.formatMessage(messages.spellcheckerSystemDefault, { default: SPELLCHECKER_LOCALES[this.props.stores.settings.app.spellcheckerLanguage] }),
118 });
119
104 const { intl } = this.context; 120 const { intl } = this.context;
105 const config = { 121 const config = {
106 fields: { 122 fields: {
@@ -138,7 +154,13 @@ export default @inject('stores', 'actions') @observer class EditServiceScreen ex
138 isDarkModeEnabled: { 154 isDarkModeEnabled: {
139 label: intl.formatMessage(messages.enableDarkMode), 155 label: intl.formatMessage(messages.enableDarkMode),
140 value: service.isDarkModeEnabled, 156 value: service.isDarkModeEnabled,
141 default: this.props.stores.settings.all.app.darkMode, 157 default: this.props.stores.settings.app.darkMode,
158 },
159 spellcheckerLanguage: {
160 label: intl.formatMessage(messages.spellcheckerLanguage),
161 value: service.spellcheckerLanguage,
162 options: spellcheckerLanguage,
163 disabled: !this.props.stores.settings.app.enableSpellchecking,
142 }, 164 },
143 }, 165 },
144 }; 166 };
diff --git a/src/containers/settings/EditSettingsScreen.js b/src/containers/settings/EditSettingsScreen.js
index ea1d319d9..350bd9f8a 100644
--- a/src/containers/settings/EditSettingsScreen.js
+++ b/src/containers/settings/EditSettingsScreen.js
@@ -12,6 +12,8 @@ import { gaPage } from '../../lib/analytics';
12import { DEFAULT_APP_SETTINGS } from '../../config'; 12import { DEFAULT_APP_SETTINGS } from '../../config';
13import { config as spellcheckerConfig } from '../../features/spellchecker'; 13import { config as spellcheckerConfig } from '../../features/spellchecker';
14 14
15import { getSelectOptions } from '../../helpers/i18n-helpers';
16
15 17
16import EditSettingsForm from '../../components/settings/settings/EditSettingsForm'; 18import EditSettingsForm from '../../components/settings/settings/EditSettingsForm';
17 19
@@ -116,20 +118,12 @@ export default @inject('stores', 'actions') @observer class EditSettingsScreen e
116 const { app, settings, user } = this.props.stores; 118 const { app, settings, user } = this.props.stores;
117 const { intl } = this.context; 119 const { intl } = this.context;
118 120
119 const locales = []; 121 const locales = getSelectOptions({
120 Object.keys(APP_LOCALES).sort(Intl.Collator().compare).forEach((key) => { 122 locales: APP_LOCALES,
121 locales.push({
122 value: key,
123 label: APP_LOCALES[key],
124 });
125 }); 123 });
126 124
127 const spellcheckingLanguages = []; 125 const spellcheckingLanguages = getSelectOptions({
128 Object.keys(SPELLCHECKER_LOCALES).sort(Intl.Collator().compare).forEach((key) => { 126 locales: SPELLCHECKER_LOCALES,
129 spellcheckingLanguages.push({
130 value: key,
131 label: SPELLCHECKER_LOCALES[key],
132 });
133 }); 127 });
134 128
135 const config = { 129 const config = {
diff --git a/src/helpers/i18n-helpers.js b/src/helpers/i18n-helpers.js
index 00a2061c1..026a220e0 100644
--- a/src/helpers/i18n-helpers.js
+++ b/src/helpers/i18n-helpers.js
@@ -25,3 +25,29 @@ export function getLocale({ locale, locales, defaultLocale, fallbackLocale }) {
25 25
26 return localeStr; 26 return localeStr;
27} 27}
28
29export function getSelectOptions({ locales, resetToDefaultText = '' }) {
30 let options = [];
31
32 if (resetToDefaultText) {
33 options = [
34 {
35 value: '',
36 label: resetToDefaultText,
37 }, {
38 value: '───',
39 label: '───',
40 disabled: true,
41 },
42 ];
43 }
44
45 Object.keys(locales).sort(Intl.Collator().compare).forEach((key) => {
46 options.push({
47 value: key,
48 label: locales[key],
49 });
50 });
51
52 return options;
53}
diff --git a/src/models/Service.js b/src/models/Service.js
index 41180dd76..deeb544d1 100644
--- a/src/models/Service.js
+++ b/src/models/Service.js
@@ -29,6 +29,7 @@ export default class Service {
29 @observable hasCustomUploadedIcon = false; 29 @observable hasCustomUploadedIcon = false;
30 @observable hasCrashed = false; 30 @observable hasCrashed = false;
31 @observable isDarkModeEnabled = false; 31 @observable isDarkModeEnabled = false;
32 @observable spellcheckerLanguage = null;
32 33
33 constructor(data, recipe) { 34 constructor(data, recipe) {
34 if (!data) { 35 if (!data) {
@@ -71,6 +72,8 @@ export default class Service {
71 72
72 this.proxy = data.proxy !== undefined ? data.proxy : this.proxy; 73 this.proxy = data.proxy !== undefined ? data.proxy : this.proxy;
73 74
75 this.spellcheckerLanguage = data.spellcheckerLanguage !== undefined ? data.spellcheckerLanguage : this.spellcheckerLanguage;
76
74 this.recipe = recipe; 77 this.recipe = recipe;
75 78
76 autorun(() => { 79 autorun(() => {
diff --git a/src/styles/select.scss b/src/styles/select.scss
index ed0fc0fc2..513975f9c 100644
--- a/src/styles/select.scss
+++ b/src/styles/select.scss
@@ -20,4 +20,8 @@ $toggle: "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj
20 min-width: 200px; 20 min-width: 200px;
21 padding: 10px; 21 padding: 10px;
22 -webkit-appearance: none; 22 -webkit-appearance: none;
23
24 &[disabled] {
25 opacity: 0.5;
26 }
23} 27}
diff --git a/src/webview/plugin.js b/src/webview/plugin.js
index 72530733d..6d4e65062 100644
--- a/src/webview/plugin.js
+++ b/src/webview/plugin.js
@@ -1,5 +1,6 @@
1import { ipcRenderer } from 'electron'; 1import { ipcRenderer } from 'electron';
2import path from 'path'; 2import path from 'path';
3import { observable } from 'mobx';
3 4
4import RecipeWebview from './lib/RecipeWebview'; 5import RecipeWebview from './lib/RecipeWebview';
5 6
@@ -12,6 +13,8 @@ const debug = require('debug')('Franz:Plugin');
12 13
13window.franzSettings = {}; 14window.franzSettings = {};
14let serviceData; 15let serviceData;
16let overrideSpellcheckerLanguage = false;
17
15 18
16ipcRenderer.on('initializeRecipe', (e, data) => { 19ipcRenderer.on('initializeRecipe', (e, data) => {
17 const modulePath = path.join(data.recipe.path, 'webview.js'); 20 const modulePath = path.join(data.recipe.path, 'webview.js');
@@ -28,6 +31,13 @@ ipcRenderer.on('initializeRecipe', (e, data) => {
28 injectDarkModeStyle(data.recipe.path); 31 injectDarkModeStyle(data.recipe.path);
29 debug('Add dark theme styles'); 32 debug('Add dark theme styles');
30 } 33 }
34
35 if (data.spellcheckerLanguage) {
36 debug('Overriding spellchecker language to', data.spellcheckerLanguage);
37 switchDict(data.spellcheckerLanguage);
38
39 overrideSpellcheckerLanguage = true;
40 }
31 } catch (err) { 41 } catch (err) {
32 debug('Recipe initialization failed', err); 42 debug('Recipe initialization failed', err);
33 } 43 }
@@ -42,10 +52,11 @@ ipcRenderer.on('initializeRecipe', (e, data) => {
42ipcRenderer.on('settings-update', async (e, data) => { 52ipcRenderer.on('settings-update', async (e, data) => {
43 debug('Settings update received', data); 53 debug('Settings update received', data);
44 54
45 if (data.enableSpellchecking) { 55 if (!data.enableSpellchecking) {
46 switchDict(data.spellcheckerLanguage);
47 } else {
48 disableSpellchecker(); 56 disableSpellchecker();
57 } else if (!overrideSpellcheckerLanguage) {
58 debug('Setting spellchecker language based on app settings to', data.spellcheckerLanguage);
59 switchDict(data.spellcheckerLanguage);
49 } 60 }
50 61
51 window.franzSettings = data; 62 window.franzSettings = data;
@@ -54,6 +65,8 @@ ipcRenderer.on('settings-update', async (e, data) => {
54ipcRenderer.on('service-settings-update', (e, data) => { 65ipcRenderer.on('service-settings-update', (e, data) => {
55 debug('Service settings update received', data); 66 debug('Service settings update received', data);
56 67
68 serviceData = data;
69
57 if (data.isDarkModeEnabled && !isDarkModeStyleInjected()) { 70 if (data.isDarkModeEnabled && !isDarkModeStyleInjected()) {
58 injectDarkModeStyle(serviceData.recipe.path); 71 injectDarkModeStyle(serviceData.recipe.path);
59 72
@@ -63,6 +76,18 @@ ipcRenderer.on('service-settings-update', (e, data) => {
63 76
64 debug('Disable service dark mode'); 77 debug('Disable service dark mode');
65 } 78 }
79
80 if (data.spellcheckerLanguage) {
81 debug('Overriding spellchecker language to', data.spellcheckerLanguage);
82 switchDict(data.spellcheckerLanguage);
83
84 overrideSpellcheckerLanguage = true;
85 } else {
86 debug('Going back to default spellchecker language to', window.franzSettings.spellcheckerLanguage);
87 switchDict(window.franzSettings.spellcheckerLanguage);
88
89 overrideSpellcheckerLanguage = false;
90 }
66}); 91});
67 92
68// Needed for current implementation of electrons 'login' event 🤦‍ 93// Needed for current implementation of electrons 'login' event 🤦‍
diff --git a/src/webview/spellchecker.js b/src/webview/spellchecker.js
index ab0cc9a90..f1bae1cd7 100644
--- a/src/webview/spellchecker.js
+++ b/src/webview/spellchecker.js
@@ -13,9 +13,7 @@ let _isEnabled = false;
13 13
14async function loadDictionary(locale) { 14async function loadDictionary(locale) {
15 try { 15 try {
16 // Replacing app.asar is not beautiful but unforunately necessary
17 const fileLocation = path.join(DICTIONARY_PATH, `hunspell-dict-${locale}/${locale}`); 16 const fileLocation = path.join(DICTIONARY_PATH, `hunspell-dict-${locale}/${locale}`);
18 console.log(fileLocation, __dirname);
19 await provider.loadDictionary(locale, `${fileLocation}.dic`, `${fileLocation}.aff`); 17 await provider.loadDictionary(locale, `${fileLocation}.dic`, `${fileLocation}.aff`);
20 } catch (err) { 18 } catch (err) {
21 console.error('Could not load dictionary', err); 19 console.error('Could not load dictionary', err);