Compare commits

...

178 Commits

Author SHA1 Message Date
Akash Nimare
3dade768a7 Merge pull request #141 from Lplenka/Certificate_Issue
 Added support for self-signed certificate fixes #126
2017-04-28 02:46:18 +05:30
Lalu Prasad Lenka
7b3c7ba5fa Merge branch 'master' into Certificate_Issue 2017-04-28 02:28:12 +05:30
Akash Nimare
616bc0f73b Merge pull request #144 from Lplenka/offline
Fixed internet connectivity error on Linux
2017-04-28 02:23:46 +05:30
Lplenka
8ecdf1f18a Update PR #115 code clean-up 2017-04-28 01:50:23 +05:30
Lplenka
d2daa65059 Update PR #115 Added ERR_NAME_NOT_RESOLVED condition 2017-04-28 00:38:55 +05:30
Lplenka
487ee538e3 Lint error fix 🔧 2017-04-27 12:54:31 +05:30
Lplenka
6382c6d2b3 Improved PR #115 2017-04-27 12:50:53 +05:30
Lplenka
cbcff67d28 [WIP] issue #126, now not remembering servers 2017-04-21 18:39:58 +05:30
akashnimare
61a429365b support self-signed cert fixing #126 [WIP] 2017-04-18 04:57:33 +05:30
akashnimare
e55f38a962 🚚 moved files to renderer 2017-04-18 04:17:32 +05:30
akashnimare
81798583ae unused tray.js from main process deleted + travis test 2017-04-18 04:04:15 +05:30
akashnimare
9cab61cebc 🎉 bump v0.5.10 2017-04-18 00:40:22 +05:30
Akash Nimare
f290732cb6 Merge pull request #134 from Lplenka/master
Added unread counts in tray icon Fixes #110
2017-04-18 00:26:36 +05:30
Lplenka
2dd44852fa Lint error fixed #126[WIP] 2017-04-17 14:22:30 +05:30
Lplenka
bd2f17deec Removed Error from console #126[WIP] 2017-04-17 12:55:41 +05:30
Lplenka
06faf46bcc Support for Switching to server with certificate error #126[WIP] 2017-04-17 12:39:54 +05:30
Lplenka
468e9d539b issue #126 [WIP] 2017-04-17 12:15:07 +05:30
akashnimare
449f407236 Enable cache on travis 2017-04-17 00:20:51 +05:30
Lplenka
7efe90e709 🔧 Lint Error fixed 2017-04-14 09:16:09 +05:30
Lalu Prasad Lenka
184e1a5bc4 Merge branch 'master' into master 2017-04-14 08:20:29 +05:30
Akash Nimare
85e7b337a7 Fixing travis test [WIP] 2017-04-14 06:37:08 +05:30
akashnimare
83759bde1c using known working version for devdependencies 2017-04-14 05:11:51 +05:30
akashnimare
d9b1d45e0e 🔧 fix linting errors 2017-04-14 04:54:44 +05:30
Akash Nimare
df91c20f36 Merge pull request #137 from brockwhittaker/landing-page-redesign
Redesign the landing page to look more inline with brand design.
2017-04-14 04:30:26 +05:30
brockwhittaker
c1f6159d69 Redesign the landing page to look more inline with brand design.
This redesigns the landing page to incorporate the Zulip style guide.
This also adds two animations:

