Skip to content

Commit 6d4ab87

Browse files
authored
Merge pull request #124 from chrisknepper/feature/spell-check-2
Feature/spell check 2
2 parents cd7441f + 1362258 commit 6d4ab87

File tree

12 files changed

+4012
-5501
lines changed

12 files changed

+4012
-5501
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,6 @@ Thumbs.db
1111
/app/background.js
1212
/app/bridge.js
1313
/app/**/*.map
14+
15+
# Dictionary files are downloaded by the user's machine
16+
/resources/dictionaries/**/*

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# Changelog
22

3+
## [0.8.0] - 2019-02-12
4+
### Added
5+
- Spellchecking for various languages (see notes in README)
6+
- Manually refreshing the webview for those times when the app gets all 🤪 (Accessible by pressing Ctrl+R or Cmd+R)
7+
- Full screen toggle item to View menu
8+
9+
### Changed
10+
- Update electron from 2.0.12 to 3.1.3 (Electron 3 is required by electron-updater 4 which is required by electron-builder 20)
11+
12+
### Fixed
13+
- Location of Check for Updates menu item on Windows (Now under Help)
14+
315
## [0.7.1] - 2018-11-17
416
### Changed
517
- Update electron from 2.0.2 to 2.0.12

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,20 @@ Head over to the [latest releases](https://github.com/chrisknepper/android-messa
2828

2929
**Important note:** The Windows app binary isn't signed. This doesn't seem to be a big problem, but please report any issues you run into on Windows that may be related to signing.
3030

31-
**Important note 2:** We currently have builds for Windows and macOS, and Linux. I've only tested on macOS and Windows 10, and would love help testing on Linux and older versions of Windows.
31+
**Important note 2:** We currently have builds for Windows and macOS, and Linux. I test releases on macOS, Windows 10, and Ubuntu Linux. I would love help testing on additional distros of Linux and other versions of Windows.
3232

3333
# Features
3434
* System notifications when a text comes in
3535
* Notification badges on macOS
36+
* Spellchecking in ~50 languages
3637
* Run in background on Windows / Linux / macOS
3738
* Minimize to tray on Windows / Linux
3839
* Menu bar support on macOS
3940
* TBD...
4041

42+
# Spellchecking
43+
Implemented via the amazing [`electron-hunpsell`](https://github.com/kwonoj/electron-hunspell) library with dictionaries provided by the excellent [`dictionaries`](https://github.com/wooorm/dictionaries) project. Language files are downloaded when the app opens and the language used is based on the language set in your operating system. If you switch your system language and restart the app, the spellchecking should occur in the new language as long as it is in the [list of supported languages](https://github.com/wooorm/dictionaries#table-of-dictionaries).
44+
4145
# TODOs / Roadmap (rough order of priority):
4246
- [x] Make sure it actually works (definitely works as of v0.1.0, done via [8068ed2](../../commit/8068ed2))
4347
- [x] Release signed binaries for macOS (binaries are signed as of v0.0.2, done via [8492023](../../commit/8492023))

package-lock.json

Lines changed: 3594 additions & 5473 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"description": "Messages for web, as a desktop app",
55
"version": "0.7.1",
66
"author": "Chris Knepper <[email protected]>",
7-
"copyright": "© 2018 Chris Knepper",
7+
"copyright": "© 2018-2019 Chris Knepper",
88
"homepage": "https://github.com/chrisknepper/android-messages-desktop",
99
"repository": {
1010
"type": "git",
@@ -25,6 +25,9 @@
2525
"directories": {
2626
"buildResources": "resources"
2727
},
28+
"extraResources": [
29+
"resources/dictionaries"
30+
],
2831
"mac": {
2932
"category": "public.app-category.social-networking",
3033
"target": [
@@ -43,7 +46,7 @@
4346
}
4447
},
4548
"scripts": {
46-
"postinstall": "electron-builder install-app-deps",
49+
"postinstall": "electron-builder install-app-deps && npm run install-hunspell && npm run build-hunspell",
4750
"preunit": "webpack --config=build/webpack.unit.config.js --env=test --display=none",
4851
"unit": "electron-mocha temp/specs.js --renderer --require source-map-support/register",
4952
"pree2e": "webpack --config=build/webpack.app.config.js --env=test --display=none && webpack --config=build/webpack.e2e.config.js --env=test --display=none",
@@ -53,13 +56,17 @@
5356
"release": "npm test && webpack --config=build/webpack.app.config.js --env=production && electron-builder -mwl",
5457
"build": "webpack --config=build/webpack.app.config.js --env=production && electron-builder --publish never",
5558
"build-all": "webpack --config=build/webpack.app.config.js --env=production && electron-builder -mwl --publish never",
56-
"generate-icons": "png2icons assets/android_messages_desktop_icon.png resources/icon -all -i"
59+
"generate-icons": "png2icons assets/android_messages_desktop_icon.png resources/icon -all -i",
60+
"install-hunspell": "npm --prefix ./node_modules/electron-hunspell install",
61+
"build-hunspell": "npm --prefix ./node_modules/electron-hunspell run build"
5762
},
5863
"dependencies": {
5964
"about-window": "^1.11.1",
65+
"electron-hunspell": "https://github.com/kwonoj/electron-hunspell/tarball/v1.0.0-beta.5",
6066
"electron-settings": "^3.2.0",
61-
"electron-updater": "^2.21.10",
62-
"fs-jetpack": "^1.0.0"
67+
"electron-updater": "4.0.6",
68+
"fs-jetpack": "^1.0.0",
69+
"hunspell-asm": "^1.1.2"
6370
},
6471
"devDependencies": {
6572
"@babel/core": "^7.0.0-beta.5",
@@ -68,7 +75,7 @@
6875
"babel-plugin-transform-object-rest-spread": "^7.0.0-beta.3",
6976
"chai": "^4.1.0",
7077
"css-loader": "^0.28.7",
71-
"electron": "2.0.12",
78+
"electron": "3.1.3",
7279
"electron-builder": "^20.15.1",
7380
"electron-mocha": "^6.0.4",
7481
"file-loader": "^1.1.11",

resources/dictionaries/.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Ignore everything in this directory
2+
*
3+
# Except this file
4+
!.gitignore
5+
6+
# This, along with the extraFiles electron-builder directive in package.json ensures that
7+
# resources/dictionaries folder is included as an empty folder in production/user-facing builds.
8+
# It must be done this way because some OSes install the app to a location from which the user does not
9+
# have the permission to create a subdirectory unless they run the app as root. Namely, Ubuntu, via the .deb,
10+
# installs the app to /opt/ and calling node mkdir only works as root from there.

src/background.js

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@ import { devMenuTemplate } from './menu/dev_menu_template';
1212
import { settingsMenu } from './menu/settings_menu_template';
1313
import { helpMenuTemplate } from './menu/help_menu_template';
1414
import createWindow from './helpers/window';
15+
import DictionaryManager from './helpers/dictionary_manager';
1516
import TrayManager from './helpers/tray/tray_manager';
1617
import settings from 'electron-settings';
17-
import { IS_MAC, IS_WINDOWS, IS_LINUX, IS_DEV, SETTING_TRAY_ENABLED, SETTING_TRAY_CLICK_SHORTCUT, EVENT_WEBVIEW_NOTIFICATION, EVENT_NOTIFICATION_REFLECT_READY } from './constants';
18+
import { IS_MAC, IS_WINDOWS, IS_LINUX, IS_DEV, SETTING_TRAY_ENABLED, SETTING_TRAY_CLICK_SHORTCUT, SETTING_CUSTOM_WORDS, EVENT_WEBVIEW_NOTIFICATION, EVENT_NOTIFICATION_REFLECT_READY, EVENT_BRIDGE_INIT, EVENT_SPELL_ADD_CUSTOM_WORD, EVENT_SPELLING_REFLECT_READY } from './constants';
1819

1920
// Special module holding environment variables which you declared
2021
// in config/env_xxx.json file.
@@ -181,6 +182,57 @@ if (isSecondInstance) {
181182
}
182183
});
183184

185+
ipcMain.on(EVENT_BRIDGE_INIT, async (event) => {
186+
187+
let spellCheckFiles = null;
188+
let customWords = null;
189+
const currentLanguage = app.getLocale();
190+
try {
191+
// TODO: Possibly don't check supported-languages.json every load if local dictionary files already exist
192+
const supportedLanguages = await DictionaryManager.getSupportedLanguages();
193+
194+
const dictionaryLocaleKey = DictionaryManager.doesLanguageExistForLocale(currentLanguage, supportedLanguages);
195+
196+
if (dictionaryLocaleKey) { // Spellchecking is supported for the current language
197+
spellCheckFiles = await DictionaryManager.getLanguagePath(currentLanguage, dictionaryLocaleKey);
198+
199+
// We send an event with the language key and array of custom words to the webview bridge which contains the
200+
// instance of the spellchecker. Done this way because passing class instances (i.e. of the spellchecker)
201+
// between electron processes is hacky at best and impossible at worst.
202+
const existingCustomWords = settings.get(SETTING_CUSTOM_WORDS, {});
203+
204+
customWords = {};
205+
if (currentLanguage in existingCustomWords) {
206+
customWords = { [currentLanguage]: existingCustomWords[currentLanguage] };
207+
}
208+
}
209+
}
210+
catch (error) {
211+
// TODO: Display this as an error message to the user?
212+
}
213+
214+
event.sender.send(EVENT_SPELLING_REFLECT_READY, {
215+
dictionaryLocaleKey: currentLanguage,
216+
spellCheckFiles,
217+
customWords
218+
});
219+
});
220+
221+
ipcMain.on(EVENT_SPELL_ADD_CUSTOM_WORD, (event, msg) => {
222+
// Add custom words picked by the user to a persistent data store because they must be added to
223+
// the instance of Hunspell on each launch of the app/loading of the dictionary.
224+
const { newCustomWord } = msg;
225+
const currentLanguage = app.getLocale();
226+
const existingCustomWords = settings.get(SETTING_CUSTOM_WORDS, {});
227+
if (!(currentLanguage in existingCustomWords)) {
228+
existingCustomWords[currentLanguage] = [];
229+
}
230+
if (newCustomWord && !existingCustomWords[currentLanguage].includes(newCustomWord)) {
231+
existingCustomWords[currentLanguage].push(newCustomWord);
232+
settings.set(SETTING_CUSTOM_WORDS, existingCustomWords);
233+
}
234+
});
235+
184236
let quitViaContext = false;
185237
app.on('before-quit', () => {
186238
quitViaContext = true;

src/constants/index.js

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import env from 'env';
2+
import path from 'path';
23

34
const osMap = {
45
win32: 'Windows',
@@ -15,14 +16,25 @@ const IS_LINUX = (osName === 'linux');
1516

1617
// Environment
1718
const IS_DEV = (env.name === 'development');
19+
const BASE_APP_PATH = IS_DEV ? path.join(__dirname, '..') : process.resourcesPath;
20+
const RESOURCES_PATH = path.join(BASE_APP_PATH, 'resources');
21+
const SPELLING_DICTIONARIES_PATH = path.join(RESOURCES_PATH, 'dictionaries');
22+
const SUPPORTED_LANGUAGES_PATH = path.join(SPELLING_DICTIONARIES_PATH, 'supported-languages.json');
1823

1924
// Settings
2025
const SETTING_TRAY_ENABLED = 'trayEnabledPref';
2126
const SETTING_TRAY_CLICK_SHORTCUT = 'trayClickShortcut';
27+
const SETTING_CUSTOM_WORDS = 'savedCustomDictionaryWords'
2228

2329
// Events
2430
const EVENT_WEBVIEW_NOTIFICATION = 'messages-webview-notification';
2531
const EVENT_NOTIFICATION_REFLECT_READY = 'messages-webview-reflect-ready';
32+
const EVENT_BRIDGE_INIT = 'messages-bridge-init';
33+
const EVENT_SPELL_ADD_CUSTOM_WORD = 'messages-spelling-add-custom-word';
34+
const EVENT_SPELLING_REFLECT_READY = 'messages-spelling-reflect-ready';
35+
36+
// Misc.
37+
const DICTIONARY_CACHE_TIME = 2592000000; // 30 days in milliseconds
2638

2739
export {
2840
osName,
@@ -31,8 +43,17 @@ export {
3143
IS_MAC,
3244
IS_LINUX,
3345
IS_DEV,
46+
BASE_APP_PATH,
47+
RESOURCES_PATH,
48+
SPELLING_DICTIONARIES_PATH,
49+
SUPPORTED_LANGUAGES_PATH,
3450
SETTING_TRAY_ENABLED,
3551
SETTING_TRAY_CLICK_SHORTCUT,
52+
SETTING_CUSTOM_WORDS,
3653
EVENT_WEBVIEW_NOTIFICATION,
37-
EVENT_NOTIFICATION_REFLECT_READY
54+
EVENT_NOTIFICATION_REFLECT_READY,
55+
EVENT_BRIDGE_INIT,
56+
EVENT_SPELL_ADD_CUSTOM_WORD,
57+
EVENT_SPELLING_REFLECT_READY,
58+
DICTIONARY_CACHE_TIME
3859
};

0 commit comments

Comments
 (0)