Compare commits

...

340 Commits

Author SHA1 Message Date
akashnimare
a16181be33 🎉 v1.1.0-beta 2017-06-23 17:39:15 +05:30
akashnimare
cd0a7741b1 styling save-server-action button 2017-06-23 17:37:28 +05:30
akashnimare
6da523a18b Remove checkbox and redesign save-server-action 2017-06-23 17:24:37 +05:30
akashnimare
86302308a9 Enable quit app using CTRL+Q on windows as well 2017-06-22 02:44:34 +05:30
akashnimare
b0294db133 Allow global return + use script as sourceType 2017-06-22 00:53:35 +05:30
akashnimare
252586cf71 fix module error #185 2017-06-22 00:52:29 +05:30
Akash Nimare
52ea1a48fd Merge pull request #184 from geeeeeeeeek/issue/network-error-page
Improve network error display.
2017-06-21 06:55:55 -07:00
Zhongyi Tong
98e73f807c Reload the app when users try to resume the connection. 2017-06-21 20:47:40 +08:00
Zhongyi Tong
f96dd6e6bc Fix linting error. 2017-06-21 20:11:58 +08:00
Zhongyi Tong
1511ce4610 Reconnect app when network comes back. 2017-06-21 20:10:58 +08:00
Akash Nimare
c2db6fc0f0 updated multi team screenshot 2017-06-21 17:35:58 +05:30
Zhongyi Tong
937a193a61 Fix linting errors. 2017-06-21 15:59:09 +08:00
Zhongyi Tong
3823ac7f78 Improve network error display. 2017-06-21 15:56:05 +08:00
akashnimare
878cc3fe82 focus window onclicking tray menus #fixes #183 2017-06-20 15:19:57 +05:30
akashnimare
eace637f29 Toggle window on clicking tray icon [Windows only] 2017-06-20 15:00:43 +05:30
akashnimare
316b5fda9e ignore spellchecker for input field 2017-06-19 15:56:06 +05:30
akashnimare
e3b8d5ea2a 🎉 v1.0.0-beta 2017-06-19 13:40:36 +05:30
akashnimare
c8434cfd21 disable auto updates for pre-release 2017-06-19 13:32:33 +05:30
akashnimare
fbc048e8cb increased min. height of window 2017-06-19 13:19:28 +05:30
akashnimare
8a4483da80 sidebar styling 2017-06-19 13:06:01 +05:30
akashnimare
8252c9ae6c remove unused tray option 2017-06-19 12:45:33 +05:30
Akash Nimare
5beb425f1c Merge pull request #180 from geeeeeeeeek/issue/refinements-on-server-side
Refinements on the main process
2017-06-19 12:28:04 +05:30
Zhongyi Tong
44337dd04c Fix a bug which would cause WebView not shown after loading. 2017-06-19 00:32:24 +08:00
Zhongyi Tong
bb76e2c2f4 Fix isInternal and open image in browser. 2017-06-18 09:58:13 +08:00
Zhongyi Tong
71305bca4e Load default icon locally. 2017-06-18 09:56:28 +08:00
Zhongyi Tong
9cff5c5a4d Fix linting errors. 2017-06-18 02:28:50 +08:00
Zhongyi Tong
f3cf2229c6 Add the ability to close for functional tabs. 2017-06-18 02:17:18 +08:00
Zhongyi Tong
a62fc3d3bf Split Tab into ServerTab and FuntionalTab. 2017-06-18 00:38:43 +08:00
Zhongyi Tong
e538543512 Move About page into WebView. 2017-06-17 22:38:24 +08:00
Zhongyi Tong
f85bca9879 Save. 2017-06-17 22:38:24 +08:00
Zhongyi Tong
f548a0ae53 Change the way utils load. 2017-06-17 22:38:24 +08:00
Zhongyi Tong
7192dc69f6 Put LinkUtil to renderer-side. 2017-06-17 22:38:23 +08:00
Zhongyi Tong
47eec89a9b Remove debug-purpose-comments in appUpdater. 2017-06-17 22:38:23 +08:00
Akash Nimare
48ff506344 Merge pull request #179 from zulip/window-close-fix
Fixed window close/hide logic + keep app running in background on close
2017-06-16 09:21:34 -07:00
akashnimare
c2e6e9603f fixed hide/quit logic #169, #160 2017-06-16 21:45:45 +05:30
akashnimare
f4f4836887 add focus option in tray + handle quit event properly 2017-06-16 20:39:16 +05:30
akashnimare
02bc5e41a5 keep app running in background on close 2017-06-16 20:29:16 +05:30
Akash Nimare
68c90434b3 Merge pull request #168 from geeeeeeeeek/issue/refinements-on-multi-tab-view
Refinements on multi tab view
2017-06-16 06:41:23 -07:00
Zhongyi Tong
7f8d933ab7 Fix lint errors. 2017-06-16 21:07:48 +08:00
Akash Nimare
935b37705a Merge pull request #175 from veeloinc/package-whitespace
normalize whitespace
2017-06-13 14:50:21 -07:00
Kevin Turner
798235fb06 normalize whitespace 2017-06-13 08:26:38 -07:00
Zhongyi Tong
743d689281 Avoid multiple webviews show at the same time. 2017-06-13 02:36:47 +08:00
Zhongyi Tong
4c188bbdc8 Update tabs position. 2017-06-13 02:18:35 +08:00
Zhongyi Tong
26e0543ae2 Fix missing badge element. 2017-06-13 01:55:53 +08:00
Zhongyi Tong
463701c5f8 Fix user-agent. 2017-06-13 01:50:37 +08:00
Zhongyi Tong
4c33f0779c Update badge style when unread number too large. 2017-06-13 00:57:28 +08:00
Zhongyi Tong
4888efb9f2 Use Zulip as app title. 2017-06-13 00:57:28 +08:00
Zhongyi Tong
ea332a9ff3 Rebase with geeeeeeeeek/issue/network-disconnectivity-resolution. 2017-06-13 00:57:28 +08:00
Zhongyi Tong
f1b2fdcf99 Disable WebView:focus outline. 2017-06-13 00:57:27 +08:00
Zhongyi Tong
9f73160f74 Add the ability to show badge count for each server. 2017-06-13 00:57:27 +08:00
Zhongyi Tong
b18e3ad5d2 Update title and badge on title change. 2017-06-13 00:57:27 +08:00
Zhongyi Tong
ed6013fb5d Add the ability to reload active webview in UI. 2017-06-13 00:57:27 +08:00
Zhongyi Tong
39b436819c Componentize Tab. 2017-06-13 00:57:27 +08:00
Zhongyi Tong
3e74fc9b0a Finish the refactoring of WebView. 2017-06-13 00:57:25 +08:00
Zhongyi Tong
0708519816 Componentize WebView. 2017-06-13 00:56:36 +08:00
Zhongyi Tong
84808313fe Add the ability to open DevTools for active webview. 2017-06-13 00:51:44 +08:00
Zhongyi Tong
e7e55596c6 Update icon names. 2017-06-13 00:51:44 +08:00
Zhongyi Tong
1b8eb099ab Disable text selections in multi-tab view. 2017-06-13 00:51:44 +08:00
Zhongyi Tong
1fa276a400 Update css structure. 2017-06-13 00:51:44 +08:00
Zhongyi Tong
0751f6ac72 Remove obsoleted main.css and rename servermanager.css to main.css.
Since we adopt new multi-tab UI for the app, the old main.css was obsoleted and not in use. For clarity, We should change the name of main.js's css file to main.css.
2017-06-13 00:51:44 +08:00
Akash Nimare
3d8da55648 update node dependency 2017-06-12 17:05:51 +05:30
Akash Nimare
318a729a4a Merge pull request #174 from geeeeeeeeek/issue/set-ua-properly
Set user-agent from a singleton util.
2017-06-12 02:27:09 -07:00
Zhongyi Tong
aab581f204 Fix missing app version in user-agent. 2017-06-12 11:32:23 +08:00
Zhongyi Tong
c0075b4f1c Set user-agent from a singleton util. 2017-06-12 01:07:45 +08:00
akashnimare
7bd2e751c5 fixed linting 2017-06-10 15:39:05 +05:30
akashnimare
5ff2492c79 temporarily disable electron browserwindow and other tests
Because of the chromedriver issue other tests like linting is failing. Disablingthis particular test will allow us to test for linting errors. This is just a temporary workaround and will be fixed ASAP.
2017-06-10 15:11:25 +05:30
Akash Nimare
a26df708f4 Merge pull request #171 from zulip/dev
Set useragent correctly fixes #170
2017-06-09 20:54:25 +05:30
akashnimare
57df256a4a set useragent correctly [WIP] #170 2017-06-09 07:52:45 +05:30
Akash Nimare
7f1890d8a1 Merge pull request #165 from geeeeeeeeek/issue/network-disconnectivity-resolution
Issue/network disconnectivity resolution
2017-06-04 01:38:12 -07:00
Akash Nimare
ff12b041a1 Merge pull request #162 from geeeeeeeeek/master
Fix WebView resize problem
2017-06-01 10:33:25 -07:00
Zhongyi Tong
606e407aee Fix network disconnectivity issue. 2017-06-01 19:33:56 +08:00
Zhongyi Tong
b0db81095a Attach user-agent to webview requests. 2017-06-01 19:09:36 +08:00
Zhongyi Tong
2208b03612 Remove vscode conf. 2017-05-30 20:41:13 +08:00
Zhongyi Tong
7cf2422d76 Fix webview resize problem when switching back to that webview. 2017-05-30 20:32:55 +08:00
akashnimare
57d4e5c930 load icons locally fixes #152 2017-05-28 02:27:25 -07:00
Akash Nimare
deafa315df Merge pull request #159 from zulip/bugfix-#158-focus-webview-on-tab-context-switch
Bugfix #158 focus webview on tab app switch
2017-05-28 01:29:55 -07:00
simplyahmazing
4c09da791c remove unneeded listener 2017-05-28 04:22:20 -04:00
simplyahmazing
e3490dbfa5 makes webview focus when browser window gains focus 2017-05-28 04:20:54 -04:00
akashnimare
f6358a06fd fixing network issue #157 [WIP] 2017-05-25 15:50:15 -07:00
akashnimare
3ef346495f updated spectron dependency 2017-05-25 11:48:49 -07:00
Akash Nimare
64fcc51c7e add chai as dependency 2017-05-24 18:59:06 -07:00
Akash Nimare
a5299a6973 Merge pull request #156 from zulip/20170523-090000-multiple-organizations-test
commment test
2017-05-24 18:53:42 -07:00
Akash Nimare
154aa323ab Update README.md 2017-05-24 18:48:28 -07:00
simplyahmazing
c52318f5d6 add chai as a dep 2017-05-24 21:41:25 -04:00
Akash Nimare
bcd4048709 Merge pull request #155 from lonerz/patch-2
CONTRIBUTING.md: Fix styling issues.
2017-05-24 18:28:45 -07:00
Joshua Pan
f6cb262d4c CONTRIBUTING.md: Fix styling issues.
beta please
2017-05-24 18:27:44 -07:00
Akash Nimare
ca21912374 Merge pull request #154 from lonerz/patch-1
development.md: Fix some grammar issues.
2017-05-24 18:13:38 -07:00
Joshua Pan
472ba9a199 development.md: Fix some grammar issues. 2017-05-24 17:20:58 -07:00
akashnimare
f3a4d4225d :memo updating development guide [WIP] 2017-05-24 17:16:28 -07:00
Akash Nimare
62178b6035 Update development.md 2017-05-24 17:13:19 -07:00
Akash Nimare
2068ac8905 Update development.md 2017-05-24 16:59:38 -07:00
akashnimare
51352be1f6 :memo updating development guide [WIP] 2017-05-24 16:58:27 -07:00
akashnimare
8c3bfcbdd5 :memo docs updated [WIP] 2017-05-24 16:51:14 -07:00
Akash Nimare
06ed522714 Update development.md 2017-05-24 16:46:44 -07:00
akashnimare
d5526944fe :memo updated development guide [WIP] 2017-05-24 16:44:07 -07:00
akashnimare
616ed89d90 :memo docs updated [WIP] 2017-05-24 16:38:09 -07:00
akashnimare
92362653d3 :memo docs updated [WIP] 2017-05-24 16:07:26 -07:00
Akash Nimare
06a09574a5 Update README.md 2017-05-24 15:27:01 -07:00
Akash Nimare
c19a7f81c2 updated development guide [WIP] 2017-05-24 15:26:14 -07:00
Akash Nimare
635b6f6128 📝 docs improvements [WIP] 2017-05-24 15:21:12 -07:00
Akash Nimare
996084cd36 Docs improvement [WIP] 2017-05-24 12:27:37 -07:00
Akash Nimare
6a403e52e1 Improve docs [WIP] 2017-05-24 11:20:02 -07:00
Akash Nimare
aed58ed1a8 Update README.md 2017-05-24 10:52:56 -07:00
Akash Nimare
0412702e35 improve docs [WIP] 2017-05-24 10:52:34 -07:00
Akash Nimare
cf0086e324 📝 improving docs 2017-05-24 10:31:06 -07:00
Akash Nimare
d156ba99c8 📝 improving docs 2017-05-24 10:30:54 -07:00
akashnimare
7d71e2e04d add missing dependency 2017-05-23 19:41:14 -07:00
Akash Nimare
546abb28c0 Merge pull request #153 from zulip/20170523-090000-multiple-organizations-test
multiple organizations tests
2017-05-23 19:37:23 -07:00
simplyahmazing
a43d008aa9 commment test 2017-05-23 22:15:10 -04:00
simplyahmazing
777ed5c561 cleans up tests 2017-05-23 22:11:22 -04:00
simplyahmazing
61db04c574 Merge branch 'master' into 20170523-090000-multiple-organizations-test 2017-05-23 20:33:01 -04:00
simplyahmazing
93123401fe fixes test 2017-05-23 20:32:53 -04:00
simplyahmazing
dca4debee2 setting up multi org test 2017-05-23 20:31:51 -04:00
akashnimare
bef1503b9e 💄 styling setting sidebar 2017-05-23 13:01:40 -07:00
simplyahmazing
f9d430b2d2 sets chai promised tests; improves application launched test case 2017-05-23 13:44:09 -04:00
simplyahmazing
0d551861c7 fixes tests; fixes linting errors 2017-05-23 13:09:58 -04:00
simplyahmazing
4ced663f01 removes window frame 2017-05-23 12:42:16 -04:00
Akash Nimare
06f15eba2d Merge pull request #151 from zulip/140-fixes
💥 Added multiple server support feature
2017-05-22 18:53:21 -07:00
Akash Nimare
3008cd1f24 Merge pull request #140 from geeeeeeeeek/feature/#1-add-support-for-multiple-server
🎉  Add nice support for multiple Zulip servers
2017-05-22 18:43:20 -07:00
SimplyAhmazing
ea449965af Merge branch '140-fixes' into feature/#1-add-support-for-multiple-server 2017-05-22 18:42:24 -07:00
simplyahmazing
06ecdb678c focus webview after loading 2017-05-22 21:21:53 -04:00
simplyahmazing
dd99560426 removes commented setting 2017-05-22 20:41:24 -04:00
simplyahmazing
cebea28ba8 change badge count on organization nav change 2017-05-22 20:37:48 -04:00
Akash Nimare
da3e7e39b9 shrink left sidebar
Just to remove unnecessary spacing.
2017-05-22 17:09:49 -07:00
Zhongyi Tong
4b4e3a3d01 Update Save Server button text. 2017-05-22 17:09:49 -07:00
Zhongyi Tong
aff4632927 Fix a typo. 2017-05-22 17:09:49 -07:00
Zhongyi Tong
eeb9ee512f Enable asar. 2017-05-22 17:09:49 -07:00
Zhongyi Tong
11785d78d2 Fix broken path issues using the module after packing. 2017-05-22 17:09:49 -07:00
Zhongyi Tong
f8d8d0ce2e Fix test errors. 2017-05-22 17:09:49 -07:00
Zhongyi Tong
b5af5d413d Add back badge count feature. 2017-05-22 17:09:49 -07:00
Zhongyi Tong
d962bd6e60 Migrate /domain to /domains. 2017-05-22 17:09:49 -07:00
Zhongyi Tong
0271ada591 Fix linter warnings. 2017-05-22 17:09:49 -07:00
Zhongyi Tong
42fedf2d73 Add reload button to preference page. 2017-05-22 17:09:49 -07:00
Zhongyi Tong
0b17dbb014 Initialize domains on first use. 2017-05-22 17:09:49 -07:00
Zhongyi Tong
ae3c595d82 Integrate actions from menu and tray with webview. 2017-05-22 17:09:49 -07:00
Zhongyi Tong
de34a22740 Move methods from mainWindow.webContents (index.js) to WebView (main.js). 2017-05-22 17:09:49 -07:00
Zhongyi Tong
865553fa45 Redirect to server settings page when domains are empty. 2017-05-22 17:09:49 -07:00
Zhongyi Tong
23fd7ba2b3 Update DomainUtil and finish PreferenceView. 2017-05-22 17:09:49 -07:00
Zhongyi Tong
e43b651060 Set up layout for PreferenceView. 2017-05-22 17:09:49 -07:00
Zhongyi Tong
c0fc7718aa Use multiple webview to increase loading speed and allow servers to be online at the same time. 2017-05-22 17:09:49 -07:00
Zhongyi Tong
3fe23e84b3 Refactor ServerManagerView and setup layout for PreferenceView. 2017-05-22 17:09:49 -07:00
Zhongyi Tong
6b29139805 Finish interactions of switching servers in ServerManagerView. 2017-05-22 17:09:49 -07:00
Zhongyi Tong
0bfa202763 Change domain config schema and update DomainUtil. 2017-05-22 17:09:49 -07:00
Zhongyi Tong
8c494f329b Setup the layout for ServerManagerView. 2017-05-22 17:09:49 -07:00
Zhongyi Tong
35bf2b0012 Add DomainUtil to manage domains in one place. 2017-05-22 17:09:49 -07:00
Zhongyi Tong
5ac4ea71c9 Update prototype design. 2017-05-22 17:09:49 -07:00
Zhongyi Tong
f7eb4128cb Finish UI template of multi-server manager. 2017-05-22 17:09:49 -07:00
simplyahmazing
f9f21cd626 bring back electron frame; shrink organization switcher bar 2017-05-22 19:16:05 -04:00
simplyahmazing
4a84f17d86 merge usptream master 2017-05-22 19:07:01 -04:00
akashnimare
d5a92110db build for mac apple store 2017-05-22 15:31:03 -07:00
akashnimare
e9cf591559 add mas config 2017-05-22 14:57:33 -07:00
akashnimare
ba60c04452 🆙 update dependencies 2017-05-22 12:10:58 -07:00
simplyahmazing
f4567c762d update spellchecker and electron to latest 2017-05-22 14:38:21 -04:00
Akash Nimare
b2aec4b27e Downgrade electron 2017-05-22 10:16:52 -07:00
akashnimare
0fc58b4cc9 Enable zipping of linux installers 2017-05-21 17:14:14 -07:00
akashnimare
e9d7bfe48b bump electron to v1.6.8 2017-05-21 17:05:36 -07:00
Akash Nimare
070eb099d0 typo fixed 2017-05-19 16:13:25 -07:00
Akash Nimare
e35661993d Document windows installer #148 2017-05-19 16:12:34 -07:00
Akash Nimare
f6234cd2f6 Merge pull request #147 from Lplenka/sleepresume
[WIP]#143 Improve handling of coming back online with the desktop app
2017-05-19 05:26:04 +05:30
Lplenka
66475cf46c [WIP] #143 Fixed lint error 2017-05-04 16:39:19 +05:30
Lplenka
06734d2e56 [WIP]#143 powerMoniter now checks when app is resumed 2017-05-04 15:12:15 +05:30
Zhongyi Tong
1c012c7a28 Update Save Server button text. 2017-04-30 23:08:45 +08:00
Zhongyi Tong
7fdccd278b Fix a typo. 2017-04-30 01:14:42 +08:00
Zhongyi Tong
9a4556a59c Enable asar. 2017-04-30 01:06:05 +08:00
Zhongyi Tong
92b9388f9a Fix broken path issues using the module after packing. 2017-04-30 00:01:22 +08:00
Zhongyi Tong
869600e3d4 Fix test errors. 2017-04-29 19:56:39 +08:00
Zhongyi Tong
3c22d5462d Add back badge count feature. 2017-04-29 17:37:08 +08:00
Zhongyi Tong
92ff92f501 Migrate /domain to /domains. 2017-04-29 15:37:02 +08:00
Zhongyi Tong
47b3dd04fb Fix linter warnings. 2017-04-29 01:10:21 +08:00
Zhongyi Tong
9ed09c9e1c Add reload button to preference page. 2017-04-28 23:56:59 +08:00
Zhongyi Tong
239cce8a4c Initialize domains on first use. 2017-04-28 23:56:59 +08:00
Zhongyi Tong
d6a35408b8 Integrate actions from menu and tray with webview. 2017-04-28 23:56:59 +08:00
Zhongyi Tong
35e6f7dcdd Move methods from mainWindow.webContents (index.js) to WebView (main.js). 2017-04-28 23:56:56 +08:00
Zhongyi Tong
a38c933bc8 Redirect to server settings page when domains are empty. 2017-04-28 23:00:08 +08:00
Zhongyi Tong
720ccf5d00 Update DomainUtil and finish PreferenceView. 2017-04-28 23:00:08 +08:00
Zhongyi Tong
8dc87d0485 Set up layout for PreferenceView. 2017-04-28 23:00:08 +08:00
Zhongyi Tong
cd9f1c0c47 Use multiple webview to increase loading speed and allow servers to be online at the same time. 2017-04-28 23:00:08 +08:00
Zhongyi Tong
331452edbb Refactor ServerManagerView and setup layout for PreferenceView. 2017-04-28 23:00:08 +08:00
Zhongyi Tong
d18885ecc9 Finish interactions of switching servers in ServerManagerView. 2017-04-28 23:00:08 +08:00
Zhongyi Tong
1aef53ef94 Change domain config schema and update DomainUtil. 2017-04-28 23:00:08 +08:00
Zhongyi Tong
11086210de Setup the layout for ServerManagerView. 2017-04-28 23:00:08 +08:00
Zhongyi Tong
e0d693fa19 Add DomainUtil to manage domains in one place. 2017-04-28 23:00:08 +08:00
Zhongyi Tong
81c71b1f83 Update prototype design. 2017-04-28 23:00:07 +08:00
Zhongyi Tong
cf8c83e3cf Finish UI template of multi-server manager. 2017-04-28 23:00:07 +08:00
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
57 changed files with 2101 additions and 1104 deletions