1. The error text slides down on error and back up when typing.
2. The form section shakes when there is invalid input for 0.5s.
2017-04-13 12:03:45 -07:00
Akash Nimare
5a0461211a remove typo 2017-04-13 01:38:41 +05:30
Akash Nimare
1394f790c3 Merge pull request #136 from brockwhittaker/master
about: Restyle Electron => Zulip desktop page.
2017-04-13 01:06:05 +05:30
brockwhittaker
4d374ff40c Restyle Electron => Zulip desktop page.
This restyles the "about" page to look slicker and have brand colors.
2017-04-12 12:24:27 -07:00
akashnimare
0d15435408 🔖 v0.5.9 2017-04-11 01:54:39 +05:30
Lalu Prasad Lenka
d4448ba086 Merge branch 'master' into master 2017-04-09 10:02:42 +05:30
akashnimare
4bd6fde5b6 remove unused dependency configstore 2017-04-09 02:37:12 +05:30
Akash Nimare
e5097ace06 📝 use nvm to install nodejs #135 2017-04-05 19:48:13 +05:30
Lplenka
ca078cbbfd Fixed size bug in Mac OS #110 [WIP] 2017-04-02 13:29:14 +05:30
Lplenka
6d45105b69 Fixed bug in Mac OS #110 [WIP] 2017-04-02 13:24:56 +05:30
Lplenka
40f81af2dd Lint error fixed #110 [WIP] 2017-04-02 11:06:39 +05:30
Lalu Prasad Lenka
d5e6184e75 Fixed bugs in Windows #110 [WIP] 2017-04-02 05:09:43 +05:30
Lplenka
0ec38ba41d Added function to set tray size according to OS, fixed toggle tray 2017-04-02 09:33:13 +05:30
Lplenka
460a64710a Js Lint error fixed 🔧, Fixes #110 2017-04-02 07:40:29 +05:30
Lplenka
9ec62a748f Added communication b/w Main & Renderer process for proper functioning of Tray icon #110 [WIP] 2017-04-02 01:21:33 +05:30
Lplenka
a7a80cef99 Added Tray.js to renderer js files 2017-04-02 00:55:48 +05:30
akashnimare
bcaf54b349 🔥 remove macOs swipe navigation 2017-04-01 11:19:39 -07:00
akashnimare
1f6d0762bb 🐛 fixing configstore permission issue on windows #125 [WIP] 2017-04-01 10:47:52 -07:00
akashnimare
1aa1655676 🔧 update electron-builder/updater to latest fixes #133 2017-03-31 02:02:47 +05:30
akashnimare
0ad66399d0 🐛 set valid config #133 2017-03-31 01:23:44 +05:30
akashnimare
3a6bb14224 🐛 fixing dmg build failed [WIP] #133 2017-03-31 00:47:26 +05:30
Akash Nimare
53eb8051ad Update CONTRIBUTING.md 2017-03-23 15:45:30 +05:30
Akash Nimare
ed9174f57c Merge pull request #119 from sumedh123/master
updated contributing guide
2017-03-23 15:44:10 +05:30
Akash Nimare
260d6a1906 Updated community section 2017-03-23 15:42:27 +05:30
Akash Nimare
dc53319c8e 🆙 bump electron-spellcheck to v1.0.5 2017-03-21 00:43:10 +05:30
Akash Nimare
77369536b3 Merge pull request #130 from Lplenka/master
Check if zulip server is down Fixes Issue #124
2017-03-20 12:31:18 +05:30
Lplenka
531afcb1e5 Fixed root directory's package.json 2017-03-19 17:33:53 +05:30
Lplenka
d6c4eeccf8 Code formatting done 2017-03-19 01:23:13 +05:30
Lplenka
496b906fd0 Merge branch 'master' of https://github.com/Lplenka/zulip-electron 2017-03-19 01:18:32 +05:30
Lplenka
1be29faea6 Removed spaces from imported/exported varibles & fixed the package.json in app folder 2017-03-19 01:16:07 +05:30
Akash Nimare
bc9a7c9890 update copyright 2017-03-19 00:50:50 +05:30
Lplenka
5745276dbb Code formatting done Fixes #124 2017-03-18 13:20:15 +05:30
Lplenka
acf0282aa0 Checks Server error while switching server 2017-03-18 12:40:38 +05:30
Lplenka
54d942178a Implemented function in index to check server error while loading 2017-03-18 12:32:43 +05:30
Lplenka
d84ada373e Added https node module 2017-03-18 12:22:29 +05:30
Lplenka
d4d36d0582 Removed reductant call to prefDomain() 2017-03-18 12:14:12 +05:30
Lplenka
63e6c634b9 Added Node global symbols to avoid setImmdediate Reference Error 2017-03-18 12:11:45 +05:30
Lplenka
4bc558cdbc Merge branch 'master' of https://github.com/Lplenka/zulip-electron 2017-03-18 09:04:19 +05:30
Cynthia Lin
34293fd66b Enable zulipbot build notifications.
PRs labeled with the *travis updates* label will receive build notifications from zulipbot.
2017-03-18 08:52:52 +05:30
Akash Nimare
5eba4b8200 Merge pull request #129 from synicalsyntax/patch-1
Enable zulipbot build notifications.
2017-03-18 00:48:47 +05:30
Akash Nimare
a949307820 Merge pull request #128 from Lplenka/master
show window when the web page has been rendered and window can be displayed without a visual flash.
2017-03-18 00:28:16 +05:30
Cynthia Lin
a714977b5a Enable zulipbot build notifications.
PRs labeled with the *travis updates* label will receive build notifications from zulipbot.
2017-03-11 11:46:43 -08:00
Lplenka
bfcaa51c46 🐛 🔧 linting error fixed 2017-03-11 01:55:48 +05:30
Lplenka
d7d3017bc1 Bug Fixes 2017-03-11 01:46:35 +05:30
Lalu Prasad Lenka
c7ce8fb7c8 Merge pull request #2 from zulip/master
Merging with zulip-electron origin
2017-03-07 13:42:02 +05:30
Sumedh Nimkarde
65a80de01d update Community section 2017-03-07 07:52:30 +05:30
akashnimare
f6bf210451 🔨 fixed linting errors 2017-03-06 15:18:52 +05:30
Akash Nimare
8c23ec3417 Merge pull request #122 from geeeeeeeeek/feature/#104-add-option-to-hide-tray-icon
#104 Add a menu item to toggle the tray icon.
2017-03-06 15:01:50 +05:30
Akash Nimare
97bbd809f7 Merge pull request #121 from geeeeeeeeek/bugfix/#120-fix-error-launching
#120 Fix error launching caused by missing  keyword.
2017-03-06 14:31:38 +05:30
Akash Nimare
76381cac08 Merge pull request #118 from Lplenka/master
Added localhost support fixes #78
2017-03-06 14:30:29 +05:30
Sumedh Nimkarde
13c4ceedc2 add Community section 2017-03-05 22:47:43 +05:30
Sumedh Nimkarde
f0889edf9c add zulipbot link 2017-03-05 15:38:18 +05:30
Zhongyi Tong
ab8367c946 #104 Add a menu item to toggle the tray icon. 2017-03-05 00:54:55 +08:00
Zhongyi Tong
c5887c8f71 #120 Fix error launching caused by missing keyword. 2017-03-04 23:46:26 +08:00
Sumedh Nimkarde
7b7ab03d0b add Chat section 2017-03-04 11:23:20 +05:30
Lplenka
394caa7934 Issue fix in better way 2017-03-04 10:02:27 +05:30
Lplenka
db2860b53e code formatting done 2017-03-04 01:32:34 +05:30
Lplenka
6d20df3557 Changed error message 2017-03-04 01:01:31 +05:30
Lplenka
2942cd1244 merge conflicts resolved 2017-03-04 00:44:40 +05:30
Lplenka
174049f489 issue #78 fixed 2017-03-04 00:16:41 +05:30
Lalu Prasad Lenka
21eae28999 Merge pull request #1 from zulip/master
Update from Original
2017-03-03 11:04:39 +05:30
akashnimare
f256cbcd5d Added error message when input url is null fixes #116 2017-03-02 17:35:20 +05:30
akashnimare
ff8c20f0b4 Removed unnessary code #116 2017-03-02 17:08:42 +05:30
akashnimare
9e0c17a793 🐛 fixing it in preference window #116 2017-03-02 17:05:01 +05:30
akashnimare
b4fb00aa52 🐛 show error message if input server url is null #116 2017-03-02 16:47:41 +05:30
akashnimare
13d0b5e51c Fixed linting error 2017-03-02 16:00:33 +05:30
Akash Nimare
dc15e4578c Merge pull request #115 from jajodiaraghav/offline
Display an error message if internet not working.
2017-03-02 15:36:19 +05:30
Raghav Jajodia
673da66ee9 Display error message if internet not working.
An error message with 'Try again' option is displayed
if the internet is not working.
Fixes #114
2017-02-28 23:01:13 +05:30
Akash Nimare
e397e9bfb4 Merge pull request #113 from chiragjn/master
Fix issue #112 for displaying Keyboard shortcuts
2017-02-24 14:35:48 +05:30
Chirag Jain
4eca2e9254 Fix lint errors 2017-02-24 11:31:10 +05:30
Chirag Jain
a1407826b6 Fix issue #112 for displaying Keyboard shortcuts 2017-02-24 10:57:29 +05:30
akashnimare
6d8f83798b 📦 update dependencies 2017-02-24 02:34:42 +05:30
akashnimare
bfc03c7e95 🐛 fix useragent + notifications #108 + #111 2017-02-24 02:30:13 +05:30
akashnimare
06737ce629 👌 detect Windows version (7/10) #108 2017-02-21 01:04:24 +05:30
akashnimare
6b09840347 improving usergent #108 2017-02-21 00:29:20 +05:30
akashnimare
19b5eecdcd Check if webview's url is failing travis tests on linux [WIP] #109 2017-02-18 16:51:31 +05:30
akashnimare
f443918433 🔧 added spellchecker dependencies in travis 🐧 2017-02-18 16:10:54 +05:30
akashnimare
bb74e58d63 🎨 fixed linting + #108 2017-02-18 15:56:41 +05:30
akashnimare
612e670bb5 🐛 added app version + os details in useragent #108 2017-02-18 15:17:30 +05:30
akashnimare
34bb55cb9f 🐛 set user-agent to ZulipElectron/version #108 2017-02-17 15:39:06 +05:30
akashnimare
1457e82649 📦 updated dependencies 2017-02-17 00:15:14 +05:30
akashnimare
0bdeaaba18 removed unused dependency dialogs 2017-02-17 00:02:27 +05:30
akashnimare
e2286b6110 🚀 windows build script + nsis web installer 2017-02-14 00:28:06 +05:30
akashnimare
27ba3f3068 removed squirrel events code 2017-02-14 00:22:40 +05:30
akashnimare
9859315fea improve logging in autoupdater[WIP] 2017-02-13 23:54:47 +05:30
akashnimare
73d18dde9e init v0.5.8 + updated dependencies 2017-02-13 20:13:33 +05:30
akashnimare
0372befc5a bump version v0.5.7 2017-02-08 10:37:02 +05:30
akashnimare
063799a053 Updated login page title + placeholder 2017-02-07 18:37:14 +05:30
akashnimare
297b307726 update electron-builder to v13.0.0 2017-02-07 14:20:43 +05:30
akashnimare
deed66973f update electron-builder to v13.0.0 2017-02-07 14:20:17 +05:30
akashnimare
03486e438d remove release name+notes details from autoupdater 2017-02-07 14:17:04 +05:30
Akash Nimare
e113f59aad Bump electron-builder to 12.3.1 2017-02-06 02:30:35 +05:30
Akash Nimare
29ece4824a Merge pull request #105 from zulip/nsis
🎉 switched to NSIS + autoupdates
2017-02-06 01:23:55 +05:30
akashnimare
66c62c55e2 fixed logger undefined error 2017-02-06 01:09:03 +05:30
akashnimare
40852942d2 fixed releaseName undefined error 2017-02-02 16:41:52 +05:30
akashnimare
15c8591691 windows installer >> install per all users 2017-02-02 16:16:32 +05:30
akashnimare
e21902a5e3 🆙 electron-updater to 1.4.1 2017-02-02 15:37:10 +05:30
akashnimare
a5d42e8ccd log whats happening in auto-updater 2017-02-02 12:06:13 +05:30
akashnimare
0923df7250 import autoupdater 2017-02-02 11:52:27 +05:30
akashnimare
37f5258210 updated to electron-builder's latest version 2017-02-02 11:07:31 +05:30
akashnimare
19819f7d48 squirrel startup is not needed for NSIS 2017-01-28 21:21:52 +05:30
akashnimare
40f74cdac2 removed auto updater feed 2017-01-28 13:44:07 +05:30
akashnimare
e4ba3b9721 Added electron-updater dependency autoupdates 2017-01-28 13:21:41 +05:30
akashnimare
9a221585b9 set target to NSIS 2017-01-27 11:23:13 +05:30
Akash Nimare
069a0ff306 Added iconUrl to win.build 2017-01-26 02:10:17 +05:30
akashnimare
3153fb91da 🚀 Added back/forward navigation 2017-01-26 01:30:21 +05:30
Akash Nimare
92d4d27fa8 Added app icon >> windows installer 2017-01-26 00:50:50 +05:30
Akash Nimare
209fc4a65c Added squirrel-windows dependency 2017-01-26 00:47:55 +05:30
Akash Nimare
5e9ecedecd Updated electron-builder to v11.5.1 2017-01-25 23:48:30 +05:30
Akash Nimare
613df32bf1 Updated Prerequisites 2017-01-25 23:03:35 +05:30
Akash Nimare
7606f37695 Merge pull request #102 from zulip/dev
update spellchecker to v1.0.0
2017-01-25 22:55:36 +05:30
akashnimare
a2f758a46b spellchecker v1.0.0 2017-01-24 13:03:05 +05:30
akashnimare
2a477abe5f Added log-out shortcut 2017-01-14 23:43:09 +05:30
akashnimare
5f027820f4 ✏️ small typos fixed 2017-01-14 22:42:28 +05:30
Akash Nimare
9e75861546 Fixing travis test (linux) 2017-01-07 17:50:56 +05:30
akashnimare
4060596474 🎨 fixed linting errors 2017-01-07 17:27:54 +05:30
Akash Nimare
2e5888c8af Merge pull request #96 from jajodiaraghav/add_clear_cache_option
Added Clear-cache option in menu
2017-01-07 17:07:09 +05:30
Raghav Jajodia
03d1188e14 Added clear cache option 2017-01-07 17:00:03 +05:30
Raghav Jajodia
c91b0c209a Added clear cache option 2017-01-07 15:58:19 +05:30
Akash Nimare
531973194c Use stable module version
Using stable version of node modules. 
Using '*' or 'latest' in node modules version could cause unexpected results and could break your code.
2017-01-03 15:14:56 +05:30
akashnimare
4d1face275 Removed electron-context-menu 2017-01-03 14:45:04 +05:30
akashnimare
ca7503f1f0 using electron-builder v10.15.1 2017-01-03 14:42:52 +05:30
Akash Nimare
9c163b4166 Merge pull request #97 from zulip/dev
export spellchecker function
2017-01-02 19:19:11 +05:30
akashnimare
742afb1c09 export spellchecker function 2017-01-02 19:15:08 +05:30
Raghav Jajodia
f9f70f001b Added clear cache option 2017-01-02 13:50:19 +05:30
akashnimare
edf34efd86 Removed unnecessary dep. electron-dl 2016-12-31 22:26:42 +05:30
akashnimare
72ebed95da v0.5.4 2016-12-31 22:17:51 +05:30
Akash Nimare
975a6ab8bf electron-spellchecker
Downgrading since v0.7.1 is not working properly on linux.
2016-12-31 22:06:19 +05:30
akashnimare
3352301b67 :head_bandage: update electron-spellchecker 2016-12-31 20:28:09 +05:30
Akash Nimare
358260f766 Update README.md 2016-12-30 03:14:32 +05:30
Akash Nimare
b58052ce34 Merge pull request #94 from GervaisdeM/launch-script-tweak
rename zulip-electron-updater-and-launcher.sh to
2016-12-29 07:29:16 +05:30
GervaisdeM
de9ad8082b rename zulip-electron-updater-and-launcher.sh to
zulip-electron-launcher.sh

changed `npm upgrade` to `npm install`
2016-12-27 00:39:06 -04:00
akashnimare
d6bf84c821 🆙 Linux app version 2016-12-25 02:32:01 +05:30
Akash Nimare
d5cba4096d Update README.md 2016-12-23 02:40:01 +05:30
Akash Nimare
afa12cc266 Update README.md 2016-12-23 02:38:41 +05:30
Akash Nimare
42ede5e54b typo in email 2016-12-23 02:35:56 +05:30
Akash Nimare
1549db5ce0 Merge pull request #93 from zulip/autoupdates
🎉 Autoupdates for windows
2016-12-23 02:35:01 +05:30
akashnimare
a0de440c2e Unregister shortcuts on will-quit 2016-12-23 02:10:45 +05:30
akashnimare
7e54eb89c2 manage squirrel events 2016-12-23 01:48:22 +05:30
akashnimare
f8e77dfa72 Using squirrel.windows 2016-12-23 01:32:08 +05:30
akashnimare
db6d1f300a adding windows auto-update 2016-12-22 02:30:48 +05:30
Akash Nimare
eac2b92cb6 ⬆️ Test timeout 2016-12-16 15:20:03 +05:30
Akash Nimare
a349e0e4e0 Check linux travis 2016-12-16 14:32:02 +05:30
Akash Nimare
58f35569c8 Added trusty option for linux travis 2016-12-16 03:23:20 +05:30
Akash Nimare
4a9f51aa1b Autoupdate button >> later 2016-12-16 02:01:37 +05:30
Akash Nimare
5bb05906b5 Merge pull request #92 from zulip/dev
Update master with dev branch
2016-12-16 01:59:00 +05:30
akashnimare
f80095d953 Updated travis build script 2016-12-15 20:53:35 +05:30
akashnimare
181803755a fix OSX travis build 2016-12-15 20:39:50 +05:30
akashnimare
ef30cd9624 💚 Fixing CI Build 2016-12-15 20:21:05 +05:30
akashnimare
7c82f41e87 🎨 fixed linting errors 2016-12-15 19:59:12 +05:30
akashnimare
61dfcfc3b1 🐛 unregister keyboard shortcuts 2016-12-15 01:57:20 +05:30
Akash Nimare
e3deb93730 Update Zulip server 2016-12-14 03:16:45 +05:30
Akash Nimare
d6a3e5fe1b Updated zulip server 2016-12-14 03:15:33 +05:30
akashnimare
dc15edf0cd Unsubscribe spellchekcer 2016-12-14 03:02:01 +05:30
31 changed files with 1005 additions and 740 deletions

