[MM-33112] Add support for multiple custom spellchecking languages (#1743)
* [MM-33112] Add support for multiple custom spellchecking languages * Styles and other formatting * Type and lint fixes * Update wording
This commit is contained in:
@@ -8,13 +8,23 @@ import 'renderer/css/settings.css';
|
||||
|
||||
import React from 'react';
|
||||
import {FormCheck, Col, FormGroup, FormText, Container, Row, Button} from 'react-bootstrap';
|
||||
import ReactSelect, {ActionMeta, OptionsType} from 'react-select';
|
||||
|
||||
import {debounce} from 'underscore';
|
||||
|
||||
import {CombinedConfig, LocalConfiguration, Team} from 'types/config';
|
||||
import {CombinedConfig, LocalConfiguration} from 'types/config';
|
||||
import {DeepPartial} from 'types/utils';
|
||||
|
||||
import {GET_LOCAL_CONFIGURATION, UPDATE_CONFIGURATION, DOUBLE_CLICK_ON_WINDOW, GET_DOWNLOAD_LOCATION, ADD_SERVER, RELOAD_CONFIGURATION} from 'common/communication';
|
||||
import {localeTranslations} from 'common/utils/constants';
|
||||
|
||||
import {
|
||||
GET_LOCAL_CONFIGURATION,
|
||||
UPDATE_CONFIGURATION,
|
||||
DOUBLE_CLICK_ON_WINDOW,
|
||||
GET_DOWNLOAD_LOCATION,
|
||||
RELOAD_CONFIGURATION,
|
||||
GET_AVAILABLE_SPELL_CHECKER_LANGUAGES,
|
||||
} from 'common/communication';
|
||||
|
||||
import AutoSaveIndicator, {SavingState} from './AutoSaveIndicator';
|
||||
|
||||
@@ -26,13 +36,11 @@ type ConfigType = typeof CONFIG_TYPE_SERVERS | typeof CONFIG_TYPE_APP_OPTIONS;
|
||||
type State = DeepPartial<CombinedConfig> & {
|
||||
ready: boolean;
|
||||
maximized?: boolean;
|
||||
teams?: Team[];
|
||||
showAddTeamForm: boolean;
|
||||
trayWasVisible?: boolean;
|
||||
firstRun?: boolean;
|
||||
savingState: SavingStateItems;
|
||||
userOpenedDownloadDialog: boolean;
|
||||
allowSaveSpellCheckerURL: boolean;
|
||||
availableLanguages: Array<{label: string; value: string}>;
|
||||
}
|
||||
|
||||
type SavingStateItems = {
|
||||
@@ -61,18 +69,19 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
|
||||
|
||||
saveQueue: SaveQueueItem[];
|
||||
|
||||
selectedSpellCheckerLocales: Array<{label: string; value: string}>;
|
||||
|
||||
constructor(props: Record<string, never>) {
|
||||
super(props);
|
||||
this.state = {
|
||||
ready: false,
|
||||
teams: [],
|
||||
showAddTeamForm: false,
|
||||
savingState: {
|
||||
appOptions: SavingState.SAVING_STATE_DONE,
|
||||
servers: SavingState.SAVING_STATE_DONE,
|
||||
},
|
||||
userOpenedDownloadDialog: false,
|
||||
allowSaveSpellCheckerURL: false,
|
||||
availableLanguages: [],
|
||||
};
|
||||
|
||||
this.getConfig();
|
||||
@@ -89,19 +98,20 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
|
||||
this.spellCheckerURLRef = React.createRef();
|
||||
|
||||
this.saveQueue = [];
|
||||
this.selectedSpellCheckerLocales = [];
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
window.ipcRenderer.on(ADD_SERVER, () => {
|
||||
this.setState({
|
||||
showAddTeamForm: true,
|
||||
});
|
||||
});
|
||||
|
||||
window.ipcRenderer.on(RELOAD_CONFIGURATION, () => {
|
||||
this.updateSaveState();
|
||||
this.getConfig();
|
||||
});
|
||||
|
||||
window.ipcRenderer.invoke(GET_AVAILABLE_SPELL_CHECKER_LANGUAGES).then((languages: string[]) => {
|
||||
const availableLanguages = languages.filter((language) => localeTranslations[language]).map((language) => ({label: localeTranslations[language], value: language}));
|
||||
availableLanguages.sort((a, b) => a.label.localeCompare(b.label));
|
||||
this.setState({availableLanguages});
|
||||
});
|
||||
}
|
||||
|
||||
getConfig = () => {
|
||||
@@ -112,16 +122,12 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
|
||||
|
||||
convertConfigDataToState = (configData: Partial<LocalConfiguration>, currentState: Partial<State> = {}) => {
|
||||
const newState = Object.assign({} as State, configData);
|
||||
newState.showAddTeamForm = currentState.showAddTeamForm || false;
|
||||
newState.trayWasVisible = currentState.trayWasVisible || false;
|
||||
if (newState.teams?.length === 0 && currentState.firstRun !== false) {
|
||||
newState.firstRun = false;
|
||||
newState.showAddTeamForm = true;
|
||||
}
|
||||
newState.savingState = currentState.savingState || {
|
||||
appOptions: SavingState.SAVING_STATE_DONE,
|
||||
servers: SavingState.SAVING_STATE_DONE,
|
||||
};
|
||||
this.selectedSpellCheckerLocales = configData.spellCheckerLocales?.map((language: string) => ({label: localeTranslations[language] || language, value: language})) || [];
|
||||
return newState;
|
||||
}
|
||||
|
||||
@@ -172,17 +178,6 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
|
||||
}
|
||||
}, 2000);
|
||||
|
||||
handleTeamsChange = (teams: Team[]) => {
|
||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_SERVERS, {key: 'teams', data: teams});
|
||||
this.setState({
|
||||
showAddTeamForm: false,
|
||||
teams,
|
||||
});
|
||||
if (teams.length === 0) {
|
||||
this.setState({showAddTeamForm: true});
|
||||
}
|
||||
}
|
||||
|
||||
handleChangeShowTrayIcon = () => {
|
||||
const shouldShowTrayIcon = this.showTrayIconRef.current?.checked;
|
||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'showTrayIcon', data: shouldShowTrayIcon});
|
||||
@@ -220,19 +215,6 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
|
||||
});
|
||||
}
|
||||
|
||||
toggleShowTeamForm = () => {
|
||||
this.setState({
|
||||
showAddTeamForm: !this.state.showAddTeamForm,
|
||||
});
|
||||
(document.activeElement as HTMLElement).blur();
|
||||
}
|
||||
|
||||
setShowTeamFormVisibility = (val: boolean) => {
|
||||
this.setState({
|
||||
showAddTeamForm: val,
|
||||
});
|
||||
}
|
||||
|
||||
handleFlashWindow = () => {
|
||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {
|
||||
key: 'notifications',
|
||||
@@ -295,6 +277,22 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
|
||||
});
|
||||
}
|
||||
|
||||
handleChangeSpellCheckerLocales = (value: OptionsType<{label: string; value: string}>, actionMeta: ActionMeta<{label: string; value: string}>) => {
|
||||
switch (actionMeta.action) {
|
||||
case 'select-option':
|
||||
this.selectedSpellCheckerLocales = [...value];
|
||||
break;
|
||||
case 'remove-value':
|
||||
this.selectedSpellCheckerLocales = this.selectedSpellCheckerLocales.filter((language) => language.value !== actionMeta.removedValue.value);
|
||||
}
|
||||
|
||||
const values = this.selectedSpellCheckerLocales.map((language) => language.value);
|
||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'spellCheckerLocales', data: values});
|
||||
this.setState({
|
||||
spellCheckerLocales: values,
|
||||
});
|
||||
}
|
||||
|
||||
handleChangeEnableHardwareAcceleration = () => {
|
||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'enableHardwareAcceleration', data: this.enableHardwareAccelerationRef.current?.checked});
|
||||
this.setState({
|
||||
@@ -426,21 +424,36 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
|
||||
}
|
||||
|
||||
options.push(
|
||||
<FormCheck>
|
||||
<FormCheck.Input
|
||||
type='checkbox'
|
||||
key='inputSpellChecker'
|
||||
id='inputSpellChecker'
|
||||
ref={this.useSpellCheckerRef}
|
||||
checked={this.state.useSpellChecker}
|
||||
onChange={this.handleChangeUseSpellChecker}
|
||||
/>
|
||||
{'Check spelling'}
|
||||
<FormText>
|
||||
{'Highlight misspelled words in your messages based on your system language configuration. '}
|
||||
{'Setting takes effect after restarting the app.'}
|
||||
</FormText>
|
||||
</FormCheck>);
|
||||
<>
|
||||
<FormCheck>
|
||||
<FormCheck.Input
|
||||
type='checkbox'
|
||||
key='inputSpellChecker'
|
||||
id='inputSpellChecker'
|
||||
ref={this.useSpellCheckerRef}
|
||||
checked={this.state.useSpellChecker}
|
||||
onChange={this.handleChangeUseSpellChecker}
|
||||
/>
|
||||
{'Check spelling'}
|
||||
<FormText>
|
||||
{'Highlight misspelled words in your messages based on your system language or language preference. '}
|
||||
{'Setting takes effect after restarting the app.'}
|
||||
</FormText>
|
||||
</FormCheck>
|
||||
{this.state.useSpellChecker &&
|
||||
<ReactSelect
|
||||
className='SettingsPage__spellCheckerLocalesDropdown'
|
||||
classNamePrefix='SettingsPage__spellCheckerLocalesDropdown'
|
||||
options={this.state.availableLanguages}
|
||||
isMulti={true}
|
||||
isClearable={false}
|
||||
onChange={this.handleChangeSpellCheckerLocales}
|
||||
value={this.selectedSpellCheckerLocales}
|
||||
placeholder={'Select preferred language(s)'}
|
||||
/>
|
||||
}
|
||||
</>,
|
||||
);
|
||||
if (process.platform !== 'darwin') {
|
||||
if (this.state.spellCheckerURL === null || typeof this.state.spellCheckerURL === 'undefined') {
|
||||
options.push(
|
||||
|
Reference in New Issue
Block a user