1
.gitignore vendored
View File

@@ -7,3 +7,4 @@ config.gypi
// osx garbage
*.DS_Store
.DS_Store
.idea

1
.node-version Normal file
View File

@@ -0,0 +1 @@
6.9.4

1
.python-version Normal file
View File

@@ -0,0 +1 @@
2.7.9

View File

@@ -5,6 +5,14 @@ os:
- osx
- linux
addons:
apt:
packages:
- build-essential
- libxext-dev
- libxtst-dev
- libxkbfile-dev
language: node_js
node_js:
- '6'
@@ -17,8 +25,12 @@ cache:
directories:
- node_modules
- app/node_modules
- $HOME/.electron
- $HOME/.cache
script:
- npm run travis
notifications:
webhooks:
urls:
- https://zulip.org/zulipbot/travis
on_success: always
on_failure: always

View File

@@ -1,37 +1,47 @@
#Contributing Guidelines
# Contributing Guidelines
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 Desktop Client. These are just guidelines, not rules, so use your best judgement and feel free to propose changes to this document in a pull request.
## 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 setting up a development environment, setting up with the Zulip webapp project, and testing, 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 on [chat.zulip.org](https://chat.zulip.org/#narrow/stream/electron).
## 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 bug, open a [new issue](https://github.com/zulip/zulip-electron/issues/new).
The [zulipbot](https://github.com/zulip/zulipbot) helps to claim an 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).
Please pay attention to the following points while opening an issue.
### Does it happen on web browsers? (especially Chrome)
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.
Zulip's desktop client 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](https://github.com/zulip/zulip).
### Write detailed information
Detailed information is very helpful to understand the problem.
Detailed information is very helpful to understand an issue.
For example:
* How to reproduce, step-by-step
* Expected behavior (or what is wrong)
* Screenshots (for GUI issues)
* Application version
* Operating system
* Zulip-Desktop version
* How to reproduce the issue, step-by-step.
* The expected behavior (or what is wrong).
* Screenshots for GUI issues.
* The application version.
* The operating system.
* The Zulip-Desktop version.
## Pull Requests
Pull Requests are welcome.
Pull Requests are always welcome.
1. When you edit the code, please run `npm run test` to check formatting of your code before git commit.
1. When you edit the code, please run `npm run test` to check the formatting of your code before you `git commit`.
2. Ensure the PR description clearly describes the problem and solution. It should include:
* Operating System version on which you tested
* Zulip-Desktop version on which you tested
* The relevant issue number if applicable
* The operating system on which you tested.
* The Zulip-Desktop version on which you tested.
* The relevant issue number, if applicable.

View File

@@ -1,80 +1,39 @@
# Zulip Desktop Client
# Zulip Desktop Client
[![Build Status](https://travis-ci.org/zulip/zulip-electron.svg?branch=master)](https://travis-ci.org/zulip/zulip-electron)
[![Windows Build Status](https://ci.appveyor.com/api/projects/status/github/zulip/zulip-electron?branch=master&svg=true)](https://ci.appveyor.com/project/akashnimare/zulip-electron/branch/master)
[![XO code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/sindresorhus/xo)
This is an experimental replacement for the [Zulip Desktop
app](https://github.com/zulip/zulip-desktop) implemented in
[Electron](http://electron.atom.io/).
Desktop client for Zulip. Available for Mac, Linux and Windows.
The goal is to achieve feature-compatibility with the old desktop app
and then start adding cool features like easy support for
multi-account, auto-updates etc.
<img src="http://i.imgur.com/ChzTq4F.png"/>
## Prerequisites
* node >= v6.3.1
* npm >= 3.10.3
* If you're on Debian or Ubuntu, you'll also need to install
`nodejs-legacy`:
```sh
$ sudo apt-get install nodejs-legacy
```
# Download
You can download the latest version from the [Releases](https://github.com/zulip/zulip-electron/releases/latest) page.
## Installation
Clone the source locally:
```sh
$ git clone https://github.com/zulip/zulip-electron
$ cd zulip-electron
```
Install project dependencies:
```sh
$ npm install
```
Start the app:
```sh
$ npm start
```
Start and watch changes
```sh
$ npm run dev
```
# Making a release
To package app into an installer use command:
```
npm run dist
```
It will start the packaging process for operating system you are running this command on. Ready for distribution file (e.g. dmg, windows installer, deb package) will be outputted to `dist` directory.
You can create Windows installer only when running on Windows, the same is true for Linux and OSX. So to generate all three installers you need all three operating systems.
## Features
- [x] Native Notifications
- [x] SpellChecker
- [x] OSX/Win/Linux installer
- [x] Automatic Updates (macOS)
- [x] Keyboard shortcuts
# Features
* Sign in to multiple teams
* Native desktop Notifications
* SpellChecker
* OSX/Win/Linux installers
* Automatic Updates (macOS/Windows)
* Keyboard shortcuts
Description | Keys
-----------------------| -----------------------
Default shortcuts | <kbd>Cmd/Ctrl</kbd> <kbd>k</kbd>
Change Zulip Server | <kbd>Cmd/Ctrl</kbd> <kbd>,</kbd>
Manage Zulip Servers | <kbd>Cmd/Ctrl</kbd> <kbd>,</kbd>
Back | <kbd>Cmd/Ctrl</kbd> <kbd>[</kbd>
Forward | <kbd>Cmd/Ctrl</kbd> <kbd>]</kbd>
# Development
Please see our [development guide](./development.md) to get started and run app locally.
## Contribute
# Contribute
If you want to contribute please make sure to read [our documentation about contributing](./CONTRIBUTING.md) first.
* [Issue Tracker](https://github.com/zulip/zulip-electron/issues)
* [Source Code](https://github.com/zulip/zulip-electron/)
# License
Released under the [Apache-2.0](./LICENSE) license.

View File

@@ -1,50 +1,34 @@
'use strict';
const os = require('os');
const {app, autoUpdater, dialog} = require('electron');
const version = app.getVersion();
const platform = os.platform() + '_' + os.arch(); // usually returns darwin_64
const updaterFeedURL = 'http://zulipdesktop.herokuapp.com/update/' + platform + '/' + version;
const {app, dialog} = require('electron');
const {autoUpdater} = require('electron-updater');
function appUpdater() {
autoUpdater.setFeedURL(updaterFeedURL);
// Log whats happening
// TODO send autoUpdater events to renderer so that we could
// it could console log in developer tools
autoUpdater.on('error', err => console.log(err));
autoUpdater.on('checking-for-update', () => console.log('checking-for-update'));
autoUpdater.on('update-available', () => console.log('update-available'));
autoUpdater.on('update-not-available', () => console.log('update-not-available'));
const log = require('electron-log');
log.transports.file.level = 'info';
autoUpdater.logger = log;
autoUpdater.allowPrerelease = false;
// Ask the user if update is available
autoUpdater.on('update-downloaded', (event, releaseNotes, releaseName) => {
let message = app.getName() + ' ' + releaseName + ' is now available. It will be installed the next time you restart the application.';
if (releaseNotes) {
const splitNotes = releaseNotes.split(/[^\r]\n/);
message += '\n\nRelease notes:\n';
splitNotes.forEach(notes => {
message += notes + '\n\n';
});
}
// eslint-disable-next-line no-unused-vars
autoUpdater.on('update-downloaded', (event, info) => {
// Ask user to update the app
dialog.showMessageBox({
type: 'question',
buttons: ['Install and Relaunch', 'Later'],
defaultId: 0,
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 => {
if (response === 0) {
setTimeout(() => autoUpdater.quitAndInstall(), 1);
}
});
});
// init for updates
// Init for updates
autoUpdater.checkForUpdates();
}
exports = module.exports = {
module.exports = {
appUpdater
};

View File

@@ -1,36 +0,0 @@
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);
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,44 +1,28 @@
'use strict';
const path = require('path');
const fs = require('fs');
const electron = require('electron');
const {app} = require('electron');
const ipc = require('electron').ipcMain;
const electronLocalshortcut = require('electron-localshortcut');
const Configstore = require('configstore');
const JsonDB = require('node-json-db');
const Configstore = require('electron-config');
const isDev = require('electron-is-dev');
const tray = require('./tray');
const appMenu = require('./menu');
const {linkIsInternal, skipImages} = require('./link-helper');
const {appUpdater} = require('./autoupdater');
const db = new JsonDB(app.getPath('userData') + '/domain.json', true, true);
const data = db.getData('/');
// Handling squirrel.windows events on windows
if (require('electron-squirrel-startup')) {
app.quit();
}
// 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')();
const conf = new Configstore('Zulip-Desktop');
const conf = new Configstore();
// prevent window being garbage collected
// Setting userAgent so that server-side code can identify the desktop app
// Prevent window being garbage collected
let mainWindow;
let targetLink;
let isQuitting = false;
// Load this url in main window
const staticURL = 'file://' + path.join(__dirname, '../renderer', 'index.html');
const targetURL = function () {
if (data.domain === undefined) {
return staticURL;
}
return data.domain;
};
const mainURL = 'file://' + path.join(__dirname, '../renderer', 'main.html');
const isAlreadyRunning = app.makeSingleInstance(() => {
if (mainWindow) {
@@ -51,14 +35,7 @@ const isAlreadyRunning = app.makeSingleInstance(() => {
});
if (isAlreadyRunning) {
app.quit();
}
function checkWindowURL() {
if (data.domain !== undefined) {
return data.domain;
}
return targetLink;
return app.quit();
}
function isWindowsOrmacOS() {
@@ -71,25 +48,6 @@ const iconPath = () => {
return APP_ICON + (process.platform === 'win32' ? '.ico' : '.png');
};
function onClosed() {
// dereference the window
// for multiple windows store them in an array
mainWindow = null;
}
function updateDockBadge(title) {
if (title.indexOf('Zulip') === -1) {
return;
}
let messageCount = (/\(([0-9]+)\)/).exec(title);
messageCount = messageCount ? Number(messageCount[1]) : 0;
if (process.platform === 'darwin') {
app.setBadgeCount(messageCount);
}
}
function createMainWindow() {
const win = new electron.BrowserWindow({
// This settings needs to be saved in config
@@ -98,17 +56,38 @@ function createMainWindow() {
height: conf.get('height') || 600,
icon: iconPath(),
minWidth: 600,
minHeight: 400,
minHeight: 500,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
plugins: true,
allowDisplayingInsecureContent: true,
nodeIntegration: false
nodeIntegration: true
},
show: false
});
win.on('focus', () => {
win.webContents.send('focus');
});
win.once('ready-to-show', () => {
win.show();
});
win.loadURL(mainURL);
// Keep the app running in background on close event
win.on('close', e => {
if (!isQuitting) {
e.preventDefault();
if (process.platform === 'darwin') {
app.hide();
} else {
win.hide();
}
}
});
win.loadURL(targetURL());
win.on('closed', onClosed);
win.setTitle('Zulip');
// Let's save browser window position
@@ -137,7 +116,7 @@ function createMainWindow() {
});
});
// on osx it's 'moved'
// On osx it's 'moved'
win.on('move', function () {
const pos = this.getPosition();
conf.set({
@@ -146,24 +125,25 @@ function createMainWindow() {
});
});
// stop page to update it's title
win.on('page-title-updated', (e, title) => {
e.preventDefault();
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;
}
// TODO - fix certificate errors
app.commandLine.appendSwitch('ignore-certificate-errors', 'true');
// 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', () => {
// unregister all the shortcuts so that they don't interfare with other apps
// Unregister all the shortcuts so that they don't interfare with other apps
electronLocalshortcut.unregisterAll(mainWindow);
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
@@ -175,65 +155,73 @@ app.on('activate', () => {
app.on('ready', () => {
electron.Menu.setApplicationMenu(appMenu);
mainWindow = createMainWindow();
tray.create(mainWindow);
const page = mainWindow.webContents;
// TODO - use global shortcut instead
electronLocalshortcut.register(mainWindow, 'CommandOrControl+R', () => {
// page.send('reload');
mainWindow.reload();
// page.send('destroytray');
});
electronLocalshortcut.register(mainWindow, 'CommandOrControl+[', () => {
if (page.canGoBack()) {
page.goBack();
}
page.send('back');
});
electronLocalshortcut.register(mainWindow, 'CommandOrControl+]', () => {
if (page.canGoForward()) {
page.goForward();
}
page.send('forward');
});
page.on('dom-ready', () => {
page.insertCSS(fs.readFileSync(path.join(__dirname, 'preload.css'), 'utf8'));
mainWindow.show();
});
page.on('new-window', (event, url) => {
if (linkIsInternal(checkWindowURL(), url) && url.match(skipImages) === null) {
event.preventDefault();
return mainWindow.loadURL(url);
}
event.preventDefault();
electron.shell.openExternal(url);
});
page.once('did-frame-finish-load', () => {
const checkOS = isWindowsOrmacOS();
if (checkOS && !isDev) {
// Initate auto-updates on macOs and windows
// Initate auto-updates on MacOS and Windows
appUpdater();
}
});
electron.powerMonitor.on('resume', () => {
mainWindow.reload();
mainWindow.webContents.send('destroytray');
});
ipc.on('focus-app', () => {
mainWindow.show();
});
ipc.on('quit-app', () => {
app.quit();
});
ipc.on('reload-main', () => {
page.reload();
});
ipc.on('toggle-app', () => {
if (mainWindow.isVisible()) {
mainWindow.hide();
} else {
mainWindow.show();
}
});
ipc.on('update-badge', (event, messageCount) => {
if (process.platform === 'darwin') {
app.setBadgeCount(messageCount);
}
page.send('tray', messageCount);
});
});
app.on('will-quit', () => {
// unregister all the shortcuts so that they don't interfare with other apps
// Unregister all the shortcuts so that they don't interfare with other apps
electronLocalshortcut.unregisterAll(mainWindow);
});
ipc.on('new-domain', (e, domain) => {
// mainWindow.loadURL(domain);
if (!mainWindow) {
mainWindow = createMainWindow();
mainWindow.loadURL(domain);
} else if (mainWindow.isMinimized()) {
mainWindow.loadURL(domain);
mainWindow.show();
} else {
mainWindow.loadURL(domain);
}
targetLink = domain;
app.on('before-quit', () => {
isQuitting = true;
});

View File

@@ -1,15 +0,0 @@
const wurl = require('wurl');
// Check link if it's internal/external
function linkIsInternal(currentUrl, newUrl) {
const currentDomain = wurl('hostname', currentUrl);
const newDomain = wurl('hostname', newUrl);
return currentDomain === newDomain;
}
// We'll be needing this to open images in default browser
const skipImages = '.jpg|.gif|.png|.jpeg|.JPG|.PNG';
exports = module.exports = {
linkIsInternal, skipImages
};

View File

@@ -2,13 +2,13 @@
const os = require('os');
const electron = require('electron');
const {dialog} = require('electron');
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;
const shell = electron.shell;
const appName = app.getName();
const {addDomain, about} = require('./windowmanager');
function sendAction(action) {
const win = BrowserWindow.getAllWindows()[0];
@@ -19,12 +19,20 @@ function sendAction(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 = [
{
label: 'Reload',
click(item, focusedWindow) {
if (focusedWindow) {
focusedWindow.reload();
sendAction('reload');
}
}
},
@@ -65,13 +73,30 @@ const viewSubmenu = [
type: 'separator'
},
{
label: 'Toggle Developer Tools',
label: 'Toggle Tray Icon',
click(item, focusedWindow) {
if (focusedWindow) {
focusedWindow.webContents.send('toggletray');
}
}
},
{
label: 'Toggle DevTools for Zulip App',
accelerator: process.platform === 'darwin' ? 'Alt+Command+I' : 'Ctrl+Shift+I',
click(item, focusedWindow) {
if (focusedWindow) {
focusedWindow.webContents.toggleDevTools();
}
}
},
{
label: 'Toggle DevTools for Active Tab',
accelerator: process.platform === 'darwin' ? 'Alt+Command+U' : 'Ctrl+Shift+U',
click(item, focusedWindow) {
if (focusedWindow) {
sendAction('tab-devtools');
}
}
}
];
@@ -108,18 +133,22 @@ const darwinTpl = [
submenu: [
{
label: 'Zulip desktop',
click() {
about();
click(item, focusedWindow) {
if (focusedWindow) {
sendAction('open-about');
}
}
},
{
type: 'separator'
},
{
label: 'Change Zulip Server',
label: 'Manage Zulip Servers',
accelerator: 'Cmd+,',
click() {
addDomain();
click(item, focusedWindow) {
if (focusedWindow) {
sendAction('open-settings');
}
}
},
{
@@ -134,8 +163,15 @@ const darwinTpl = [
{
type: 'separator'
},
{
label: 'Clear Cache',
click() {
clearCache();
}
},
{
label: 'Log Out',
accelerator: 'Cmd+L',
click(item, focusedWindow) {
if (focusedWindow) {
sendAction('log-out');
@@ -234,18 +270,22 @@ const otherTpl = [
submenu: [
{
label: 'Zulip desktop',
click() {
about();
click(item, focusedWindow) {
if (focusedWindow) {
sendAction('open-about');
}
}
},
{
type: 'separator'
},
{
label: 'Change Zulip Server',
label: 'Manage Zulip Servers',
accelerator: 'Ctrl+,',
click() {
addDomain();
click(item, focusedWindow) {
if (focusedWindow) {
sendAction('open-settings');
}
}
},
{
@@ -263,8 +303,15 @@ const otherTpl = [
{
type: 'separator'
},
{
label: 'Clear Cache',
click() {
clearCache();
}
},
{
label: 'Log Out',
accelerator: 'Ctrl+L',
click(item, focusedWindow) {
if (focusedWindow) {
sendAction('log-out');
@@ -275,7 +322,8 @@ const otherTpl = [
type: 'separator'
},
{
role: 'quit'
role: 'quit',
accelerator: 'Ctrl+Q'
}
]
},
@@ -312,7 +360,6 @@ const otherTpl = [
{
role: 'selectall'
}
]
},
{

View File

@@ -1 +0,0 @@
/* We'll be overriding default styling so that app look more native * /

View File

@@ -1,52 +0,0 @@
'use strict';
const ipcRenderer = require('electron').ipcRenderer;
const {webFrame} = require('electron');
// 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();
});
// To prevent failing this script on linux we need to load it after the document loaded
document.addEventListener('DOMContentLoaded', () => {
require('./spellchecker')();
});
require('./domain')();

View File

@@ -1,22 +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');
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();
});

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,69 +0,0 @@
'use strict';
const path = require('path');
const electron = require('electron');
let domainWindow;
let aboutWindow;
function onClosed() {
// dereference the window
domainWindow = null;
aboutWindow = null;
}
// Change Zulip server Window
function createdomainWindow() {
const domainwin = new electron.BrowserWindow({
frame: false,
height: 300,
resizable: false,
width: 400
});
const domainURL = 'file://' + path.join(__dirname, '../renderer', 'pref.html');
domainwin.loadURL(domainURL);
domainwin.on('closed', onClosed);
return domainwin;
}
// Call this window onClick addDomain in tray
function addDomain() {
domainWindow = createdomainWindow();
domainWindow.show();
}
// About window
function createAboutWindow() {
const aboutwin = new electron.BrowserWindow({
width: 500,
height: 500,
title: 'About Zulip Desktop',
show: false,
center: true,
fullscreen: false,
fullscreenable: false,
resizable: false
});
const aboutURL = 'file://' + path.join(__dirname, '../renderer', 'about.html');
aboutwin.loadURL(aboutURL);
aboutwin.on('closed', onClosed);
// stop page to update it's title
aboutwin.on('page-title-updated', e => {
e.preventDefault();
});
aboutwin.on('closed', onClosed);
return aboutwin;
}
// Call this onClick About in tray
function about() {
aboutWindow = createAboutWindow();
aboutWindow.show();
}
exports = module.exports = {
addDomain, about
};

View File

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

View File

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

View File

@@ -1,15 +1,22 @@
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 {
margin-top: 50px;
}
.left {
position: absolute;
top:89%;
left:76%;
text-align: center;
}
.about p {
@@ -18,10 +25,49 @@ body {
}
.about img {
width:160px;
width: 150px;
}
.detail {
text-align: left;
margin-left: 35%;
}
text-align: center;
}
.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,184 @@
@charset "UTF-8";
header,
section {
display: block
}
html {
font-size: 100%;
overflow-y: scroll;
-webkit-text-size-adjust: 100%;
}
html,
button,
input {
font-family: "Helvetica Neue", Arial, sans-serif
}
html,
body {
/*******************
* General rules *
*******************/
html, body {
height: 100%;
margin: 0
}
img {
border: 0;
-ms-interpolation-mode: bicubic
}
img {
vertical-align: middle
}
form {
margin: 0
}
fieldset {
border: 0;
margin: 0;
padding: 0
cursor: default;
user-select:none;
}
button,
input {
font-size: 100%;
margin: 0;
vertical-align: baseline;
box-sizing: content-box;
-webkit-box-sizing: content-box
#content {
display: flex;
height: 100%;
background: #eee url(../img/ic_loading.gif) no-repeat;
background-size: 60px 60px;
background-position: center;
}
button,
input {
line-height: normal
#sidebar {
background: #222c31;
width: 54px;
padding: 27px 0 20px 0;
justify-content: space-between;
display: flex;
flex-direction: column;
-webkit-app-region: drag;
}
button {
@font-face {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: local('Material Icons'),
local('MaterialIcons-Regular'),
url(../fonts/MaterialIcons-Regular.ttf) format('truetype');
}
/*******************
* Left Sidebar *
*******************/
#tabs-container {
display: flex;
align-items: center;
flex-direction: column;
}
.material-icons {
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
/* Preferred icon size */
font-size: 24px;
display: inline-block;
line-height: 1;
text-transform: none;
letter-spacing: normal;
word-wrap: normal;
white-space: nowrap;
direction: ltr;
/* Support for all WebKit browsers. */
-webkit-font-smoothing: antialiased;
/* Support for Safari and Chrome. */
text-rendering: optimizeLegibility;
}
.action-button {
display: flex;
flex-direction: column;
align-items: center;
padding: 10px;
}
.action-button i {
color: #6c8592;
font-size: 28px;
}
.action-button:hover i {
color: #98a9b3;
}
.tab {
position: relative;
margin: 5px 0;
cursor: pointer;
-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 {
z-index: 800;
border-bottom: 1px solid #dae0e7;
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 {
position: absolute!important;
top: 50%;
left: 10px;
-webkit-transform: translate(0, -50%);
transform: translate(0, -50%)
}
body.container-layout header #logo {
position: relative!important;
top: 0;
left: 0;
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
margin: 0 auto;
display: block
}
.content {
padding-bottom: 40px;
overflow: hidden
}
.container-layout .content {
max-width: 660px;
margin: 0 auto
}
.content .server {
position: relative;
margin: 0 10px
}
.content .server .container {
.tab.active::before {
content: "";
background: #fff;
-webkit-box-sizing: border-box;
box-sizing: border-box;
padding: 50px 0 0;
-webkit-border-radius: 4px;
border-radius: 0 3px 3px 0;
width: 4px;
position: absolute;
height: 35px;
left: -10px;
top: 5px;
}
.tab .server-tab {
background: #a4d3c4;
background-size: 100%;
border-radius: 4px;
width: 35px;
height: 35px;
position: relative;
z-index: 10;
max-width: 580px
}
.content .server h1 {
margin: 5px 0;
z-index: 11;
line-height: 31px;
color: #194a2b;
text-align: center;
padding: 0 10%
overflow: hidden;
opacity: 0.6;
}
.content .server h1 {
font-size: 2.4em;
line-height: 1.2em;
margin-bottom: 10px
.tab .server-tab:hover {
opacity: 0.8;
}
.content .server fieldset {
padding: 25px 10% 80px 39px;
position: relative
.tab .functional-tab {
background: #eee;
}
.content .server fieldset .control-group .control-field input {
width: 100%
.tab .functional-tab i {
font-size: 28px;
line-height: 36px;
}
.content .server button {
width: 100%
.tab.active .server-tab {
opacity: 1;
}
@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 {
.tab .server-tab-badge.active {
border-radius: 9px;
min-width: 11px;
padding: 0 3px;
height: 17px;
background-color: #f44336;
font-size: 10px;
font-family: sans-serif;
position: absolute;
right: -6px;
z-index: 15;
top: -2px;
float: right;
color: #fff;
text-align: center;
color: #c71212;
line-height: 17px;
display: block;
}
.tab .server-tab-badge {
display: none;
}
.tab .server-tab-badge.close-button {
width: 16px;
padding: 0 0 0 1px;
}
.tab .server-tab-badge.close-button i {
font-size: 13px;
line-height: 17px;
}
/*******************
* Webview Area *
*******************/
webview {
opacity: 1;
transition: opacity 0.3s;
flex-grow: 1;
}
webview.disabled {
flex: 0 1;
height: 0;
width: 0;
opacity: 0;
transition: opacity 0.3s;
}
webview:focus {
outline: 0px solid transparent;
}

View File

@@ -0,0 +1,42 @@
html, body {
margin: 0;
cursor: default;
font-size: 14px;
color: #333;
background: #fff;
user-select:none;
}
#content {
display: flex;
flex-direction: column;
font-family: "Trebuchet MS", Helvetica, sans-serif;
margin: 100px 200px;
text-align: center;
}
#title {
font-size: 24px;
font-weight: bold;
margin: 20px 0;
}
#description {
font-size: 16px;
}
#reconnect {
font-size: 16px;
background: #009688;
color: #fff;
width: 84px;
height: 32px;
border-radius: 5px;
line-height: 32px;
margin: 20px auto 0;
cursor: pointer;
}
#reconnect:hover {
opacity: 0.8;
}

View File

@@ -1,83 +0,0 @@
body{
background-color: #6BB6C7;
}
.form {
position: absolute;
top: 35%;
width: 300px;
left: 9%;
}
.close {
background: transparent url('../img/close.png') no-repeat 4px 4px;
background-size: 24px 24px;
cursor: pointer;
display: inline-block;
height: 32px;
position: absolute;
right: 6px;
text-indent: -10000px;
top: 6px;
width: 32px;
z-index: 1;
-webkit-app-region: no-drag;
}
input[type="text"] {
display: block;
margin: 0;
width: 100%;
font-family: sans-serif;
font-size: 18px;
appearance: none;
box-shadow: none;
border-radius: none;
color: #646464;
}
input[type="text"]:focus {
outline: none;
}
.form input[type="text"] {
padding: 10px;
border: solid 1px #dcdcdc;
transition: box-shadow 0.3s, border 0.3s;
}
.form input[type="text"]:focus,
.form input[type="text"].focus {
border: solid 1px #707070;
box-shadow: 0 0 5px 1px #969696;
}
button {
border: none;
color: #fff;
padding: 12px 32px;
text-align: center;
text-decoration: none;
margin-left: 107px;
margin-top: 24px;
display: inline-block;
font-size: 16px;
background: #137b86;
}
button:focus {
outline: 0;
}
#urladded {
font-size: 20px;
position: absolute;
font-family: 'opensans';
top: -61%;
left: 25%;
text-align: center;
}
#pic {
width: 20px;
left: 36%;
margin-left: 4px;
top: 63%;
display: none;
position: absolute;
}

View File

@@ -0,0 +1,181 @@
html,
body {
height: 100%;
margin: 0;
cursor: default;
font-size: 14px;
color: #333;
background: #fff;
}
#content {
display: flex;
height: 100%;
font-family: sans-serif;
}
#sidebar {
width: 80px;
padding: 30px;
display: flex;
flex-direction: column;
font-size: 16px;
}
#tabs-container {
padding: 20px 0;
}
.tab {
padding: 5px 0;
color: #999;
cursor: pointer;
}
.tab.active {
color: #464e5a;
cursor: default;
position: relative;
}
.tab.active::before {
background: #464e5a;
width: 3px;
height: 16px;
position: absolute;
left: -8px;
content: '';
}
#settings-header {
font-size: 22px;
color: #5c6166;
}
#settings-container {
width: 100%;
display: flex;
padding: 30px;
overflow-y: scroll;
}
.server-info-container {
margin: 20px 0;
}
.title {
padding: 4px 0 6px 0;
font-size: 18px;
color: #000;
}
img.server-info-icon {
background: #a4d3c4;
background-size: 100%;
border-radius: 4px;
width: 44px;
height: 44px;
}
.server-info-left {
margin-right: 20px;
}
.server-info-right {
flex-grow: 1;
}
.server-info-row {
display: flex;
line-height: 26px;
height: 40px;
}
.server-info-key {
width: 40px;
margin-right: 20px;
text-align: right;
}
.server-info-value {
flex-grow: 1;
font-size: 14px;
height: 24px;
border: none;
border-bottom: #ddd 1px solid;
outline-width: 0;
background: transparent;
max-width: 500px;
}
.server-info-value:focus {
border-bottom: #b0d8ce 2px solid;
}
.actions-container {
display: flex;
font-size: 14px;
color: #235d3a;
vertical-align: middle;
margin: 10px 0;
flex-wrap: wrap;
}
.action {
display: flex;
align-items: center;
margin-right: 20px;
}
.action i {
margin-right: 5px;
font-size: 18px;
}
.settings-pane {
flex-grow: 1;
}
.action:hover {
cursor: pointer;
}
.action.disabled:hover {
cursor: default;
}
.action.disabled {
color: #999;
}
.server-info.active {
background: #ecf4ef;
}
.server-info {
display: flex;
padding: 10px;
margin: 10px 0 10px 0;
}
.hidden {
display: none;
}
.save-server-button {
display: inline-block;
cursor: pointer;
padding: 7px 14px;
background-color: #52c2af;
border-radius: 4px;
border: 0;
font-size: 1em;
font-weight: 600;
color: #fff;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
transition: all .2s ease;
}
.save-server-button:hover {
background-color: #32a692;
}

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 803 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
app/renderer/img/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

View File

@@ -1,42 +0,0 @@
<!DOCTYPE html>
<html lang="en" class="responsive desktop">
<!--<![endif]-->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width">
<title>Login - Zulip</title>
<link rel="stylesheet" href="css/main.css" type="text/css" media="screen">
</head>
<body class="container-layout">
<div class="section-main">
<header>
<div class="container">
<img src="../resources/zulip.png" id="logo"/>
</div>
</header>
<hr>
<section class="content">
<section class="server">
<div class="container">
<h1>Login to Zulip Server</h1>
<form id="frm-signInForm" class="form-large" onsubmit="addDomain(); return false">
<fieldset>
<div class="control-group control-required">
<div class="control-field">
<input type="text" id="url" autofocus="autofocus" spellcheck="false" placeholder="chat.zulip.org">
</div>
</div>
<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>
</div>
</section>
</section>
</div>
</body>
</html>

View File

@@ -0,0 +1,11 @@
'use strict';
class BaseComponent {
generateNodeFromTemplate(template) {
const wrapper = document.createElement('div');
wrapper.innerHTML = template;
return wrapper.firstElementChild;
}
}
module.exports = BaseComponent;

View File

@@ -0,0 +1,43 @@
'use strict';
const Tab = require(__dirname + '/../components/tab.js');
class FunctionalTab extends Tab {
template() {
return `<div class="tab">
<div class="server-tab-badge close-button">
<i class="material-icons">close</i>
</div>
<div class="server-tab functional-tab">
<i class="material-icons">${this.props.materialIcon}</i>
</div>
</div>`;
}
init() {
this.$el = this.generateNodeFromTemplate(this.template());
this.props.$root.appendChild(this.$el);
this.$closeButton = this.$el.getElementsByClassName('server-tab-badge')[0];
this.registerListeners();
}
registerListeners() {
super.registerListeners();
this.$el.addEventListener('mouseover', () => {
this.$closeButton.classList.add('active');
});
this.$el.addEventListener('mouseout', () => {
this.$closeButton.classList.remove('active');
});
this.$closeButton.addEventListener('click', e => {
this.props.onDestroy();
e.stopPropagation();
});
}
}
module.exports = FunctionalTab;

View File

@@ -0,0 +1,31 @@
'use strict';
const Tab = require(__dirname + '/../components/tab.js');
class ServerTab extends Tab {
template() {
return `<div class="tab">
<div class="server-tab-badge"></div>
<div class="server-tab" style="background-image: url(${this.props.icon});"></div>
</div>`;
}
init() {
super.init();
this.$badge = this.$el.getElementsByClassName('server-tab-badge')[0];
}
updateBadge(count) {
if (count > 0) {
const formattedCount = count > 999 ? '1K+' : count;
this.$badge.innerHTML = formattedCount;
this.$badge.classList.add('active');
} else {
this.$badge.classList.remove('active');
}
}
}
module.exports = ServerTab;

View File

@@ -0,0 +1,49 @@
'use strict';
const BaseComponent = require(__dirname + '/../components/base.js');
class Tab extends BaseComponent {
constructor(props) {
super();
this.props = props;
this.webview = this.props.webview;
this.init();
}
init() {
this.$el = this.generateNodeFromTemplate(this.template());
this.props.$root.appendChild(this.$el);
this.registerListeners();
}
registerListeners() {
this.$el.addEventListener('click', this.props.onClick);
}
isLoading() {
return this.webview.isLoading;
}
activate() {
this.$el.classList.add('active');
this.webview.load();
}
deactivate() {
this.$el.classList.remove('active');
this.webview.hide();
}
destroy() {
this.$el.parentNode.removeChild(this.$el);
this.webview.$el.parentNode.removeChild(this.webview.$el);
}
}
Tab.SERVER_TAB = 0;
Tab.SETTINGS_TAB = 1;
module.exports = Tab;

View File

@@ -0,0 +1,178 @@
'use strict';
const DomainUtil = require(__dirname + '/../utils/domain-util.js');
const SystemUtil = require(__dirname + '/../utils/system-util.js');
const LinkUtil = require(__dirname + '/../utils/link-util.js');
const {app, dialog, shell} = require('electron').remote;
const {ipcRenderer} = require('electron');
const BaseComponent = require(__dirname + '/../components/base.js');
class WebView extends BaseComponent {
constructor(props) {
super();
this.props = props;
this.zoomFactor = 1.0;
this.loading = false;
this.badgeCount = 0;
}
template() {
return `<webview
class="disabled"
src="${this.props.url}"
${this.props.nodeIntegration ? 'nodeIntegration' : ''}
disablewebsecurity
preload="js/preload.js"
webpreferences="allowRunningInsecureContent, javascript=yes">
</webview>`;
}
init() {
this.$el = this.generateNodeFromTemplate(this.template());
this.props.$root.appendChild(this.$el);
this.registerListeners();
}
registerListeners() {
this.$el.addEventListener('new-window', event => {
const {url} = event;
const domainPrefix = DomainUtil.getDomain(this.props.index).url;
if (LinkUtil.isInternal(domainPrefix, url)) {
event.preventDefault();
this.$el.loadURL(url);
} else {
event.preventDefault();
shell.openExternal(url);
}
});
this.$el.addEventListener('page-title-updated', event => {
const {title} = event;
this.badgeCount = this.getBadgeCount(title);
this.props.onTitleChange();
});
this.$el.addEventListener('dom-ready', this.show.bind(this));
this.$el.addEventListener('did-fail-load', event => {
const {errorDescription} = event;
const hasConnectivityErr = (SystemUtil.connectivityERR.indexOf(errorDescription) >= 0);
if (hasConnectivityErr) {
console.error('error', errorDescription);
this.props.onNetworkError();
}
});
this.$el.addEventListener('did-start-loading', () => {
let userAgent = SystemUtil.getUserAgent();
if (!userAgent) {
SystemUtil.setUserAgent(this.$el.getUserAgent());
userAgent = SystemUtil.getUserAgent();
}
this.$el.setUserAgent(userAgent);
});
}
getBadgeCount(title) {
const messageCountInTitle = (/\(([0-9]+)\)/).exec(title);
return messageCountInTitle ? Number(messageCountInTitle[1]) : 0;
}
show() {
// Do not show WebView if another tab was selected and this tab should be in background.
if (!this.props.isActive()) {
return;
}
this.$el.classList.remove('disabled');
this.focus();
this.loading = false;
this.props.onTitleChange(this.$el.getTitle());
}
focus() {
this.$el.focus();
}
hide() {
this.$el.classList.add('disabled');
}
load() {
if (this.$el) {
this.show();
} else {
this.init();
}
}
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) {
this.reload();
ipcRenderer.send('reload');
ipcRenderer.send('destroytray');
}
if (index === 1) {
app.quit();
}
});
}
zoomIn() {
this.zoomFactor += 0.1;
this.$el.setZoomFactor(this.zoomFactor);
}
zoomOut() {
this.zoomFactor -= 0.1;
this.$el.setZoomFactor(this.zoomFactor);
}
zoomActualSize() {
this.zoomFactor = 1.0;
this.$el.setZoomFactor(this.zoomFactor);
}
logOut() {
this.$el.executeJavaScript('logout()');
}
showShortcut() {
this.$el.executeJavaScript('shortcut()');
}
openDevTools() {
this.$el.openDevTools();
}
back() {
if (this.$el.canGoBack()) {
this.$el.goBack();
}
}
forward() {
if (this.$el.canGoForward()) {
this.$el.goForward();
}
}
reload() {
this.hide();
this.$el.reload();
}
}
module.exports = WebView;

204
app/renderer/js/main.js Normal file
View File

@@ -0,0 +1,204 @@
'use strict';
require(__dirname + '/js/tray.js');
const {ipcRenderer} = require('electron');
const DomainUtil = require(__dirname + '/js/utils/domain-util.js');
const WebView = require(__dirname + '/js/components/webview.js');
const ServerTab = require(__dirname + '/js/components/server-tab.js');
const FunctionalTab = require(__dirname + '/js/components/functional-tab.js');
class ServerManagerView {
constructor() {
this.$tabsContainer = document.getElementById('tabs-container');
const $actionsContainer = document.getElementById('actions-container');
this.$reloadButton = $actionsContainer.querySelector('#reload-action');
this.$addServerButton = $actionsContainer.querySelector('#add-action');
this.$settingsButton = $actionsContainer.querySelector('#settings-action');
this.$content = document.getElementById('content');
this.activeTabIndex = -1;
this.tabs = [];
this.functionalTabs = {};
}
init() {
this.initTabs();
this.initActions();
this.registerIpcs();
}
initTabs() {
const servers = DomainUtil.getDomains();
if (servers.length > 0) {
for (let i = 0; i < servers.length; i++) {
this.initServer(servers[i], i);
}
this.activateTab(0);
} else {
this.openSettings();
}
}
initServer(server, index) {
this.tabs.push(new ServerTab({
icon: server.icon,
$root: this.$tabsContainer,
onClick: this.activateTab.bind(this, index),
webview: new WebView({
$root: this.$content,
index,
url: server.url,
name: server.alias,
isActive: () => {
return index === this.activeTabIndex;
},
onNetworkError: this.openNetworkTroubleshooting.bind(this),
onTitleChange: this.updateBadge.bind(this),
nodeIntegration: false
})
}));
}
initActions() {
this.$reloadButton.addEventListener('click', () => {
this.tabs[this.activeTabIndex].webview.reload();
});
this.$addServerButton.addEventListener('click', this.openSettings.bind(this));
this.$settingsButton.addEventListener('click', this.openSettings.bind(this));
}
openFunctionalTab(tabProps) {
if (this.functionalTabs[tabProps.name]) {
this.activateTab(this.functionalTabs[tabProps.name]);
return;
}
this.functionalTabs[tabProps.name] = this.tabs.length;
this.tabs.push(new FunctionalTab({
materialIcon: tabProps.materialIcon,
$root: this.$tabsContainer,
onClick: this.activateTab.bind(this, this.functionalTabs[tabProps.name]),
onDestroy: this.destroyTab.bind(this, tabProps.name, this.functionalTabs[tabProps.name]),
webview: new WebView({
$root: this.$content,
index: this.functionalTabs[tabProps.name],
url: tabProps.url,
name: tabProps.name,
isActive: () => {
return this.functionalTabs[tabProps.name] === this.activeTabIndex;
},
onNetworkError: this.openNetworkTroubleshooting.bind(this),
onTitleChange: this.updateBadge.bind(this),
nodeIntegration: true
})
}));
this.activateTab(this.functionalTabs[tabProps.name]);
}
openSettings() {
this.openFunctionalTab({
name: 'Settings',
materialIcon: 'settings',
url: `file://${__dirname}/preference.html`
});
}
openAbout() {
this.openFunctionalTab({
name: 'About',
materialIcon: 'sentiment_very_satisfied',
url: `file://${__dirname}/about.html`
});
}
openNetworkTroubleshooting() {
this.openFunctionalTab({
name: 'Network Troubleshooting',
materialIcon: 'network_check',
url: `file://${__dirname}/network.html`
});
}
activateTab(index, hideOldTab = true) {
if (this.tabs[index].loading) {
return;
}
if (this.activeTabIndex !== -1) {
if (this.activeTabIndex === index) {
return;
} else if (hideOldTab) {
this.tabs[this.activeTabIndex].deactivate();
}
}
this.activeTabIndex = index;
this.tabs[index].activate();
}
destroyTab(name, index) {
if (this.tabs[index].loading) {
return;
}
this.tabs[index].destroy();
delete this.tabs[index];
delete this.functionalTabs[name];
this.activateTab(0, false);
}
updateBadge() {
let messageCountAll = 0;
for (let i = 0; i < this.tabs.length; i++) {
if (this.tabs[i] && this.tabs[i].updateBadge) {
const count = this.tabs[i].webview.badgeCount;
messageCountAll += count;
this.tabs[i].updateBadge(count);
}
}
ipcRenderer.send('update-badge', messageCountAll);
}
registerIpcs() {
const webviewListeners = {
'webview-reload': 'reload',
back: 'back',
focus: 'focus',
forward: 'forward',
zoomIn: 'zoomIn',
zoomOut: 'zoomOut',
zoomActualSize: 'zoomActualSize',
'log-out': 'logOut',
shortcut: 'showShortcut',
'tab-devtools': 'openDevTools'
};
for (const key in webviewListeners) {
ipcRenderer.on(key, () => {
const activeWebview = this.tabs[this.activeTabIndex].webview;
if (activeWebview) {
activeWebview[webviewListeners[key]]();
}
});
}
ipcRenderer.on('open-settings', this.openSettings.bind(this));
ipcRenderer.on('open-about', this.openAbout.bind(this));
}
}
window.onload = () => {
const serverManagerView = new ServerManagerView();
serverManagerView.init();
};
window.addEventListener('online', () => {
ipcRenderer.send('reload-main');
});

View File

@@ -0,0 +1,20 @@
'use strict';
const {ipcRenderer} = require('electron');
class NetworkTroubleshootingView {
constructor() {
this.$reconnectButton = document.getElementById('reconnect');
}
init() {
this.$reconnectButton.addEventListener('click', () => {
ipcRenderer.send('reload-main');
});
}
}
window.onload = () => {
const networkTroubleshootingView = new NetworkTroubleshootingView();
networkTroubleshootingView.init();
};

View File

@@ -0,0 +1,144 @@
'use strict';
const {ipcRenderer} = require('electron');
const DomainUtil = require(__dirname + '/js/utils/domain-util.js');
class PreferenceView {
constructor() {
this.$newServerButton = document.getElementById('new-server-action');
this.$saveServerButton = document.getElementById('save-server-action');
this.$reloadServerButton = document.getElementById('reload-server-action');
this.$serverInfoContainer = document.querySelector('.server-info-container');
}
init() {
this.initServers();
this.initActions();
}
initServers() {
const servers = DomainUtil.getDomains();
this.$serverInfoContainer.innerHTML = servers.length ? '' : 'Add your first server to get started!';
this.initNewServerForm();
for (const i in servers) {
this.initServer(servers[i], i);
}
}
initServer(server, index) {
const {
alias,
url,
icon
} = server;
const serverInfoTemplate = `
<div class="server-info">
<div class="server-info-left">
<img class="server-info-icon" src="${icon}"/>
</div>
<div class="server-info-right">
<div class="server-info-row">
<span class="server-info-key">Name</span>
<input class="server-info-value" disabled value="${alias}"/>
</div>
<div class="server-info-row">
<span class="server-info-key">Url</span>
<input class="server-info-value" disabled value="${url}"/>
</div>
<div class="server-info-row">
<span class="server-info-key">Icon</span>
<input class="server-info-value" disabled value="${icon}"/>
</div>
<div class="server-info-row">
<span class="server-info-key">Actions</span>
<div class="action server-info-value" id="delete-server-action-${index}">
<i class="material-icons">indeterminate_check_box</i>
<span>Delete</span>
</div>
</div>
</div>
</div>`;
this.$serverInfoContainer.appendChild(this.insertNode(serverInfoTemplate));
document.getElementById(`delete-server-action-${index}`).addEventListener('click', () => {
DomainUtil.removeDomain(index);
this.initServers();
// alert('Success. Reload to apply changes.');
ipcRenderer.send('reload-main');
this.$reloadServerButton.classList.remove('hidden');
});
}
initNewServerForm() {
const newServerFormTemplate = `
<div class="server-info active hidden">
<div class="server-info-left">
<img class="server-info-icon" src="https://chat.zulip.org/static/images/logo/zulip-icon-128x128.271d0f6a0ca2.png"/>
</div>
<div class="server-info-right">
<div class="server-info-row">
<span class="server-info-key">Name</span>
<input id="server-info-name" class="server-info-value" placeholder="(Required)"/>
</div>
<div class="server-info-row">
<span class="server-info-key">Url</span>
<input id="server-info-url" spellcheck="false" class="server-info-value" placeholder="(Required)"/>
</div>
<div class="server-info-row">
<span class="server-info-key">Icon</span>
<input id="server-info-icon" class="server-info-value" placeholder="(Optional)"/>
</div>
</div>
</div>
`;
this.$serverInfoContainer.appendChild(this.insertNode(newServerFormTemplate));
this.$newServerForm = document.querySelector('.server-info.active');
this.$newServerAlias = this.$newServerForm.querySelectorAll('input.server-info-value')[0];
this.$newServerUrl = this.$newServerForm.querySelectorAll('input.server-info-value')[1];
this.$newServerIcon = this.$newServerForm.querySelectorAll('input.server-info-value')[2];
}
initActions() {
this.$newServerButton.addEventListener('click', () => {
this.$newServerForm.classList.remove('hidden');
this.$saveServerButton.classList.remove('hidden');
this.$newServerButton.classList.add('hidden');
});
this.$saveServerButton.addEventListener('click', () => {
DomainUtil.checkDomain(this.$newServerUrl.value).then(domain => {
const server = {
alias: this.$newServerAlias.value,
url: domain,
icon: this.$newServerIcon.value
};
DomainUtil.addDomain(server);
this.$saveServerButton.classList.add('hidden');
this.$newServerButton.classList.remove('hidden');
this.$newServerForm.classList.add('hidden');
this.initServers();
// alert('Success. Reload to apply changes.');
ipcRenderer.send('reload-main');
this.$reloadServerButton.classList.remove('hidden');
}, errorMessage => {
alert(errorMessage);
});
});
this.$reloadServerButton.addEventListener('click', () => {
ipcRenderer.send('reload-main');
});
}
insertNode(html) {
const wrapper = document.createElement('div');
wrapper.innerHTML = html;
return wrapper.firstElementChild;
}
}
window.onload = () => {
const preferenceView = new PreferenceView();
preferenceView.init();
};

View File

@@ -1,48 +0,0 @@
'use strict';
// eslint-disable-next-line import/no-extraneous-dependencies
const {remote} = require('electron');
const prefWindow = remote.getCurrentWindow();
document.getElementById('close-button').addEventListener('click', () => {
prefWindow.close();
});
document.addEventListener('keydown', event => {
if (event.key === 'Escape' || event.keyCode === 27) {
prefWindow.close();
}
});
// eslint-disable-next-line no-unused-vars
function addDomain() {
const request = require('request');
// eslint-disable-next-line import/no-extraneous-dependencies
const ipcRenderer = require('electron').ipcRenderer;
const JsonDB = require('node-json-db');
// eslint-disable-next-line import/no-extraneous-dependencies
const {app} = require('electron').remote;
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;
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('pic').style.display = 'none';
document.getElementById('main').innerHTML = 'Switch';
document.getElementById('urladded').innerHTML = 'Switched to ' + newDomain;
db.push('/domain', domain);
ipcRenderer.send('new-domain', domain);
} else {
document.getElementById('pic').style.display = 'none';
document.getElementById('main').innerHTML = 'Switch';
document.getElementById('urladded').innerHTML = 'Not a vaild Zulip Server.';
}
});
}

View File

@@ -0,0 +1,39 @@
'use strict';
const {ipcRenderer} = require('electron');
const {spellChecker} = require('./spellchecker');
const logout = () => {
// 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();
};
const 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();
}
};
process.once('loaded', () => {
global.logout = logout;
global.shortcut = shortcut;
});
// To prevent failing this script on linux we need to load it after the document loaded
document.addEventListener('DOMContentLoaded', () => {
// Init spellchecker
spellChecker();
// redirect users to network troubleshooting page
document.querySelector('.restart_get_events_button').addEventListener('click', () => {
ipcRenderer.send('reload-main');
});
});

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
};

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

@@ -0,0 +1,206 @@
'use strict';
const path = require('path');
const electron = require('electron');
const {ipcRenderer, remote} = electron;
const {Tray, Menu, nativeImage, BrowserWindow} = 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));
});
};
function sendAction(action) {
const win = BrowserWindow.getAllWindows()[0];
if (process.platform === 'darwin') {
win.restore();
}
win.webContents.send(action);
}
const createTray = function () {
window.tray = new Tray(iconPath());
const contextMenu = Menu.buildFromTemplate([{
label: 'About',
click() {
// We need to focus the main window first
ipcRenderer.send('focus-app');
sendAction('open-about');
}
},
{
type: 'separator'
},
{
label: 'Focus',
click() {
ipcRenderer.send('focus-app');
}
},
{
type: 'separator'
},
{
label: 'Manage Zulip servers',
click() {
ipcRenderer.send('focus-app');
sendAction('open-settings');
}
},
{
type: 'separator'
},
{
label: 'Quit',
click() {
ipcRenderer.send('quit-app');
}
}
]);
window.tray.setContextMenu(contextMenu);
window.tray.on('click', () => {
// Click event only works on Windows
if (process.platform === 'win32') {
ipcRenderer.send('toggle-app');
}
});
};
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

@@ -0,0 +1,82 @@
'use strict';
const {app} = require('electron').remote;
const JsonDB = require('node-json-db');
const request = require('request');
let instance = null;
const defaultIconUrl = __dirname + '../../../img/icon.png';
class DomainUtil {
constructor() {
if (instance) {
return instance;
} else {
instance = this;
}
this.db = new JsonDB(app.getPath('userData') + '/domain.json', true, true);
// Migrate from old schema
if (this.db.getData('/').domain) {
this.addDomain({
alias: 'Zulip',
url: this.db.getData('/domain')
});
this.db.delete('/domain');
}
return instance;
}
getDomains() {
if (this.db.getData('/').domains === undefined) {
return [];
} else {
return this.db.getData('/domains');
}
}
getDomain(index) {
return this.db.getData(`/domains[${index}]`);
}
addDomain(server) {
server.icon = server.icon || defaultIconUrl;
this.db.push('/domains[]', server, true);
}
removeDomains() {
this.db.delete('/domains');
}
removeDomain(index) {
this.db.delete(`/domains[${index}]`);
}
checkDomain(domain) {
const hasPrefix = (domain.indexOf('http') === 0);
if (!hasPrefix) {
domain = (domain.indexOf('localhost:') >= 0) ? `http://${domain}` : `https://${domain}`;
}
const checkDomain = domain + '/static/audio/zulip.ogg';
return new Promise((resolve, reject) => {
request(checkDomain, (error, response) => {
if (!error && response.statusCode !== 404) {
resolve(domain);
} else if (error.toString().indexOf('Error: self signed certificate') >= 0) {
if (window.confirm(`Do you trust certificate from ${domain}?`)) {
resolve(domain);
} else {
reject('Untrusted Certificate.');
}
} else {
reject('Not a valid Zulip server');
}
});
});
}
}
module.exports = new DomainUtil();

View File

@@ -0,0 +1,29 @@
'use strict';
const wurl = require('wurl');
let instance = null;
class LinkUtil {
constructor() {
if (instance) {
return instance;
} else {
instance = this;
}
return instance;
}
isInternal(currentUrl, newUrl) {
const currentDomain = wurl('hostname', currentUrl);
const newDomain = wurl('hostname', newUrl);
const skipImages = '.jpg|.gif|.png|.jpeg|.JPG|.PNG';
// We'll be needing this to open images in default browser
return (currentDomain === newDomain) && !newUrl.match(skipImages);
}
}
module.exports = new LinkUtil();

View File

@@ -0,0 +1,55 @@
'use strict';
const {app} = require('electron').remote;
const os = require('os');
let instance = null;
class SystemUtil {
constructor() {
if (instance) {
return instance;
} else {
instance = this;
}
this.connectivityERR = [
'ERR_INTERNET_DISCONNECTED',
'ERR_PROXY_CONNECTION_FAILED',
'ERR_CONNECTION_RESET',
'ERR_NOT_CONNECTED',
'ERR_NAME_NOT_RESOLVED',
'ERR_NETWORK_CHANGED'
];
this.userAgent = null;
return instance;
}
getOS() {
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';
}
}
}
setUserAgent(webViewUserAgent) {
this.userAgent = 'ZulipElectron/' + app.getVersion() + ' ' + webViewUserAgent;
}
getUserAgent() {
return this.userAgent;
}
}
module.exports = new SystemUtil();

28
app/renderer/main.html Normal file
View File

@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html lang="en" class="responsive desktop">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width">
<title>Zulip</title>
<link rel="stylesheet" href="css/main.css" type="text/css" media="screen">
</head>
<body>
<div id="content">
<div id="sidebar">
<div id="tabs-container"></div>
<div id="actions-container">
<div class="action-button" id="reload-action">
<i class="material-icons md-48">refresh</i>
</div>
<div class="action-button" id="add-action">
<i class="material-icons md-48">add_circle</i>
</div>
<div class="action-button" id="settings-action">
<i class="material-icons md-48">settings</i>
</div>
</div>
</div>
</div>
</body>
<script src="js/main.js"></script>
</html>

21
app/renderer/network.html Normal file
View File

@@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="en" class="responsive desktop">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width">
<title>Zulip - Network Troubleshooting</title>
<link rel="stylesheet" href="css/network.css" type="text/css" media="screen">
</head>
<body>
<div id="content">
<div id="picture"><img src="img/zulip_network.png"></div>
<div id="title">Zulip can't connect</div>
<div id="description">
<div>Your computer seems to be offline.</div>
<div>We will keep trying to reconnect, or you can try now.</div>
</div>
<div id="reconnect">Try now</div>
</div>
</body>
<script src="js/pages/network.js"></script>
</html>

View File

@@ -1,22 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="css/pref.css">
<script type="text/javascript">
</script>
</head>
<body>
<div class="close" id="close-button">Close</div>
<div class="form">
<form onsubmit="addDomain(); return false">
<input id="url" type="text" placeholder="chat.zulip.org">
<button type="submit" id="main" value="Submit" onclick="addDomain();">
Switch</button>
<img id="pic" src="img/loader.gif" />
</form>
<p id="urladded"><p>
</div>
<script src="js/pref.js"></script>
</body>
</html>

View File

@@ -0,0 +1,44 @@
<!DOCTYPE html>
<html lang="en" class="responsive desktop">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width">
<title>Zulip - Settings</title>
<link rel="stylesheet" href="css/preference.css" type="text/css" media="screen">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body>
<div id="content">
<div id="sidebar">
<div id="settings-header">Settings</div>
<div id="tabs-container">
<div class="tab" id="general-settings">General</div>
<div class="tab active" id="server-settings">Servers</div>
<div class="tab" id="about-settings">About</div>
</div>
</div>
<div id="settings-container">
<div class="settings-pane" id="server-settings-pane">
<div class="title">Manage Servers</div>
<div class="actions-container">
<div class="action" id="new-server-action">
<i class="material-icons">add_box</i>
<span>New Server</span>
</div>
<div class="action hidden" id="save-server-action">
<button class="save-server-button">Save</button>
</div>
<div class="action hidden" id="reload-server-action">
<i class="material-icons">refresh</i>
<span>Reload to Apply Changes</span>
</div>
</div>
<div class="server-info-container">
</div>
</div>
</div>
</div>
</body>
<script src="js/pages/preference.js"></script>
</html>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.files.downloads.read-write</key>
<true/>
</dict>
</plist>

56
development.md Normal file
View File

@@ -0,0 +1,56 @@
# Development guide
## Prerequisites
* [Git](http://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
* [Node.js](https://nodejs.org) >= v6.9.0
* [python](https://www.python.org/downloads/release/python-2713/) (v2.7.x recommended)
* [node-gyp](https://github.com/nodejs/node-gyp#installation)
## System specific dependencies
### Linux
Install following packages:
```sh
$ sudo apt-get install build-essential libxext-dev libxtst-dev libxkbfile-dev
```
## Installation
Clone the source locally:
```sh
$ git clone https://github.com/zulip/zulip-electron
$ cd zulip-electron
```
Install project dependencies:
```sh
$ npm install
```
Start the app:
```sh
$ npm start
```
Start and watch changes
```sh
$ npm run dev
```
### Making a release
To package app into an installer use command:
```
npm run dist
```
It will start the packaging process for the operating system you are running this command on. The ready for distribution file (e.g. dmg, windows installer, deb package) will be outputted to the `dist` directory.
You can create a Windows installer only when running on Windows and similarly for Linux and OSX. So, to generate all three installers, you will need all three operating systems.
# Troubleshooting
If you have any problems running the app please see the [most common issues](./troubleshooting.md).

View File

@@ -1,11 +1,12 @@
{
"name": "zulip",
"productName": "Zulip",
"version": "0.5.3",
"version": "1.1.0-beta",
"main": "./app/main",
"description": "Zulip Desktop App",
"license": "Apache-2.0",
"email":"<svnitakash@gmail.com>",
"copyright": "©2016 Kandra Labs, Inc.",
"email": "<svnitakash@gmail.com>",
"copyright": "©2017 Kandra Labs, Inc.",
"author": {
"name": "Akash Nimare",
"email": "svnitakash@gmail.com"
@@ -18,36 +19,41 @@
"url": "https://github.com/zulip/zulip-electron/issues"
},
"scripts": {
"start": "electron ./app/main",
"start": "electron app --disable-http-cache",
"postinstall": "install-app-deps",
"test": "gulp test && xo",
"test": "xo",
"dev": "gulp dev",
"pack": "build --dir",
"dist": "build",
"mas": "build --mac mas",
"build:win": "build --win nsis-web --ia32 --x64",
"travis": "cd ./scripts && ./travis-build-test.sh"
},
"build": {
"appId": "org.zulip.zulip-electron",
"asar": "true",
"asar": true,
"files": [
"**/*",
"!node_modules/@paulcbetts/cld/deps/cld${/*}"
],
"copyright": "©2016 Kandra Labs, Inc.",
"copyright": "©2017 Kandra Labs, Inc.",
"mac": {
"category": "public.app-category.productivity"
},
"linux" : {
"synopsis": "Zulip Desktop App",
"linux": {
"category": "",
"packageCategory": "GNOME;GTK;Network;InstantMessaging",
"description": "Zulip Desktop Client for Linux",
"target" : ["deb", "AppImage"],
"version" : "0.5.3",
"title" : "Zulip",
"license": "Apache-2.0",
"target": [
"deb",
"zip",
"AppImage"
],
"maintainer": "Akash Nimare <svnitakash@gmail.com>"
},
"deb": {
"synopsis": "Zulip Desktop App"
},
"dmg": {
"background": "build/appdmg.png",
"icon": "build/icon.icns",
@@ -67,43 +73,60 @@
]
},
"win": {
"target": "squirrel",
"target": "nsis",
"icon": "build/icon.ico"
},
"nsis": {
"perMachine": true,
"oneClick": false
}
},
"keywords": [
"Zulip",
"Group Chat app",
"electron-app",
"electron",
"Desktop app",
"InstantMessaging"
"Zulip",
"Group Chat app",
"electron-app",
"electron",
"Desktop app",
"InstantMessaging"
],
"devDependencies": {
"assert": "^1.4.1",
"devtron": "^1.1.0",
"electron-builder": "*",
"electron": "1.4.7",
"electron-connect": "^0.4.6",
"gulp": "^3.9.1",
"gulp-mocha": "^3.0.1",
"spectron": "^3.3.0",
"xo": "*"
"assert": "1.4.1",
"devtron": "1.4.0",
"electron-builder": "17.10.0",
"electron": "1.6.8",
"electron-connect": "0.4.8",
"gulp": "3.9.1",
"gulp-mocha": "3.0.1",
"chai-as-promised": "6.0.0",
"chai": "^3.5.0",
"spectron": "3.6.4",
"xo": "0.18.1"
},
"xo": {
"parserOptions": {
"sourceType": "script",
"ecmaFeatures": {
"globalReturn": true
}
},
"esnext": true,
"overrides": [
{
"files": "app/main/*.js",
"files": "app*/**/*.js",
"rules": {
"max-lines": [
"warn",
350
500
],
"no-warning-comments": 0,
"capitalized-comments": 0,
"no-else-return": 0,
"no-path-concat": 0,
"no-alert": 0,
"guard-for-in": 0,
"prefer-promise-reject-errors": 0,
"import/no-unresolved": 0,
"import/no-extraneous-dependencies":0
"import/no-extraneous-dependencies": 0
}
}
],
@@ -116,4 +139,4 @@
"mocha"
]
}
}
}

View File

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

View File

@@ -1,5 +1,11 @@
const assert = require('assert')
const Application = require('spectron').Application
const chai = require('chai')
const { expect } = chai
const chaiAsPromised = require('chai-as-promised')
chai.should()
chai.use(chaiAsPromised)
describe('application launch', function () {
this.timeout(15000)
@@ -7,11 +13,15 @@ describe('application launch', function () {
beforeEach(function () {
this.app = new Application({
path: require('electron'),
args: [__dirname + '/../app/main/index.js']
args: [__dirname + '/../app/renderer/main.html']
})
return this.app.start()
})
beforeEach(function () {
chaiAsPromised.transferPromiseness = this.app.transferPromiseness
})
afterEach(function () {
if (this.app && this.app.isRunning()) {
return this.app.stop()
@@ -19,9 +29,53 @@ describe('application launch', function () {
})
it('shows an initial window', function () {
return this.app.client.getWindowCount().then(function (count) {
assert.equal(count, 1)
})
return this.app.client.waitUntilWindowLoaded(5000)
.getWindowCount().should.eventually.equal(2)
.browserWindow.isMinimized().should.eventually.be.false
.browserWindow.isDevToolsOpened().should.eventually.be.false
.browserWindow.isVisible().should.eventually.be.true
.browserWindow.isFocused().should.eventually.be.true
.browserWindow.getBounds().should.eventually.have.property('width').and.be.above(0)
.browserWindow.getBounds().should.eventually.have.property('height').and.be.above(0)
})
it('sets up a default organization', function () {
let app = this.app
let self = this
app.client.execute(() => {
window.confirm = function () { return true }
})
function createOrg (client, name, url, winIndex) {
return client
// Focus on settings webview
.then(switchToWebviewAtIndex.bind(null, self.app.client, winIndex))
.pause(1000) // wait for settings to load
// Fill settings form
.click('#new-server-action')
.setValue('input[id="server-info-name"]', name)
.setValue('input[id="server-info-url"]', url)
.click('#save-server-action')
.pause(500) // Need to pause while server verification takes place
.then(() => app.browserWindow.reload())
.pause(1500) // Wait for webview of org to load
}
function switchToWebviewAtIndex(client, index) {
return client
.windowHandles()
.then(function (session) {
this.window(session.value[index])
})
}
return this.app.client.waitUntilWindowLoaded(5000)
.then(() => createOrg(self.app.client, 'Zulip 1', 'chat.zulip.org', 1))
.then(switchToWebviewAtIndex.bind(null, self.app.client, 0))
.click('#add-action > i').pause(500)
.then(switchToWebviewAtIndex.bind(null, self.app.client, 2))
.then(() => createOrg(self.app.client, 'Zulip 2', 'chat.zulip.org', 2))
})
})

5
troubleshooting.md Normal file
View File

@@ -0,0 +1,5 @@
# Troubleshooting
* App icon will only show in the release version. The dev version will use the Electron icon
* If you see issue, try deleting `node_modules` and `npm install`
* Electron is more or less Chrome, you can get developer tools using `CMD+ALT+I`

View File

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