From 32b2b69787c87c823f109fc8d3768c7b0f17fc5c Mon Sep 17 00:00:00 2001 From: Jijo Joseph Date: Wed, 19 Jul 2023 20:00:12 +0530 Subject: [PATCH] #867 --- app/appConfiguration/index.js | 49 +++++++++++++ app/index.js | 16 ++--- app/mainAppWindow/index.js | 22 +++++- app/menus/index.js | 70 ++++++++++++++++--- app/spellCheckProvider/index.js | 56 +++++++++++++-- ...IsmaelMartinez.teams_for_linux.appdata.xml | 7 ++ package.json | 2 +- 7 files changed, 195 insertions(+), 27 deletions(-) create mode 100644 app/appConfiguration/index.js diff --git a/app/appConfiguration/index.js b/app/appConfiguration/index.js new file mode 100644 index 00000000..d4a8638d --- /dev/null +++ b/app/appConfiguration/index.js @@ -0,0 +1,49 @@ +const Store = require('electron-store'); + +let _AppConfiguration_configPath = new WeakMap(); +let _AppConfiguration_startupConfig = new WeakMap(); +let _AppConfiguration_legacyConfigStore = new WeakMap(); +let _AppConfiguration_settingsStore = new WeakMap(); + +class AppConfiguration { + /** + * @param {string} configPath + */ + constructor(configPath) { + _AppConfiguration_configPath.set(this, configPath); + _AppConfiguration_startupConfig.set(this, require('../config')(configPath)); + _AppConfiguration_legacyConfigStore.set(this, new Store({ + name: 'config' + })); + _AppConfiguration_settingsStore.set(this, new Store({ + name: 'settings' + })); + } + + /** + * @returns {string} + */ + get configPath() { + return _AppConfiguration_configPath.get(this); + } + + get startupConfig() { + return _AppConfiguration_startupConfig.get(this); + } + + /** + * @returns {Store} + */ + get legacyConfigStore() { + return _AppConfiguration_legacyConfigStore.get(this); + } + + /** + * @returns {Store} + */ + get settingsStore() { + return _AppConfiguration_settingsStore.get(this); + } +} + +module.exports = { AppConfiguration }; \ No newline at end of file diff --git a/app/index.js b/app/index.js index 533aaa9b..2af30cbc 100644 --- a/app/index.js +++ b/app/index.js @@ -10,7 +10,11 @@ const isMac = os.platform() === 'darwin'; if (app.commandLine.hasSwitch('customUserDir')) { app.setPath('userData', app.commandLine.getSwitchValue('customUserDir')); } -const config = require('./config')(app.getPath('userData')); + +const { AppConfiguration } = require('./appConfiguration'); +const appConfig = new AppConfiguration(app.getPath('userData')); + +const config = appConfig.startupConfig; config.appPath = path.join(__dirname, isDev ? '' : '../../'); const logger = new LucidLog({ @@ -41,10 +45,6 @@ try { logger.info('No audio players found. Audio notifications might not work.'); } -const Store = require('electron-store'); -const store = new Store({ - name: 'settings' -}); const certificateModule = require('./certificate'); const gotTheLock = app.requestSingleInstanceLock(); const mainAppWindow = require('./mainAppWindow'); @@ -144,7 +144,7 @@ function handleAppReady() { process.on('SIGTERM', onAppTerminated); //Just catch the error process.stdout.on('error', () => { }); - mainAppWindow.onAppReady(config); + mainAppWindow.onAppReady(appConfig); } async function handleGetConfig() { @@ -183,7 +183,7 @@ async function handleGetCustomBGList() { } function getPartitions() { - return store.get('app.partitions') || []; + return appConfig.settingsStore.get('app.partitions') || []; } function getPartition(name) { @@ -204,7 +204,7 @@ function savePartition(arg) { } else { partitions.push(arg); } - store.set('app.partitions', partitions); + appConfig.settingsStore.set('app.partitions', partitions); } function handleCertificateError() { diff --git a/app/mainAppWindow/index.js b/app/mainAppWindow/index.js index 3039504a..aec06e0a 100644 --- a/app/mainAppWindow/index.js +++ b/app/mainAppWindow/index.js @@ -13,6 +13,8 @@ const { SpellCheckProvider } = require('../spellCheckProvider'); const helpers = require('../helpers'); const exec = require('child_process').exec; const TrayIconChooser = require('../browser/tools/trayIconChooser'); +// eslint-disable-next-line no-unused-vars +const { AppConfiguration } = require('../appConfiguration'); /** * @type {TrayIconChooser} @@ -43,16 +45,26 @@ let config; */ let window = null; +/** + * @type {AppConfiguration} + */ +let appConfig = null; + +/** + * @param {AppConfiguration} mainConfig + */ exports.onAppReady = async function onAppReady(mainConfig) { - config = mainConfig; - iconChooser = new TrayIconChooser(mainConfig); + appConfig = mainConfig; + config = mainConfig.startupConfig; + iconChooser = new TrayIconChooser(mainConfig.startupConfig); logger = new LucidLog({ levels: config.appLogLevels.split(',') }); window = await createWindow(); - new Menus(window, config, iconChooser.getFile()); + const m = new Menus(window, config, iconChooser.getFile()); + m.onSpellCheckerLanguageChanged = onSpellCheckerLanguageChanged; addEventHandlers(); @@ -62,6 +74,10 @@ exports.onAppReady = async function onAppReady(mainConfig) { applyAppConfiguration(config, window); }; +function onSpellCheckerLanguageChanged(languages) { + appConfig.legacyConfigStore.set('spellCheckerLanguages', languages); +} + let allowFurtherRequests = true; exports.onAppSecondInstance = function onAppSecondInstance(event, args) { diff --git a/app/menus/index.js b/app/menus/index.js index 56d74ced..36317e48 100644 --- a/app/menus/index.js +++ b/app/menus/index.js @@ -9,6 +9,7 @@ const { LucidLog } = require('lucid-log'); const { SpellCheckProvider } = require('../spellCheckProvider'); const checkConnectivity = require('./connectivity'); +let _Menus_onSpellCheckerLanguageChanged = new WeakMap(); class Menus { constructor(window, config, iconPath) { /** @@ -24,6 +25,22 @@ class Menus { this.initialize(); } + /** + * @type {(languages:Array)=>void} + */ + get onSpellCheckerLanguageChanged() { + return _Menus_onSpellCheckerLanguageChanged.get(this); + } + + /** + * @type {(languages:Array)=>void} + */ + set onSpellCheckerLanguageChanged(value) { + if (typeof value === 'function') { + _Menus_onSpellCheckerLanguageChanged.set(this, value); + } + } + async quit(clearStorage = false) { this.allowQuit = true; @@ -279,14 +296,42 @@ function addSpellCheckMenuItems(menu, menus) { function createSpellCheckLanguagesMenu(menus) { const activeLanguages = menus.window.webContents.session.getSpellCheckerLanguages(); const splChkMenu = new Menu(); - for (const language of menus.spellCheckProvider.supportedList) { - splChkMenu.append( - createLanguageMenuItem(language, activeLanguages, menus) - ); + for (const group of menus.spellCheckProvider.supportedListByGroup) { + const subMenu = new Menu(); + splChkMenu.append(new MenuItem({ + label: group.key, + submenu: subMenu + })); + for (const language of group.list) { + subMenu.append( + createLanguageMenuItem(language, activeLanguages, menus) + ); + } } + + createSpellCheckLanguagesNoneMenuEntry(splChkMenu, menus); + return splChkMenu; } +/** + * @param {Electron.Menu} menu + * @param {Menus} menus + */ +function createSpellCheckLanguagesNoneMenuEntry(menu, menus) { + menu.append( + new MenuItem({ + type: 'separator' + }) + ); + menu.append( + new MenuItem({ + label: 'None', + click: () => chooseLanguage(null, menus) + }) + ); +} + /** * @param {{language:string,code:string}} language * @param {Array} activeLanguages @@ -309,12 +354,19 @@ function createLanguageMenuItem(language, activeLanguages, menus) { */ function chooseLanguage(item, menus) { const activeLanguages = menus.window.webContents.session.getSpellCheckerLanguages(); - if (item.checked) { - addToList(activeLanguages, item.id); - } else { - removeFromList(activeLanguages, item.id); + if (item) { + if (item.checked) { + addToList(activeLanguages, item.id); + } else { + removeFromList(activeLanguages, item.id); + } + } + + const changes = menus.spellCheckProvider.setLanguages(item ? activeLanguages : []); + + if (menus.onSpellCheckerLanguageChanged) { + menus.onSpellCheckerLanguageChanged.apply(menus, [changes]); } - menus.spellCheckProvider.setLanguages(activeLanguages); } /** diff --git a/app/spellCheckProvider/index.js b/app/spellCheckProvider/index.js index f60ba28f..991e1ba8 100644 --- a/app/spellCheckProvider/index.js +++ b/app/spellCheckProvider/index.js @@ -23,6 +23,18 @@ class SpellCheckProvider { return _SpellCheckProvider_supportedList.get(this); } + /** + * @type {Array<{key:string,list:{language:string,code:string}}>} + */ + get supportedListByGroup() { + var groupedList = []; + for (const language of this.supportedList) { + var key = language.language.substring(0, 1); + addLanguageToGroup(groupedList, key, language); + } + return groupedList; + } + /** * @type {Electron.BrowserWindow} */ @@ -59,14 +71,12 @@ class SpellCheckProvider { this.window.webContents.session.setSpellCheckerLanguages(setlanguages); if (setlanguages.length > 0) { this.logger.debug(`Language codes ${setlanguages.join(',')} set for spellchecker`); + } else { + this.logger.debug('Spellchecker is disabled!'); } return setlanguages; } - - setSystemLanguages() { - //this.window.webContents.spl - } } @@ -76,9 +86,11 @@ class SpellCheckProvider { */ function init(intance, window) { const listFromElectron = window.webContents.session.availableSpellCheckerLanguages; - _SpellCheckProvider_supportedList.set(intance, codes.filter(lf => { + var list = codes.filter(lf => { return listContains(listFromElectron, lf.code); - })); + }); + sortLanguages(list); + _SpellCheckProvider_supportedList.set(intance, list); } /** @@ -92,4 +104,36 @@ function listContains(list, text) { }); } +/** + * @param {Array<{key:string,list:{language:string,code:string}}>} groupedList + * @param {string} key + * @param {{language:string,code:string}} language + */ +function addLanguageToGroup(groupedList, key, language) { + const group = groupedList.filter(f => f.key === key)[0]; + if (group) { + group.list.push(language); + } else { + groupedList.push({ + key: key, + list: [language] + }); + } +} + +/** + * @param {Array<{language:string,code:string}} languages + */ +function sortLanguages(languages) { + languages.sort((a, b) => { + return stringCompare(a.language.toLocaleLowerCase(), b.language.toLocaleLowerCase()); + }); +} + +function stringCompare(str1, str2) { + const le = str1 < str2; + const gr = str1 > str2; + return le ? -1 : gr ? 1 : 0; +} + module.exports = { SpellCheckProvider }; \ No newline at end of file diff --git a/com.github.IsmaelMartinez.teams_for_linux.appdata.xml b/com.github.IsmaelMartinez.teams_for_linux.appdata.xml index dde88435..27aadcf1 100644 --- a/com.github.IsmaelMartinez.teams_for_linux.appdata.xml +++ b/com.github.IsmaelMartinez.teams_for_linux.appdata.xml @@ -14,6 +14,13 @@ https://github.com/IsmaelMartinez/teams-for-linux/issues com.github.IsmaelMartinez.teams_for_linux.desktop + + +
    +
  • New: Spellchecker language selections are persisted between runs
  • +
+
+
    diff --git a/package.json b/package.json index 7a0315b2..7a3d1a39 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "teams-for-linux", - "version": "1.2.6", + "version": "1.2.7", "main": "app/index.js", "description": "Unofficial client for Microsoft Teams for Linux", "homepage": "https://github.com/IsmaelMartinez/teams-for-linux",