View File

@@ -1,12 +1,21 @@
language: node_js sudo: required
dist: trusty
os: os:
- osx - osx
- linux - linux
sudo: required
addons:
apt:
packages:
- build-essential
- libxext-dev
- libxtst-dev
- libxkbfile-dev
language: node_js
node_js: node_js:
- 'node' - '6'
before_install: before_install:
- npm install -g gulp - npm install -g gulp
@@ -15,6 +24,13 @@ before_install:
cache: cache:
directories: directories:
- node_modules - node_modules
- app/node_modules
script: script:
- npm run travis - npm run travis
notifications:
webhooks:
urls:
- https://zulip.org/zulipbot/travis
on_success: always
on_failure: always

View File

@@ -1,16 +1,24 @@
#Contributing Guidelines # Contributing Guidelines
Thanks for taking the time to contribute! Thanks for taking the time to contribute!
The following is a set of guidelines for contributing to zulip-electron. These are just guidelines, not rules, use your best judgment and feel free to propose changes to this document in a pull request. The following is a set of guidelines for contributing to zulip-electron. These are just guidelines, not rules, use your best judgement and feel free to propose changes to this document in a pull request.
## Getting Started ## Getting Started
Zulip-Desktop app is built on top of [Electron](http://electron.atom.io/). If you are new to Electron please head over to [this](http://jlord.us/essential-electron/) great article. Zulip-Desktop app is built on top of [Electron](http://electron.atom.io/). If you are new to Electron please head over to [this](http://jlord.us/essential-electron/) great article.
## Community
* The whole zulip documentation such as development environment, setting up with zulip project, testing, code of conduct can be read [here](https://zulip.readthedocs.io).
* If you have any questions regarding zulip-electron, open an [issue](https://github.com/zulip/zulip-electron/issues/new/) or ask it [here](https://chat.zulip.org/#narrow/stream/electron).
## Issue ## Issue
Ensure the bug was not already reported by searching on GitHub under [Issues](https://github.com/zulip/zulip-electron/issues). If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/zulip/zulip-electron/issues/new). Please pay attention to following points while opening an issue. Ensure the bug was not already reported by searching on GitHub under [Issues](https://github.com/zulip/zulip-electron/issues). If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/zulip/zulip-electron/issues/new). Please pay attention to following points while opening an issue.
The [Zulipbot](https://github.com/zulip/zulipbot) helps to claim the issue by commenting the following in the comment section: "**@zulipbot** claim". **@zulipbot** will assign you to the issue and label the issue as **in progress**. For more details, check out [**@zulipbot**](https://github.com/zulip/zulipbot).
### Does it happen on web browsers? (especially Chrome) ### Does it happen on web browsers? (especially Chrome)
Zulip-Desktop is based on Electron, which integrates the Chrome engine within a standalone application. Zulip-Desktop is based on Electron, which integrates the Chrome engine within a standalone application.
If the problem you encounter can be reproduced on web browsers, it may be an issue with Zulip web app. If the problem you encounter can be reproduced on web browsers, it may be an issue with Zulip web app.

View File

@@ -13,11 +13,13 @@ multi-account, auto-updates etc.
## Prerequisites ## Prerequisites
* node >= v6.3.1 * node >= v6.3.1
* npm >= 3.10.3 > Use [nvm](https://github.com/creationix/nvm) to install the current stable version of node
* If you're on Debian or Ubuntu, you'll also need to install
`nodejs-legacy`:
* python (v2.7.x recommended)
* If you're on Debian or Ubuntu, you'll need to install following packages:
```sh ```sh
$ sudo apt-get install nodejs-legacy $ sudo apt-get install build-essential libxext-dev libxtst-dev libxkbfile-dev
``` ```
## Installation ## Installation
@@ -60,6 +62,8 @@ You can create Windows installer only when running on Windows, the same is true
- [x] Native Notifications - [x] Native Notifications
- [x] SpellChecker - [x] SpellChecker
- [x] OSX/Win/Linux installer
- [x] Automatic Updates (macOS/Windows)
- [x] Keyboard shortcuts - [x] Keyboard shortcuts
Description | Keys Description | Keys
@@ -69,9 +73,6 @@ Change Zulip Server | <kbd>Cmd/Ctrl</kbd> <kbd>,</kbd>
Back | <kbd>Cmd/Ctrl</kbd> <kbd>[</kbd> Back | <kbd>Cmd/Ctrl</kbd> <kbd>[</kbd>
Forward | <kbd>Cmd/Ctrl</kbd> <kbd>]</kbd> Forward | <kbd>Cmd/Ctrl</kbd> <kbd>]</kbd>
- [x] OSX/Win/Linux installer
- [ ] Launch on OS startup
- [ ] Automatic Updates
## Contribute ## Contribute

View File

@@ -1,49 +1,47 @@
'use strict'; 'use strict';
const {app, autoUpdater, dialog} = require('electron'); const {app, dialog} = require('electron');
const version = app.getVersion(); const {autoUpdater} = require('electron-updater');
const os = require('os');
const platform = os.platform() + '_' + os.arch(); // usually returns darwin_64
const updaterFeedURL = 'http://zulipdesktop.herokuapp.com/update/'+ platform + '/' + version;
function appUpdater() { function appUpdater() {
autoUpdater.setFeedURL(updaterFeedURL);
// Log whats happening // Log whats happening
autoUpdater.on('error', err => console.log(err)) const log = require('electron-log');
autoUpdater.on('checking-for-update', () => console.log('checking-for-update')) log.transports.file.level = 'info';
autoUpdater.on('update-available', () => console.log('update-available')) autoUpdater.logger = log;
autoUpdater.on('update-not-available', () => console.log('update-not-available')) /*
AutoUpdater.on('error', err => log.info(err));
autoUpdater.on('checking-for-update', () => log.info('checking-for-update'));
autoUpdater.on('update-available', () => log.info('update-available'));
autoUpdater.on('update-not-available', () => log.info('update-not-available'));
*/
// Ask the user if update is available // Ask the user if update is available
autoUpdater.on('update-downloaded', (event, releaseNotes, releaseName, releaseDate) => { // eslint-disable-next-line no-unused-vars
autoUpdater.on('update-downloaded', (event, info) => {
let message = app.getName() + ' ' + releaseName + ' is now available. It will be installed the next time you restart the application.'; // Let message = app.getName() + ' ' + info.releaseName + ' is now available. It will be installed the next time you restart the application.';
if (releaseNotes) { // if (info.releaseNotes) {
let splitNotes = releaseNotes.split(/[^\r]\n/); // const splitNotes = info.releaseNotes.split(/[^\r]\n/);
message += '\n\nRelease notes:\n'; // message += '\n\nRelease notes:\n';
splitNotes.forEach(function (notes) { // splitNotes.forEach(notes => {
message += notes + '\n\n'; // message += notes + '\n\n';
}) // });
}; // }
// Ask user to update the app // Ask user to update the app
dialog.showMessageBox({ dialog.showMessageBox({
type: 'question', type: 'question',
buttons: ['Install and Relaunch' ,'Cancel'], buttons: ['Install and Relaunch', 'Later'],
defaultId: 0, defaultId: 0,
message: 'A new version of ' + app.getName() + ' has been downloaded', message: 'A new version of ' + app.getName() + ' has been downloaded',
detail: message detail: 'It will be installed the next time you restart the application'
}, response => { }, response => {
if (response === 0) { if (response === 0) {
setTimeout(() => autoUpdater.quitAndInstall(), 1); setTimeout(() => autoUpdater.quitAndInstall(), 1);
} }
}) });
}) });
// init for updates // Init for updates
autoUpdater.checkForUpdates() autoUpdater.checkForUpdates();
} }
exports = module.exports = { module.exports = {
appUpdater appUpdater
} };

View File

@@ -1,36 +0,0 @@
const JsonDB = require('node-json-db');
const {app} = require('electron').remote;
const request = require('request');
const ipcRenderer = require('electron').ipcRenderer;
const db = new JsonDB(app.getPath('userData') + '/domain.json', true, true);
const data = db.getData('/');
console.log(data.domain);
// if (data.domain && window.location.href.indexOf(data.domain) === -1) {
// window.location.href = data.domain
// }
// require('electron-connect').client.create();
window.addDomain = function () {
document.getElementById('main').innerHTML = 'checking...';
let newDomain = document.getElementById('url').value;
newDomain = newDomain.replace(/^https?:\/\//, '');
const domain = 'https://' + newDomain;
const checkDomain = domain + '/static/audio/zulip.ogg';
request(checkDomain, (error, response) => {
if (!error && response.statusCode !== 404) {
document.getElementById('main').innerHTML = 'Connect';
db.push('/domain', domain);
ipcRenderer.send('new-domain', domain);
} else {
document.getElementById('main').innerHTML = 'Connect';
document.getElementById('server-status').innerHTML = 'Not a vaild Zulip Server.';
}
});
};

View File

@@ -1,27 +1,49 @@
'use strict'; 'use strict';
const path = require('path'); const path = require('path');
const fs = require('fs'); const fs = require('fs');
const os = require('os');
const electron = require('electron'); const electron = require('electron');
const {app} = require('electron'); const {app} = require('electron');
const electronLocalshortcut = require('electron-localshortcut');
const ipc = require('electron').ipcMain; const ipc = require('electron').ipcMain;
const Configstore = require('configstore'); const {dialog} = require('electron');
const https = require('https');
const http = require('http');
const electronLocalshortcut = require('electron-localshortcut');
const Configstore = require('electron-config');
const JsonDB = require('node-json-db'); const JsonDB = require('node-json-db');
const isDev = require('electron-is-dev'); const isDev = require('electron-is-dev');
const tray = require('./tray');
const appMenu = require('./menu'); const appMenu = require('./menu');
const {linkIsInternal, skipImages} = require('./link-helper'); const {linkIsInternal, skipImages} = require('./link-helper');
const { appUpdater } = require('./autoupdater') const {appUpdater} = require('./autoupdater');
const db = new JsonDB(app.getPath('userData') + '/domain.json', true, true); const db = new JsonDB(app.getPath('userData') + '/domain.json', true, true);
const data = db.getData('/'); const data = db.getData('/');
// adds debug features like hotkeys for triggering dev tools and reload // Adds debug features like hotkeys for triggering dev tools and reload
require('electron-debug')(); require('electron-debug')();
const conf = new Configstore('Zulip-Desktop'); const conf = new Configstore();
// prevent window being garbage collected function userOS() {
if (os.platform() === 'darwin') {
return 'Mac';
}
if (os.platform() === 'linux') {
return 'Linux';
}
if (os.platform() === 'win32' || os.platform() === 'win64') {
if (parseFloat(os.release()) < 6.2) {
return 'Windows 7';
} else {
return 'Windows 10';
}
}
}
// Setting userAgent so that server-side code can identify the desktop app
const isUserAgent = 'ZulipElectron/' + app.getVersion() + ' ' + userOS();
// Prevent window being garbage collected
let mainWindow; let mainWindow;
let targetLink; let targetLink;
@@ -31,11 +53,77 @@ const staticURL = 'file://' + path.join(__dirname, '../renderer', 'index.html');
const targetURL = function () { const targetURL = function () {
if (data.domain === undefined) { if (data.domain === undefined) {
return staticURL; return staticURL;
} else {
return data.domain;
} }
return data.domain;
}; };
function serverError(targetURL) {
if (targetURL.indexOf('localhost:') < 0 && data.domain) {
const req = https.request(targetURL + '/static/audio/zulip.ogg', res => {
console.log('Server StatusCode:', res.statusCode);
console.log('You are connected to:', res.req._headers.host);
if (res.statusCode >= 500 && res.statusCode <= 599) {
return dialog.showErrorBox('SERVER IS DOWN!', 'We are getting a ' + res.statusCode + ' error status from the server ' + res.req._headers.host + '. Please try again after some time or you may switch server.');
}
});
req.on('error', e => {
if (e.toString().indexOf('Error: self signed certificate') >= 0) {
const url = targetURL.replace(/^https?:\/\//, '');
console.log('Server StatusCode:', 200);
console.log('You are connected to:', url);
} else {
console.error(e);
}
});
req.end();
} else if (data.domain) {
const req = http.request(targetURL + '/static/audio/zulip.ogg', res => {
console.log('Server StatusCode:', res.statusCode);
console.log('You are connected to:', res.req._headers.host);
});
req.on('error', e => {
console.error(e);
});
req.end();
}
}
function checkConnectivity() {
return dialog.showMessageBox({
title: 'Internet connection problem',
message: 'No internet available! Try again?',
type: 'warning',
buttons: ['Try again', 'Close'],
defaultId: 0
}, index => {
if (index === 0) {
mainWindow.webContents.reload();
mainWindow.webContents.send('destroytray');
}
if (index === 1) {
app.quit();
}
});
}
const connectivityERR = [
'ERR_INTERNET_DISCONNECTED',
'ERR_PROXY_CONNECTION_FAILED',
'ERR_CONNECTION_RESET',
'ERR_NOT_CONNECTED',
'ERR_NAME_NOT_RESOLVED'
];
function checkConnection() {
// eslint-disable-next-line no-unused-vars
mainWindow.webContents.on('did-fail-load', (event, errorCode, errorDescription, validatedURL) => {
const hasConnectivityErr = (connectivityERR.indexOf(errorDescription) >= 0);
if (hasConnectivityErr) {
console.error('error', errorDescription);
checkConnectivity();
}
});
}
const isAlreadyRunning = app.makeSingleInstance(() => { const isAlreadyRunning = app.makeSingleInstance(() => {
if (mainWindow) { if (mainWindow) {
if (mainWindow.isMinimized()) { if (mainWindow.isMinimized()) {
@@ -57,6 +145,10 @@ function checkWindowURL() {
return targetLink; return targetLink;
} }
function isWindowsOrmacOS() {
return process.platform === 'darwin' || process.platform === 'win32';
}
const APP_ICON = path.join(__dirname, '../resources', 'Icon'); const APP_ICON = path.join(__dirname, '../resources', 'Icon');
const iconPath = () => { const iconPath = () => {
@@ -64,8 +156,8 @@ const iconPath = () => {
}; };
function onClosed() { function onClosed() {
// dereference the window // Dereference the window
// for multiple windows store them in an array // For multiple windows, store them in an array
mainWindow = null; mainWindow = null;
} }
@@ -80,6 +172,7 @@ function updateDockBadge(title) {
if (process.platform === 'darwin') { if (process.platform === 'darwin') {
app.setBadgeCount(messageCount); app.setBadgeCount(messageCount);
} }
mainWindow.webContents.send('tray', messageCount);
} }
function createMainWindow() { function createMainWindow() {
@@ -92,14 +185,24 @@ function createMainWindow() {
minWidth: 600, minWidth: 600,
minHeight: 400, minHeight: 400,
webPreferences: { webPreferences: {
preload: path.join(__dirname, 'preload.js'), preload: path.join(__dirname, '../renderer/js/preload.js'),
plugins: true, plugins: true,
allowDisplayingInsecureContent: true, allowDisplayingInsecureContent: true,
nodeIntegration: false nodeIntegration: false
} },
show: false
});
win.once('ready-to-show', () => {
win.show();
});
serverError(targetURL());
win.loadURL(targetURL(), {
userAgent: isUserAgent + ' ' + win.webContents.getUserAgent()
}); });
win.loadURL(targetURL());
win.on('closed', onClosed); win.on('closed', onClosed);
win.setTitle('Zulip'); win.setTitle('Zulip');
@@ -129,7 +232,7 @@ function createMainWindow() {
}); });
}); });
// on osx it's 'moved' // On osx it's 'moved'
win.on('move', function () { win.on('move', function () {
const pos = this.getPosition(); const pos = this.getPosition();
conf.set({ conf.set({
@@ -138,19 +241,55 @@ function createMainWindow() {
}); });
}); });
// stop page to update it's title // Stop page to update it's title
win.on('page-title-updated', (e, title) => { win.on('page-title-updated', (e, title) => {
e.preventDefault(); e.preventDefault();
updateDockBadge(title); updateDockBadge(title);
}); });
// To destroy tray icon when navigate to a new URL
win.webContents.on('will-navigate', e => {
if (e) {
win.webContents.send('destroytray');
}
});
return win; return win;
} }
// TODO - fix certificate errors // TODO - fix certificate errors
app.commandLine.appendSwitch('ignore-certificate-errors', 'true');
// app.commandLine.appendSwitch('ignore-certificate-errors', 'true');
// For self-signed certificate
ipc.on('certificate-err', (e, domain) => {
const detail = `URL: ${domain} \n Error: Self-Signed Certificate`;
dialog.showMessageBox(mainWindow, {
title: 'Certificate error',
message: `Do you trust certificate from ${domain}?`,
// eslint-disable-next-line object-shorthand
detail: detail,
type: 'warning',
buttons: ['Yes', 'No'],
cancelId: 1
// eslint-disable-next-line object-shorthand
}, response => {
if (response === 0) {
// eslint-disable-next-line object-shorthand
db.push('/domain', domain);
mainWindow.loadURL(domain);
}
});
});
// eslint-disable-next-line max-params
app.on('certificate-error', (event, webContents, url, error, certificate, callback) => {
event.preventDefault();
callback(true);
});
app.on('window-all-closed', () => { app.on('window-all-closed', () => {
// Unregister all the shortcuts so that they don't interfare with other apps
electronLocalshortcut.unregisterAll(mainWindow);
if (process.platform !== 'darwin') { if (process.platform !== 'darwin') {
app.quit(); app.quit();
} }
@@ -165,13 +304,14 @@ app.on('activate', () => {
app.on('ready', () => { app.on('ready', () => {
electron.Menu.setApplicationMenu(appMenu); electron.Menu.setApplicationMenu(appMenu);
mainWindow = createMainWindow(); mainWindow = createMainWindow();
tray.create(mainWindow); // Not using for now // tray.create();
const page = mainWindow.webContents; const page = mainWindow.webContents;
// TODO - use global shortcut instead // TODO - use global shortcut instead
electronLocalshortcut.register(mainWindow, 'CommandOrControl+R', () => { electronLocalshortcut.register(mainWindow, 'CommandOrControl+R', () => {
mainWindow.reload(); mainWindow.reload();
mainWindow.webContents.send('destroytray');
}); });
electronLocalshortcut.register(mainWindow, 'CommandOrControl+[', () => { electronLocalshortcut.register(mainWindow, 'CommandOrControl+[', () => {
@@ -187,7 +327,7 @@ app.on('ready', () => {
}); });
page.on('dom-ready', () => { page.on('dom-ready', () => {
page.insertCSS(fs.readFileSync(path.join(__dirname, 'preload.css'), 'utf8')); page.insertCSS(fs.readFileSync(path.join(__dirname, '../renderer/css/preload.css'), 'utf8'));
mainWindow.show(); mainWindow.show();
}); });
@@ -200,26 +340,35 @@ app.on('ready', () => {
electron.shell.openExternal(url); electron.shell.openExternal(url);
}); });
page.once('did-frame-finish-load', () => {
page.once("did-frame-finish-load", () => { const checkOS = isWindowsOrmacOS();
if (process.platform === 'darwin' && !isDev) { if (checkOS && !isDev) {
// Initate auto-updates // Initate auto-updates on MacOS and Windows
appUpdater() appUpdater();
} }
}) });
checkConnection();
});
app.on('will-quit', () => {
// Unregister all the shortcuts so that they don't interfare with other apps
electronLocalshortcut.unregisterAll(mainWindow);
}); });
ipc.on('new-domain', (e, domain) => { ipc.on('new-domain', (e, domain) => {
// mainWindow.loadURL(domain); // MainWindow.loadURL(domain);
if (!mainWindow) { if (!mainWindow) {
mainWindow = createMainWindow(); mainWindow = createMainWindow();
mainWindow.loadURL(domain); mainWindow.loadURL(domain);
mainWindow.webContents.send('destroytray');
} else if (mainWindow.isMinimized()) { } else if (mainWindow.isMinimized()) {
mainWindow.webContents.send('destroytray');
mainWindow.loadURL(domain); mainWindow.loadURL(domain);
mainWindow.show(); mainWindow.show();
} else { } else {
mainWindow.webContents.send('destroytray');
mainWindow.loadURL(domain); mainWindow.loadURL(domain);
serverError(domain);
} }
targetLink = domain; targetLink = domain;
}); });

View File

@@ -10,6 +10,7 @@ function linkIsInternal(currentUrl, newUrl) {
// We'll be needing this to open images in default browser // We'll be needing this to open images in default browser
const skipImages = '.jpg|.gif|.png|.jpeg|.JPG|.PNG'; const skipImages = '.jpg|.gif|.png|.jpeg|.JPG|.PNG';
exports = module.exports = { module.exports = {
linkIsInternal, skipImages linkIsInternal,
skipImages
}; };

View File

@@ -2,10 +2,13 @@
const os = require('os'); const os = require('os');
const electron = require('electron'); const electron = require('electron');
const {dialog} = require('electron');
const app = electron.app; const app = electron.app;
const BrowserWindow = electron.BrowserWindow; const BrowserWindow = electron.BrowserWindow;
const shell = electron.shell; const shell = electron.shell;
const appName = app.getName(); const appName = app.getName();
// Const tray = require('./tray');
const {addDomain, about} = require('./windowmanager'); const {addDomain, about} = require('./windowmanager');
@@ -19,13 +22,21 @@ function sendAction(action) {
win.webContents.send(action); win.webContents.send(action);
} }
function clearCache() {
const win = BrowserWindow.getAllWindows()[0];
const ses = win.webContents.session;
ses.clearCache(() => {
dialog.showMessageBox({type: 'info', buttons: [], message: 'Cache cleared!'});
});
}
const viewSubmenu = [ const viewSubmenu = [
{ {
label: 'Reload', label: 'Reload',
accelerator: 'CmdOrCtrl+R',
click(item, focusedWindow) { click(item, focusedWindow) {
if (focusedWindow) { if (focusedWindow) {
focusedWindow.reload(); focusedWindow.reload();
focusedWindow.webContents.send('destroytray');
} }
} }
}, },
@@ -65,6 +76,14 @@ const viewSubmenu = [
{ {
type: 'separator' type: 'separator'
}, },
{
label: 'Toggle Tray Icon',
click(item, focusedWindow) {
if (focusedWindow) {
focusedWindow.webContents.send('toggletray');
}
}
},
{ {
label: 'Toggle Developer Tools', label: 'Toggle Developer Tools',
accelerator: process.platform === 'darwin' ? 'Alt+Command+I' : 'Ctrl+Shift+I', accelerator: process.platform === 'darwin' ? 'Alt+Command+I' : 'Ctrl+Shift+I',
@@ -135,8 +154,15 @@ const darwinTpl = [
{ {
type: 'separator' type: 'separator'
}, },
{
label: 'Clear Cache',
click() {
clearCache();
}
},
{ {
label: 'Log Out', label: 'Log Out',
accelerator: 'Cmd+L',
click(item, focusedWindow) { click(item, focusedWindow) {
if (focusedWindow) { if (focusedWindow) {
sendAction('log-out'); sendAction('log-out');
@@ -264,8 +290,15 @@ const otherTpl = [
{ {
type: 'separator' type: 'separator'
}, },
{
label: 'Clear Cache',
click() {
clearCache();
}
},
{ {
label: 'Log Out', label: 'Log Out',
accelerator: 'Ctrl+L',
click(item, focusedWindow) { click(item, focusedWindow) {
if (focusedWindow) { if (focusedWindow) {
sendAction('log-out'); sendAction('log-out');
@@ -313,7 +346,6 @@ const otherTpl = [
{ {
role: 'selectall' role: 'selectall'
} }
] ]
}, },
{ {

View File

@@ -1,52 +0,0 @@
'use strict';
const ipcRenderer = require('electron').ipcRenderer;
// Handle zooming functionality
const zoomIn = () => {
webFrame.setZoomFactor(webFrame.getZoomFactor() + 0.1);
};
const zoomOut = () => {
webFrame.setZoomFactor(webFrame.getZoomFactor() - 0.1);
};
const zoomActualSize = () => {
webFrame.setZoomFactor(1);
};
// Get zooming actions from main process
ipcRenderer.on('zoomIn', () => {
zoomIn();
});
ipcRenderer.on('zoomOut', () => {
zoomOut();
});
ipcRenderer.on('zoomActualSize', () => {
zoomActualSize();
});
ipcRenderer.on('log-out', () => {
// create the menu for the below
document.querySelector('.dropdown-toggle').click();
const nodes = document.querySelectorAll('.dropdown-menu li:last-child a');
nodes[nodes.length - 1].click();
});
ipcRenderer.on('shortcut', () => {
// create the menu for the below
document.querySelector('.dropdown-toggle').click();
const nodes = document.querySelectorAll('.dropdown-menu li:nth-child(4) a');
nodes[nodes.length - 1].click();
});
require('./domain');
// To prevent failing this script on linux we need to load it after the document loaded
document.addEventListener('DOMContentLoaded', function () {
require('./spellchecker');
});

View File

@@ -1,14 +0,0 @@
const {SpellCheckHandler, ContextMenuListener, ContextMenuBuilder} = require('electron-spellchecker');
// Implement spellcheck using electron api
window.spellCheckHandler = new SpellCheckHandler();
window.spellCheckHandler.attachToInput();
// Start off as US English
window.spellCheckHandler.switchLanguage('en-US');
let contextMenuBuilder = new ContextMenuBuilder(window.spellCheckHandler);
let contextMenuListener = new ContextMenuListener((info) => {
contextMenuBuilder.showPopupMenu(info);
});

View File

@@ -1,61 +0,0 @@
'use strict';
const path = require('path');
const electron = require('electron');
const app = require('electron').app;
const {addDomain, about} = require('./windowmanager');
let tray = null;
const APP_ICON = path.join(__dirname, '../resources/tray', 'tray');
const iconPath = () => {
if (process.platform === 'linux') {
return APP_ICON + 'linux.png'
}
return APP_ICON + (process.platform === 'win32' ? 'win.ico' : 'osx.png');
};
exports.create = () => {
const contextMenu = electron.Menu.buildFromTemplate([
{
label: 'About',
click() {
about();
}
},
{
type: 'separator'
},
{
label: 'Change Zulip server',
click() {
addDomain();
}
},
{
type: 'separator'
},
{
label: 'Reload',
click(item, focusedWindow) {
if (focusedWindow) {
focusedWindow.reload();
}
}
},
{
type: 'separator'
},
{
label: 'Quit',
click() {
app.quit();
}
}
]);
tray = new electron.Tray(iconPath());
tray.setToolTip(`${app.getName()}`);
tray.setContextMenu(contextMenu);
};

View File

@@ -1,12 +1,18 @@
'use strict'; 'use strict';
const path = require('path'); const path = require('path');
const electron = require('electron'); const electron = require('electron');
const ipc = require('electron').ipcMain;
const APP_ICON = path.join(__dirname, '../resources', 'Icon');
const iconPath = () => {
return APP_ICON + (process.platform === 'win32' ? '.ico' : '.png');
};
let domainWindow; let domainWindow;
let aboutWindow; let aboutWindow;
function onClosed() { function onClosed() {
// dereference the window // Dereference the window
domainWindow = null; domainWindow = null;
aboutWindow = null; aboutWindow = null;
} }
@@ -14,10 +20,14 @@ function onClosed() {
// Change Zulip server Window // Change Zulip server Window
function createdomainWindow() { function createdomainWindow() {
const domainwin = new electron.BrowserWindow({ const domainwin = new electron.BrowserWindow({
title: 'Switch Server',
frame: false, frame: false,
height: 300, height: 300,
resizable: false, resizable: false,
width: 400 width: 400,
show: false,
icon: iconPath()
}); });
const domainURL = 'file://' + path.join(__dirname, '../renderer', 'pref.html'); const domainURL = 'file://' + path.join(__dirname, '../renderer', 'pref.html');
domainwin.loadURL(domainURL); domainwin.loadURL(domainURL);
@@ -25,13 +35,20 @@ function createdomainWindow() {
return domainwin; return domainwin;
} }
// Call this window onClick addDomain in tray // Call this window onClick addDomain in tray
function addDomain() { function addDomain() {
domainWindow = createdomainWindow(); domainWindow = createdomainWindow();
domainWindow.once('ready-to-show', () => {
domainWindow.show(); domainWindow.show();
});
setTimeout(() => {
if (domainWindow !== null) {
if (!domainWindow.isDestroyed()) {
domainWindow.destroy();
}
}
}, 15000);
} }
// About window // About window
function createAboutWindow() { function createAboutWindow() {
const aboutwin = new electron.BrowserWindow({ const aboutwin = new electron.BrowserWindow({
@@ -48,7 +65,7 @@ function createAboutWindow() {
aboutwin.loadURL(aboutURL); aboutwin.loadURL(aboutURL);
aboutwin.on('closed', onClosed); aboutwin.on('closed', onClosed);
// stop page to update it's title // Stop page to update it's title
aboutwin.on('page-title-updated', e => { aboutwin.on('page-title-updated', e => {
e.preventDefault(); e.preventDefault();
}); });
@@ -61,9 +78,23 @@ function createAboutWindow() {
// Call this onClick About in tray // Call this onClick About in tray
function about() { function about() {
aboutWindow = createAboutWindow(); aboutWindow = createAboutWindow();
aboutWindow.once('ready-to-show', () => {
aboutWindow.show(); aboutWindow.show();
});
} }
exports = module.exports = { ipc.on('trayabout', event => {
addDomain, about if (event) {
about();
}
});
ipc.on('traychangeserver', event => {
if (event) {
addDomain();
}
});
module.exports = {
addDomain,
about
}; };

View File

@@ -1,11 +1,11 @@
{ {
"name": "zulip", "name": "zulip",
"productName": "Zulip", "productName": "Zulip",
"version": "0.5.2", "version": "0.5.10",
"description": "Zulip Desktop App", "description": "Zulip Desktop App",
"license": "Apache-2.0", "license": "Apache-2.0",
"email":"<svnitakash@gmail.com>", "email": "<svnitakash@gmail.com>",
"copyright": "©2016 Kandra Labs, Inc.", "copyright": "©2017 Kandra Labs, Inc.",
"author": { "author": {
"name": "Akash Nimare", "name": "Akash Nimare",
"email": "svnitakash@gmail.com" "email": "svnitakash@gmail.com"
@@ -27,16 +27,16 @@
"InstantMessaging" "InstantMessaging"
], ],
"dependencies": { "dependencies": {
"electron-is-dev": "*", "electron-config":"0.2.1",
"configstore": "^2.0.0", "electron-debug": "1.1.0",
"dialogs": "1.1.14", "electron-is-dev": "0.1.2",
"electron-context-menu": "0.4.0", "electron-localshortcut": "1.0.0",
"electron-debug": "^1.0.0", "electron-log": "1.3.0",
"electron-dl": "^0.2.0", "electron-spellchecker": "1.0.5",
"electron-localshortcut": "^0.6.1", "electron-updater": "1.11.2",
"node-json-db": "^0.7.2", "https": "^1.0.0",
"request": "^2.74.0", "node-json-db": "0.7.3",
"electron-spellchecker": "^0.5.12", "request": "2.79.0",
"wurl": "^2.1.0" "wurl": "2.1.0"
} }
} }

View File

@@ -6,17 +6,19 @@
</head> </head>
<body> <body>
<div class="about"> <div class="about">
<center><img src="../resources/zulip.png"></center> <img class="logo" src="../resources/zulip.png" />
<center><p class="detail" id="version"> Version : ?.?.? </p> <p class="detail" id="version">version ?.?.?</p>
<center><p class="detail"> License : Apache </p> <div class="maintenance-info">
<center><p class="detail"> Maintainer : Zulip </p> <p class="detail maintainer">Maintained by Zulip</p>
<p class="left"><a class="bug" onclick="linkInBrowser()" href="#">Found bug?</a></p> <p class="detail license">Available under the Apache License</p>
<a class="bug" onclick="linkInBrowser()" href="#">Found bug?</a>
</div>
</div> </div>
<script> <script>
const app = require('electron').remote.app; const app = require('electron').remote.app;
const version_tag = document.getElementById('version'); const version_tag = document.getElementById('version');
version_tag.innerHTML = ' Version : ' + app.getVersion() + ' '; version_tag.innerHTML = 'version ' + app.getVersion();
function linkInBrowser(event) { function linkInBrowser(event) {

View File

@@ -1,15 +1,22 @@
body { body {
background: #6BB6C7; background: #fafafa;
font-family: menu, "Helvetica Neue", sans-serif;
-webkit-font-smoothing: antialiased;
}
.logo {
display: block;
margin: 0 auto;
}
#version {
color: #aaa;
font-size: 0.9em;
} }
.about { .about {
margin-top: 50px; margin-top: 50px;
} text-align: center;
.left {
position: absolute;
top:89%;
left:76%;
} }
.about p { .about p {
@@ -18,10 +25,49 @@ body {
} }
.about img { .about img {
width:160px; width: 150px;
} }
.detail { .detail {
text-align: left; text-align: center;
margin-left: 35%; }
.detail.maintainer {
font-size: 1.2em;
font-weight: 500;
}
.detail.license {
font-size: 0.8em;
}
.maintenance-info {
position: absolute;
width: 100%;
bottom: 20px;
left: 0px;
color: #444;
}
.maintenance-info p {
margin: 0;
font-size: 1em;
width: 100%;
}
.maintenance-info .bug {
display: inline-block;
padding: 8px 15px;
margin-top: 30px;
text-decoration: none;
background-color: #52c2af;
color: #fff;
border-radius: 4px;
transition: background-color 0.2s ease;
}
.maintenance-info .bug:hover {
background-color: #32a692;
} }

View File

@@ -1,375 +1,143 @@
@charset "UTF-8"; * {
header, font-family: -apple-system, BlinkMacSystemFont, "Segoe UI",
section { Helvetica, Arial, sans-serif, "Apple Color Emoji",
display: block "Segoe UI Emoji", "Segoe UI Symbol";
-webkit-font-smoothing: antialiased;
color: #444;
vertical-align: top;
} }
html {
font-size: 100%;
overflow-y: scroll;
-webkit-text-size-adjust: 100%;
}
html,
button,
input {
font-family: "Helvetica Neue", Arial, sans-serif
}
html,
body { body {
height: 100%;
margin: 0
}
img {
border: 0;
-ms-interpolation-mode: bicubic
}
img {
vertical-align: middle
}
form {
margin: 0
}
fieldset {
border: 0;
margin: 0; margin: 0;
padding: 0 background-image: url(../img/topography.png);
}
button,
input {
font-size: 100%;
margin: 0;
vertical-align: baseline;
box-sizing: content-box;
-webkit-box-sizing: content-box
}
button,
input {
line-height: normal
} }
input,
button { button {
cursor: pointer; font-size: 1em;
-webkit-appearance: button;
}
button::-moz-focus-inner,
input::-moz-focus-inner {
border: 0;
padding: 0
}
hr {
display: none
}
img {
max-width: 100%
}
h1 {
color: #111;
line-height: 1em;
font-weight: 400;
font-family: "Helvetica Neue", Arial, sans-serif;
text-rendering: optimizelegibility;
-webkit-text-stroke: none
}
h1 {
margin: 0 0 35px
} }
body.container-layout header #logo {
position: relative;
display: inline-block;
vertical-align: top
}
body.container-layout header #logo {
width: 50px;
height: 50px;
background-position: -790px 0
}
button[type=submit] {
text-decoration: none;
display: inline-block;
vertical-align: top;
-webkit-box-sizing: border-box;
box-sizing: border-box;
-webkit-border-radius: 4px;
border-radius: 4px;
position: relative;
font-family: "Helvetica Neue", Arial, sans-serif;
font-size-adjust: auto;
vertical-align: bottom;
background-color: #e6eaef;
border: 2px solid #e6eaef;
color: #96a0ac;
font-size: 20px;
line-height: 26px;
padding: 6px 17px
}
.desktop button[type=submit] {
-webkit-transition: all .2s ease-in-out;
transition: all .2s ease-in-out
}
.desktop button[type=submit]:hover {
background-color: #eff2f5;
border: 2px solid #eff2f5;
color: #96a0ac
}
button[type=submit]:focus {
outline: 0
}
button[type=submit].btn-primary {
background-color: #20b36c;
border: 2px solid #20b36c;
color: #fff
}
.desktop button[type=submit].btn-primary:hover {
background-color: #39ca83;
border: 2px solid #39ca83;
color: #fff
}
button[type=submit].btn-primary:focus {
outline: 0
}
button[type=submit].btn-large {
font-family: "Helvetica Neue", Arial, sans-serif;
font-size: 20px;
line-height: 26px;
padding: 12px 30px
}
input[type=text] {
font-family: "Helvetica Neue", Arial, sans-serif;
font-weight: 200;
display: inline-block;
vertical-align: top;
-webkit-border-radius: 4px;
border-radius: 4px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
background-color: #fff;
border: 1px solid #cad0d7;
color: #000;
font-size: 18px;
line-height: 26px;
height: 42px;
padding: 10px 10px
}
.desktop input[type=text]:hover {
background-color: #fff;
border-color: #bbc3cc;
color: #111
}
input[type=text]:focus {
background-color: #fff;
border-color: #20b36c!important;
color: #000;
outline: 0
}
input[type=text]::-webkit-input-placeholder {
color: #8e959e
}
input[type=text]::-moz-placeholder {
color: #8e959e
}
input[type=text]:-ms-input-placeholder {
color: #8e959e
}
.form-large input[type=text] {
font-size: 18px;
line-height: 26px;
height: 54px;
padding: 12px 15px
}
.control-group {
margin-top: 40px
}
h1 {
white-space: normal;
word-break: break-all;
word-break: break-word;
-webkit-hyphens: auto;
-moz-hyphens: auto;
hyphens: auto
}
.section-main {
position: relative
}
body {
color: #111;
font-size: 18px;
line-height: 24px;
font-family: "Helvetica Neue", Arial, sans-serif;
background: #edf1f3;
-webkit-box-sizing: border-box;
box-sizing: border-box
}
.desktop body {
padding-top: 116px
}
body.container-layout {
padding: 0!important;
background-color: #E6EAEF
}
header { header {
z-index: 800; text-align: center;
border-bottom: 1px solid #dae0e7; margin: 0px 0px 30px 0px;
background: rgba(255, 255, 255, .97);
-webkit-box-sizing: border-box;
box-sizing: border-box;
position: relative;
top: 0;
left: 0;
width: 100%
}
header .container {
position: relative
}
.desktop header {
position: fixed
}
header .container {
position: relative;
height: 75px
}
.container-layout header {
position: relative;
border: 0;
background: 0 0;
padding: 30px 0
}
.container-layout header .container {
height: auto
}
header #logo {
display: block;
text-indent: -9999px
} }
header #logo { header img {
position: absolute!important; width: 50px;
top: 50%;
left: 10px;
-webkit-transform: translate(0, -50%);
transform: translate(0, -50%)
} }
body.container-layout header #logo {
position: relative!important; header h1 {
top: 0; display: inline-block;
left: 0; margin: 10px 0px 10px 10px;
-webkit-transform: translate(0, 0);
transform: translate(0, 0); font-weight: 500;
margin: 0 auto;
display: block
} }
.content {
padding-bottom: 40px;
overflow: hidden section.server {
display: inline-block;
padding: 50px;
margin-top: calc(50vh - 135px);
text-align: left;
box-shadow: 0px 0px 100px rgba(0,0,0,0.15);
background-color: #fff;
animation-name: pulse;
animation-duration: 2s;
animation-iteration-count: infinite;
} }
.container-layout .content {
max-width: 660px; section.shake {
margin: 0 auto animation-name: shake;
animation-duration: 0.5s;
animation-iteration-count: 1;
} }
.content .server {
position: relative; form label {
margin: 0 10px display: block;
font-weight: 600;
margin-bottom: 5px;
} }
.content .server .container {
background: #fff; form input[type=text] {
-webkit-box-sizing: border-box; width: 300px;
box-sizing: border-box; border: 2px solid #ccc;
padding: 50px 0 0; padding: 10px 10px;
-webkit-border-radius: 4px;
border-radius: 4px; outline: none;
position: relative;
z-index: 10; transition: all 0.2s ease;
max-width: 580px
} }
.content .server h1 {
form input[type=text]:hover,
form input[type=text]:focus {
border-color: #aaa;
}
form button {
padding: 10px 10px;
background-color: #52c2af;
color: #fff;
border: 2px solid #52c2af;
outline: none;
cursor: pointer;
transition: all 0.2s ease;
}
form button:hover {
background-color: #30b09a;
border-color: #30b09a;
}
form button:active {
background-color: #14957f;
border-color: #14957f;
}
form #error {
margin: 5px 0px 0px;
font-size: 0.8em;
font-weight: 600;
color: rgb(201, 107, 107);
opacity: 0;
transform: translateY(-10px);
height: 15px;
transition: all 0.2s ease;
}
form #error.show {
opacity: 1;
transform: translateY(0px);
}
/* -- generic components -- */
.center {
text-align: center; text-align: center;
padding: 0 10%
} }
.content .server h1 {
font-size: 2.4em; @keyframes pulse {
line-height: 1.2em; 0% { box-shadow: 0px 0px 100px rgba(0,0,0,0.15); }
margin-bottom: 10px 50% { box-shadow: 0px 0px 100px rgba(0,0,0,0.30); }
100% { box-shadow: 0px 0px 100px rgba(0,0,0,0.15); }
} }
.content .server fieldset {
padding: 25px 10% 80px 39px; @keyframes shake {
position: relative 10%, 90% { transform: translate3d(-1px, 0, 0); }
} 20%, 80% { transform: translate3d(2px, 0, 0); }
.content .server fieldset .control-group .control-field input { 30%, 50%, 70% { transform: translate3d(-4px, 0, 0); }
width: 100% 40%, 60% { transform: translate3d(4px, 0, 0); }
}
.content .server button {
width: 100%
}
@media screen and (min-width: 749px) {
input[type=text] {
width: 60%
}
}
@media screen and (min-width: 1071px) {
h1 {
font-size: 3.2em;
line-height: 1.3em
}
}
.container {
width: 1070px;
margin-left: auto;
margin-right: auto;
padding-left: 10px;
padding-right: 10px;
}
.container:before,
.container:after {
content: "";
display: table
}
.container:after {
clear: both
}
.responsive .container {
max-width: 1070px;
width: auto;
margin-left: auto;
margin-right: auto;
padding-left: 10px;
padding-right: 10px;
}
.responsive .container:before,
.responsive .container:after {
content: "";
display: table
}
.responsive .container:after {
clear: both
}
@media screen and (max-width: 480px) {
.responsive h1 {
font-size: 1.7em;
line-height: 1.3em
}
}
@media screen and (min-width: 481px) and (max-width: 640px) {
.responsive h1 {
font-size: 1.9em;
line-height: 1.3em
}
}
@media screen and (min-width: 641px) and (max-width: 748px) {
.responsive h1 {
font-size: 2.2em;
line-height: 1.3em
}
}
@media screen and (max-width: 748px) {
.responsive input[type=text] {
width: 100%
}
}
@media screen and (min-width: 749px) and (max-width: 1070px) {
.responsive h1 {
font-size: 2.6em;
line-height: 1.3em
}
}
#server-status {
text-align: center;
color: #c71212;
} }

View File

@@ -72,12 +72,3 @@ button:focus {
left: 25%; left: 25%;
text-align: center; text-align: center;
} }
#pic {
width: 20px;
left: 36%;
margin-left: 4px;
top: 63%;
display: none;
position: absolute;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@@ -7,36 +7,24 @@
<title>Login - Zulip</title> <title>Login - Zulip</title>
<link rel="stylesheet" href="css/main.css" type="text/css" media="screen"> <link rel="stylesheet" href="css/main.css" type="text/css" media="screen">
</head> </head>
<body class="container-layout"> <body>
<div class="section-main"> <div class="center">
<header>
<div class="container">
<img src="../resources/zulip.png" id="logo"/>
</div>
</header>
<hr>
<section class="content">
<section class="server"> <section class="server">
<header>
<img src="../resources/zulip.png" id="logo"/>
<h1>Zulip Login</h1>
</header>
<div class="container"> <div class="container">
<h1>Login to Zulip Server</h1>
<form id="frm-signInForm" class="form-large" onsubmit="addDomain(); return false"> <form id="frm-signInForm" class="form-large" onsubmit="addDomain(); return false">
<fieldset> <label for="url">
<div class="control-group control-required"> Zulip Server URL
<div class="control-field"> </label>
<input type="text" id="url" autofocus="autofocus" spellcheck="false" placeholder="zulip.tabbott.net"> <input type="text" id="url" autofocus="autofocus" spellcheck="false" placeholder="Server URL">
</div> <button type="submit" id="main" class="btn-primary btn-large" value="Submit">Connect</button>
</div> <p id="error"></p>
<div class="control-group">
<div class="control-submit">
<button type="submit" id="main" class="btn-primary btn-large" value="Submit" onclick="addDomain();">Connect</button>
</div>
</div>
<p id="server-status"><p>
</fieldset>
</form> </form>
</div> </div>
</section> </section>
</section>
</div> </div>
</body> </body>
</html> </html>

80
app/renderer/js/domain.js Normal file
View File

@@ -0,0 +1,80 @@
const {app} = require('electron').remote;
const ipcRenderer = require('electron').ipcRenderer;
const JsonDB = require('node-json-db');
const request = require('request');
const db = new JsonDB(app.getPath('userData') + '/domain.json', true, true);
window.addDomain = function () {
const el = sel => {
return document.querySelector(sel);
};
const $el = {
error: el('#error'),
main: el('#main'),
section: el('section')
};
const event = sel => {
return {
on: (event, callback) => {
document.querySelector(sel).addEventListener(event, callback);
}
};
};
const displayError = msg => {
$el.error.innerText = msg;
$el.error.classList.add('show');
$el.section.classList.add('shake');
};
let newDomain = document.getElementById('url').value;
newDomain = newDomain.replace(/^https?:\/\//, '');
if (newDomain === '') {
displayError('Please input a valid URL.');
} else {
el('#main').innerHTML = 'Checking...';
if (newDomain.indexOf('localhost:') >= 0) {
const domain = 'http://' + newDomain;
const checkDomain = domain + '/static/audio/zulip.ogg';
request(checkDomain, (error, response) => {
if (!error && response.statusCode !== 404) {
document.getElementById('main').innerHTML = 'Connect';
db.push('/domain', domain);
ipcRenderer.send('new-domain', domain);
} else {
$el.main.innerHTML = 'Connect';
displayError('Not a valid Zulip local server');
}
});
// });
} else {
const domain = 'https://' + newDomain;
const checkDomain = domain + '/static/audio/zulip.ogg';
request(checkDomain, (error, response) => {
if (!error && response.statusCode !== 404) {
$el.main.innerHTML = 'Connect';
db.push('/domain', domain);
ipcRenderer.send('new-domain', domain);
} else if (error.toString().indexOf('Error: self signed certificate') >= 0) {
$el.main.innerHTML = 'Connect';
ipcRenderer.send('certificate-err', domain);
} else {
$el.main.innerHTML = 'Connect';
displayError('Not a valid Zulip server');
}
});
}
}
event('#url').on('input', () => {
el('#error').classList.remove('show');
});
event('section').on('animationend', function () {
this.classList.remove('shake');
});
};

View File

@@ -1,4 +1,5 @@
'use strict'; 'use strict';
// eslint-disable-next-line import/no-extraneous-dependencies
const {remote} = require('electron'); const {remote} = require('electron');
const prefWindow = remote.getCurrentWindow(); const prefWindow = remote.getCurrentWindow();
@@ -13,33 +14,56 @@ document.addEventListener('keydown', event => {
} }
}); });
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
function addDomain() { window.prefDomain = function () {
const request = require('request'); const request = require('request');
// eslint-disable-next-line import/no-extraneous-dependencies
const ipcRenderer = require('electron').ipcRenderer; const ipcRenderer = require('electron').ipcRenderer;
const JsonDB = require('node-json-db'); const JsonDB = require('node-json-db');
// eslint-disable-next-line import/no-extraneous-dependencies
const {app} = require('electron').remote; const {app} = require('electron').remote;
const db = new JsonDB(app.getPath('userData') + '/domain.json', true, true); const db = new JsonDB(app.getPath('userData') + '/domain.json', true, true);
document.getElementById('main').innerHTML = 'checking...';
document.getElementById('pic').style.display = 'block';
let newDomain = document.getElementById('url').value; let newDomain = document.getElementById('url').value;
newDomain = newDomain.replace(/^https?:\/\//, ''); newDomain = newDomain.replace(/^https?:\/\//, '');
newDomain = newDomain.replace(/^http?:\/\//, '');
const domain = 'https://' + newDomain; if (newDomain === '') {
document.getElementById('urladded').innerHTML = 'Please input a value';
} else {
document.getElementById('main').innerHTML = 'Checking...';
if (newDomain.indexOf('localhost:') >= 0) {
const domain = 'http://' + newDomain;
const checkDomain = domain + '/static/audio/zulip.ogg'; const checkDomain = domain + '/static/audio/zulip.ogg';
request(checkDomain, (error, response) => { request(checkDomain, (error, response) => {
if (!error && response.statusCode !== 404) { if (!error && response.statusCode !== 404) {
document.getElementById('pic').style.display = 'none';
document.getElementById('main').innerHTML = 'Switch'; document.getElementById('main').innerHTML = 'Switch';
document.getElementById('urladded').innerHTML = 'Switched to ' + newDomain; document.getElementById('urladded').innerHTML = 'Switched to ' + newDomain;
db.push('/domain', domain); db.push('/domain', domain);
ipcRenderer.send('new-domain', domain); ipcRenderer.send('new-domain', domain);
} else { } else {
document.getElementById('pic').style.display = 'none';
document.getElementById('main').innerHTML = 'Switch'; document.getElementById('main').innerHTML = 'Switch';
document.getElementById('urladded').innerHTML = 'Not a vaild Zulip Server.'; document.getElementById('urladded').innerHTML = 'Not a valid Zulip Local Server.';
} }
}); });
} } else {
const domain = 'https://' + newDomain;
const checkDomain = domain + '/static/audio/zulip.ogg';
request(checkDomain, (error, response) => {
if (!error && response.statusCode !== 404) {
document.getElementById('main').innerHTML = 'Switch';
document.getElementById('urladded').innerHTML = 'Switched to ' + newDomain;
db.push('/domain', domain);
ipcRenderer.send('new-domain', domain);
} else if (error.toString().indexOf('Error: self signed certificate') >= 0) {
document.getElementById('main').innerHTML = 'Switch';
ipcRenderer.send('certificate-err', domain);
document.getElementById('urladded').innerHTML = 'Switched to ' + newDomain;
} else {
document.getElementById('main').innerHTML = 'Switch';
document.getElementById('urladded').innerHTML = 'Not a valid Zulip Server.';
}
});
}
}
};

View File

@@ -0,0 +1,69 @@
'use strict';
const ipcRenderer = require('electron').ipcRenderer;
const {webFrame} = require('electron');
const {spellChecker} = require('./spellchecker');
const _setImmediate = setImmediate;
const _clearImmediate = clearImmediate;
process.once('loaded', () => {
global.setImmediate = _setImmediate;
global.clearImmediate = _clearImmediate;
});
// eslint-disable-next-line import/no-unassigned-import
require('./domain');
// eslint-disable-next-line import/no-unassigned-import
require('./tray.js');
// Calling Tray.js in renderer process everytime app window loads
// Handle zooming functionality
const zoomIn = () => {
webFrame.setZoomFactor(webFrame.getZoomFactor() + 0.1);
};
const zoomOut = () => {
webFrame.setZoomFactor(webFrame.getZoomFactor() - 0.1);
};
const zoomActualSize = () => {
webFrame.setZoomFactor(1);
};
// Get zooming actions from main process
ipcRenderer.on('zoomIn', () => {
zoomIn();
});
ipcRenderer.on('zoomOut', () => {
zoomOut();
});
ipcRenderer.on('zoomActualSize', () => {
zoomActualSize();
});
ipcRenderer.on('log-out', () => {
// Create the menu for the below
document.querySelector('.dropdown-toggle').click();
const nodes = document.querySelectorAll('.dropdown-menu li:last-child a');
nodes[nodes.length - 1].click();
});
ipcRenderer.on('shortcut', () => {
// Create the menu for the below
const node = document.querySelector('a[data-overlay-trigger=keyboard-shortcuts]');
// Additional check
if (node.text.trim().toLowerCase() === 'keyboard shortcuts') {
node.click();
} else {
// Atleast click the dropdown
document.querySelector('.dropdown-toggle').click();
}
});
// To prevent failing this script on linux we need to load it after the document loaded
document.addEventListener('DOMContentLoaded', () => {
// Init spellchecker
spellChecker();
});

View File

@@ -0,0 +1,27 @@
const {SpellCheckHandler, ContextMenuListener, ContextMenuBuilder} = require('electron-spellchecker');
function spellChecker() {
// Implement spellcheck using electron api
window.spellCheckHandler = new SpellCheckHandler();
window.spellCheckHandler.attachToInput();
// Start off as US English
window.spellCheckHandler.switchLanguage('en-US');
const contextMenuBuilder = new ContextMenuBuilder(window.spellCheckHandler);
const contextMenuListener = new ContextMenuListener(info => {
contextMenuBuilder.showPopupMenu(info);
});
// Clean up events after you navigate away from this page;
// otherwise, you may experience errors
window.addEventListener('beforeunload', () => {
// eslint-disable-next-line no-undef
spellCheckHandler.unsubscribe();
contextMenuListener.unsubscribe();
});
}
module.exports = {
spellChecker
};

188
app/renderer/js/tray.js Normal file
View File

@@ -0,0 +1,188 @@
'use strict';
const path = require('path');
const electron = require('electron');
const {ipcRenderer, remote} = electron;
const {Tray, Menu, nativeImage} = remote;
const APP_ICON = path.join(__dirname, '../../resources/tray', 'tray');
const iconPath = () => {
if (process.platform === 'linux') {
return APP_ICON + 'linux.png';
}
return APP_ICON + (process.platform === 'win32' ? 'win.ico' : 'osx.png');
};
let unread = 0;
const trayIconSize = () => {
switch (process.platform) {
case 'darwin':
return 20;
case 'win32':
return 100;
case 'linux':
return 100;
default: return 80;
}
};
// Default config for Icon we might make it OS specific if needed like the size
const config = {
pixelRatio: window.devicePixelRatio,
unreadCount: 0,
showUnreadCount: true,
unreadColor: '#000000',
readColor: '#000000',
unreadBackgroundColor: '#B9FEEA',
readBackgroundColor: '#B9FEEA',
size: trayIconSize(),
thick: process.platform === 'win32'
};
const renderCanvas = function (arg) {
config.unreadCount = arg;
return new Promise((resolve, reject) => {
const SIZE = config.size * config.pixelRatio;
const PADDING = SIZE * 0.05;
const CENTER = SIZE / 2;
const HAS_COUNT = config.showUnreadCount && config.unreadCount;
const color = config.unreadCount ? config.unreadColor : config.readColor;
const backgroundColor = config.unreadCount ? config.unreadBackgroundColor : config.readBackgroundColor;
const canvas = document.createElement('canvas');
canvas.width = SIZE;
canvas.height = SIZE;
const ctx = canvas.getContext('2d');
// Circle
// If (!config.thick || config.thick && HAS_COUNT) {
ctx.beginPath();
ctx.arc(CENTER, CENTER, (SIZE / 2) - PADDING, 0, 2 * Math.PI, false);
ctx.fillStyle = backgroundColor;
ctx.fill();
ctx.lineWidth = SIZE / (config.thick ? 10 : 20);
ctx.strokeStyle = backgroundColor;
ctx.stroke();
// Count or Icon
if (HAS_COUNT) {
ctx.fillStyle = color;
ctx.textAlign = 'center';
if (config.unreadCount > 99) {
ctx.font = `${config.thick ? 'bold ' : ''}${SIZE * 0.4}px Helvetica`;
ctx.fillText('99+', CENTER, CENTER + (SIZE * 0.15));
} else if (config.unreadCount < 10) {
ctx.font = `${config.thick ? 'bold ' : ''}${SIZE * 0.5}px Helvetica`;
ctx.fillText(config.unreadCount, CENTER, CENTER + (SIZE * 0.20));
} else {
ctx.font = `${config.thick ? 'bold ' : ''}${SIZE * 0.5}px Helvetica`;
ctx.fillText(config.unreadCount, CENTER, CENTER + (SIZE * 0.15));
}
resolve(canvas);
} else {
reject(canvas);
}
});
};
/**
* Renders the tray icon as a native image
* @param arg: Unread count
* @return the native image
*/
const renderNativeImage = function (arg) {
return Promise.resolve()
.then(() => renderCanvas(arg))
.then(canvas => {
const pngData = nativeImage.createFromDataURL(canvas.toDataURL('image/png')).toPng();
return Promise.resolve(nativeImage.createFromBuffer(pngData, config.pixelRatio));
});
};
const createTray = function () {
window.tray = new Tray(iconPath());
const contextMenu = Menu.buildFromTemplate([{
label: 'About',
click() {
ipcRenderer.send('trayabout');
}
},
{
type: 'separator'
},
{
label: 'Change Zulip server',
click() {
ipcRenderer.send('traychangeserver');
}
},
{
type: 'separator'
},
{
label: 'Reload',
click() {
remote.getCurrentWindow().reload();
window.tray.destroy();
}
},
{
type: 'separator'
},
{
label: 'Quit',
click() {
remote.getCurrentWindow().close();
}
}
]);
window.tray.setContextMenu(contextMenu);
};
ipcRenderer.on('destroytray', event => {
window.tray.destroy();
if (window.tray.isDestroyed()) {
window.tray = null;
} else {
throw new Error('Tray icon not properly destroyed.');
}
return event;
});
ipcRenderer.on('tray', (event, arg) => {
if (arg === 0) {
unread = arg;
// Message Count // console.log("message count is zero.");
window.tray.setImage(iconPath());
window.tray.setToolTip('No unread messages');
} else {
unread = arg;
renderNativeImage(arg).then(image => {
window.tray.setImage(image);
window.tray.setToolTip(arg + ' unread messages');
});
}
});
ipcRenderer.on('toggletray', event => {
if (event) {
if (window.tray) {
window.tray.destroy();
if (window.tray.isDestroyed()) {
window.tray = null;
}
} else {
createTray();
renderNativeImage(unread).then(image => {
window.tray.setImage(image);
window.tray.setToolTip(unread + ' unread messages');
});
}
}
});
createTray();

View File

@@ -3,17 +3,14 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<link rel="stylesheet" href="css/pref.css"> <link rel="stylesheet" href="css/pref.css">
<script type="text/javascript">
</script>
</head> </head>
<body> <body>
<div class="close" id="close-button">Close</div> <div class="close" id="close-button">Close</div>
<div class="form"> <div class="form">
<form onsubmit="addDomain(); return false"> <form onsubmit="prefDomain(); return false">
<input id="url" type="text" placeholder="zulip.example.com"> <input id="url" type="text" placeholder="Server URL">
<button type="submit" id="main" value="Submit" onclick="addDomain();"> <button type="submit" id="main" value="Submit">
Switch</button> Switch</button>
<img id="pic" src="img/loader.gif" />
</form> </form>
<p id="urladded"><p> <p id="urladded"><p>
</div> </div>

View File

@@ -1,11 +1,12 @@
{ {
"name": "zulip", "name": "zulip",
"productName": "Zulip", "productName": "Zulip",
"version": "0.5.2", "version": "0.5.10",
"main": "./app/main",
"description": "Zulip Desktop App", "description": "Zulip Desktop App",
"license": "Apache-2.0", "license": "Apache-2.0",
"email":"<svnitakash@gmail.com>", "email": "<svnitakash@gmail.com>",
"copyright": "©2016 Kandra Labs, Inc.", "copyright": "©2017 Kandra Labs, Inc.",
"author": { "author": {
"name": "Akash Nimare", "name": "Akash Nimare",
"email": "svnitakash@gmail.com" "email": "svnitakash@gmail.com"
@@ -24,30 +25,33 @@
"dev": "gulp dev", "dev": "gulp dev",
"pack": "build --dir", "pack": "build --dir",
"dist": "build", "dist": "build",
"build:win": "build --win nsis-web --ia32 --x64",
"travis": "cd ./scripts && ./travis-build-test.sh" "travis": "cd ./scripts && ./travis-build-test.sh"
}, },
"build": { "build": {
"appId": "org.zulip.zulip-electron", "appId": "org.zulip.zulip-electron",
"asar": "true", "asar": true,
"files": [ "files": [
"**/*", "**/*",
"!node_modules/@paulcbetts/cld/deps/cld${/*}" "!node_modules/@paulcbetts/cld/deps/cld${/*}"
], ],
"copyright": "©2016 Kandra Labs, Inc.", "copyright": "©2017 Kandra Labs, Inc.",
"mac": { "mac": {
"category": "public.app-category.productivity" "category": "public.app-category.productivity"
}, },
"linux" : { "linux": {
"synopsis": "Zulip Desktop App",
"category": "", "category": "",
"packageCategory": "GNOME;GTK;Network;InstantMessaging", "packageCategory": "GNOME;GTK;Network;InstantMessaging",
"description": "Zulip Desktop Client for Linux", "description": "Zulip Desktop Client for Linux",
"target" : ["deb", "AppImage"], "target": [
"version" : "0.5.1", "deb",
"title" : "Zulip", "AppImage"
"license": "Apache-2.0", ],
"maintainer": "Akash Nimare <svnitakash@gmail.com>" "maintainer": "Akash Nimare <svnitakash@gmail.com>"
}, },
"deb": {
"synopsis": "Zulip Desktop App"
},
"dmg": { "dmg": {
"background": "build/appdmg.png", "background": "build/appdmg.png",
"icon": "build/icon.icns", "icon": "build/icon.icns",
@@ -69,6 +73,10 @@
"win": { "win": {
"target": "nsis", "target": "nsis",
"icon": "build/icon.ico" "icon": "build/icon.ico"
},
"nsis": {
"perMachine": true,
"oneClick": false
} }
}, },
"keywords": [ "keywords": [
@@ -80,15 +88,15 @@
"InstantMessaging" "InstantMessaging"
], ],
"devDependencies": { "devDependencies": {
"assert": "^1.4.1", "assert": "1.4.1",
"devtron": "^1.1.0", "devtron": "1.4.0",
"electron-builder": "*", "electron-builder": "16.6.0",
"electron": "1.4.7", "electron": "1.4.15",
"electron-connect": "^0.4.6", "electron-connect": "0.4.8",
"gulp": "^3.9.1", "gulp": "3.9.1",
"gulp-mocha": "^3.0.1", "gulp-mocha": "3.0.1",
"spectron": "^3.3.0", "spectron": "3.6.1",
"xo": "*" "xo": "0.18.1"
}, },
"xo": { "xo": {
"esnext": true, "esnext": true,
@@ -98,10 +106,13 @@
"rules": { "rules": {
"max-lines": [ "max-lines": [
"warn", "warn",
350 500
], ],
"no-warning-comments": 0, "no-warning-comments": 0,
"no-else-return": 0 "capitalized-comments": 0,
"no-else-return": 0,
"import/no-unresolved": 0,
"import/no-extraneous-dependencies": 0
} }
} }
], ],

View File

@@ -1,6 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
export {no_proxy,NO_PROXY}="127.0.0.1,localhost"
export DISPLAY=:99.0 export DISPLAY=:99.0
sh -e /etc/init.d/xvfb start sh -e /etc/init.d/xvfb start
sleep 3 sleep 3

View File

@@ -2,12 +2,12 @@ const assert = require('assert')
const Application = require('spectron').Application const Application = require('spectron').Application
describe('application launch', function () { describe('application launch', function () {
this.timeout(10000) this.timeout(15000)
beforeEach(function () { beforeEach(function () {
this.app = new Application({ this.app = new Application({
path: require('electron'), path: require('electron'),
args: [__dirname + '/../app/main/index.js'] args: [__dirname + '/../app/renderer/index.html']
}) })
return this.app.start() return this.app.start()
}) })

View File

@@ -74,11 +74,11 @@ gitCheckout()
} }
# }}} # }}}
# {{{ npmUpgradeStart() # {{{ npmInstallStart()
npmUpgradeStart() npmInstallStart()
{ {
npm upgrade npm install
npm start & npm start &
} }
@@ -105,5 +105,5 @@ cleanUp()
envSetup $* envSetup $*
gitCheckout gitCheckout
npmUpgradeStart npmInstallStart
cleanUp cleanUp