├── .eslintrc ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md ├── LICENSE.md ├── README.md ├── README_zh.md ├── assets ├── icon.icns ├── icon.png ├── loading.gif ├── status_bar.png ├── status_bar@2x.png ├── tray_black.png ├── tray_unread_black.png ├── tray_unread_white.png └── tray_white.png ├── config.json ├── package.json ├── scripts ├── build-all.sh ├── build-win32.bat ├── build.sh ├── qiniu.sh └── tar-all.sh └── src ├── common.js ├── common_cn.js ├── configuration.js ├── handlers ├── menu.js ├── message.js └── update.js ├── inject ├── badge_count.js ├── css.js ├── emoji_parser.js ├── mention_menu.js ├── preload.js └── share_menu.js ├── main.js └── windows ├── controllers ├── app_tray.js ├── settings.js ├── splash.js └── wechat.js ├── styles ├── settings.css └── splash.css └── views ├── settings.html └── splash.html /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": "airbnb/base", 4 | "rules": { 5 | "strict": "off", 6 | "max-len": "off", 7 | "prefer-template": "warn", 8 | "arrow-body-style": "off", 9 | "no-unused-vars": "warn", 10 | "no-undef": "off", 11 | "array-callback-return": "off", 12 | "no-confusing-arrow": "off", 13 | "consistent-return": "warn", 14 | "no-param-reassign": "off", 15 | "default-case": "off", 16 | "guard-for-in": "off", 17 | "no-restricted-syntax": "off", 18 | "no-underscore-dangle": "off", 19 | "new-cap": "warn", 20 | "no-console": "off", 21 | "global-require": "off", 22 | "class-methods-use-this": "warn" 23 | }, 24 | } 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /dist 3 | npm-debug.log* 4 | .idea 5 | 6 | # Dependency directories 7 | node_modules 8 | 9 | *.sublime-project 10 | *.sublime-workspace 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | sudo: required 3 | node_js: 4 | - '5.2' 5 | branches: 6 | only: 7 | - master 8 | - production 9 | before_script: 10 | - npm install 11 | script: 12 | - ./scripts/build-all.sh 13 | - ./scripts/tar-all.sh 14 | deploy: 15 | provider: releases 16 | api_key: 17 | secure: ETudcaMBembv5mq5WcA0Zu5YCQt02A8sfMIYJ+XN0dTUCFRODYgyk8SiW3ndI4zLfhsc31KbYecSVfcrvYhPlkLucdhD0hY+v4mowrGaG6q3DUE4v9+qATOE5z51MPNTQO/suPNZpeFkSCKaWh6SY9oSd/tsD+YmbcpuD0//DMiFMpYqA8ueQ7yka4SmlZq8C48MsRbULAtyHNEVNJ4en9xdE9vFHZ45kM2A2IWYVikuCa5J6YoL7N2CyIFwtKMeF68d0vwidXUXEc7z1VOHwosG7V0vEfNRrIy4mft0tXyEYe/nM8GlYnirVRCy3xF4h4ssERXbLMuZSYGm+bg/pqReL+dvsN5oKszuo7IseZnE8QfmmhfbMB4dWf8Le5WXfFgJTG28lNvl2VwTTEW4Cj5qeJmfO524GydqRE+i3uQvW4c2tBTFmfpusPnaFqVXTPH7o54hT18hYvgaBvJQv6pyMNMLLXq0BbkzquTTWTwb8lSi8XiRr/fWkQreRZNofJc21ZUSI5YcuqZpzbz1fOLseC4QJ8YXQ9b2OU/LiFF3gvHTK6vSKMQmbOFg0zFXMi5FT1SzCi/mKduax/OR/H6lolVW83eXCG1Ni+sIrwUkp0d/UL6E1pVeJMibBrOEgriWIpD+AiVzNVyBdq/oDC6qG9IXRWzii9Ks6J9zH7k= 18 | file: 19 | - 'dist/mac-osx.tar.gz' 20 | - 'dist/linux-x64.tar.gz' 21 | - 'dist/linux-ia32.tar.gz' 22 | skip_cleanup: true 23 | on: 24 | repo: geeeeeeeeek/electronic-wechat 25 | branch: production 26 | notifications: 27 | webhooks: 28 | urls: 29 | - https://webhooks.gitter.im/e/d6bab2376f47ee992d78 30 | on_success: always # options: [always|never|change] default: always 31 | on_failure: always # options: [always|never|change] default: always 32 | on_start: always # options: [always|never|change] default: always 33 | after_deploy: 34 | - ./scripts/qiniu.sh 35 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | **v2.0 (2017.02.13) CN** 4 | 5 | 1. 升级 **Electron** 至 **V1.4.15**,**Chromium** 至 **54** 6 | 2. 增加了**偏好设置**(感谢设计建议 @**[xiaoyusilen](https://github.com/xiaoyusilen)**) 7 | 3. 增加了英文版本的支持 8 | 4. 增加了一键隐藏窗口(**`ESC`** 键) 9 | 5. 修复了 **macOS** 上窗口最小化时不显示新消息提示的红点(感谢 @wujysh 的贡献) 10 | 6. 修复了聊天框内换行提示仅针对 macOS 的问题 11 | 7. 增加了两个快捷键(感谢 @awmleer 的贡献) 12 | - 搜索联系人:**`Ctrl + F`** 13 | - 切换到全屏模式:**macOS** 下 **`Ctrl + Command + F`**,**Linux** 下为 **`F11`** 14 | 8. 修复了在 Linux 系统下部分菜单按钮失效的问题(感谢 @qzchenwl 的贡献) 15 | 8. 更新了依赖的第三方库的版本至最新兼容版本 16 | 17 | **v2.0 (2017.02.13) EN** 18 | 19 | 1. Update Electron to V1.4.15, Chromium API level 54 20 | 2. Add **Preference Panel** (Thanks for the design advises from @**[xiaoyusilen](https://github.com/xiaoyusilen)**](https://github.com/xiaoyusilen)) 21 | 3. Fully support English UI! 22 | 4. Quick hide windows shortcut (**Press `ESC`**) 23 | 5. Fix **macOS** new message red dot display improperly (Thanks to @wujysh) 24 | 6. Tips in chat window now are adapted with platform 25 | 7. Add two shortcuts (Thanks to @awmleer) 26 | - Search Contact人: **`Ctrl + F`** 27 | - Toggle Fullscreen Mode: **macOS** **`Ctrl + Command + F`**, **Linux** **`F11`** 28 | 8. Fix unfunctional menu items on **Linux** (Thanks to @qzchenwl) 29 | 8. All thrid party libraries are up-to-date 30 | 31 | 32 | **v1.3 (2016.05.19)** 33 | 34 | 1. 升级 electron 至 1.1.0, Chrome 至 50.0.2661.102,Node 至 6.1.0 (感谢 @lfs1102 的贡献) 35 | 2. 新增 `brew cask` 安装方式 (最新可下载版本为 v1.2.0) 36 | 3. 新增 Windows 下的安装脚本 (感谢 @3dseals 的贡献) 37 | 4. 新增 应用启动动画,缩短首次展现时间 38 | 5. 优化 应用启动稳定性,增加超时重试 39 | 6. 优化 主要文案均统一为英文 40 | 7. 优化 减少 20M 应用体积 41 | 8. 修复 关于页面版本号显示的 bug 42 | 9. 修复 Linux 系统下左边栏组件重叠的 bug 43 | 10. 修复 部分 Linux KDE 系统下托盘图标空白的 bug 44 | 11. 其他修改 (感谢 @wzyboy, @rivershang, @hexchain, @samurai00, @boltomli 的贡献) 45 | 46 | 47 | **v1.2 (2016.04.21)** 48 | 49 | 1. 新增 更新检测模块,应用内即可检查更新 50 | 2. 新增 公众号文章的第三方分享功能。现支持一键分享到微博、QQ 空间、Facebook、Twitter、Evernote 和邮件 (感谢 @oblank 的贡献) 51 | 3. 新增 群聊 @ 提及成员功能,但收到提醒需要服务端支持 (感谢 @iamcc 的贡献) 52 | 4. 优化 登录界面使用单独的尺寸 (感谢 @xnfa 的贡献) 53 | 5. 优化 修改 OS X 下隐藏其他窗口的快捷键为 `Command+Alt+H` 54 | 6. 优化 Linux 下可执行文件文件名使用小写字母,去除空格 55 | 7. 优化 Linux 下使用彩色图标 56 | 8. 升级 `electron-prebuilt` 版本至 `0.37.6` , `electron-packager` 版本至 `7.0.0` 57 | 9. ~~降级 Emoji贴纸显示的功能。由于微信协议调整和官方代码缺陷,现有商店内贴纸及部分个人收藏的贴纸无法显示。后续跟进微信的修复进行调整。~~ (Update: 微信已修复,贴纸均可正常显示) 58 | 59 | 60 | **v1.1 (2016.03.17)** 61 | 62 | 1. 新增 OS X 和 Linux 下的托盘菜单,点击可进入应用、退出应用 (仅Linux) (感谢 @iamcc 和 @wenLiangcan 的贡献) 63 | 2. 新增 cnpm 镜像提醒 64 | 3. 优化 应用的退出逻辑,Cmd+Q 退出应用,Cmd+W 或点击关闭隐藏应用 65 | 4. 优化 OS X 和 Linux 下的应用菜单显示 66 | 5. 优化 Emoji贴纸的实现方式,避免滑动时内容抖动,无法回到底部 67 | 6. 优化 接管应用刷新的逻辑,Cmd+R 重新加载页面 68 | 7. 优化 OS X 下 build 后将应用拷贝到 Application 文件夹 69 | 8. 优化 Linux 下使用 Ctrl+Shift+I 打开开发者工具 (感谢 @wenLiangcan 的贡献) 70 | 9. 修复 错误的微信站内重定向 (感谢 @gucheen 的贡献) 71 | 10. 修复 Linux 下应用图标的显示 72 | 11. 修复 聊天列表滑动性能问题 73 | 12. 修复 公众号新窗口打开报错 (感谢 @gzzhanghao 的贡献) 74 | 75 | **v1.0 (2016.03.01)** 76 | 77 | 1. 新增 阻止消息撤回的功能 (感谢 @arrowrowe 的贡献) 78 | 2. 新增 引入了 Travis CI 和 Gitter.im 79 | 3. 优化 贴纸显示的实现方式 (感谢 @arrowrowe 的贡献) 80 | 4. 优化 build 脚本 (感谢 @gaocegege, @viko16 和 @htc550605125 的贡献) 81 | 5. 优化 Linux 下自动隐藏菜单 (感谢 @wenLiangcan 的贡献) 82 | 6. 优化 Linux 下用户头像的显示 83 | 7. 优化 禁用缩放、选中文本、默认光标 84 | 85 | **v0.1 (2016.02.19)** 86 | 87 | 1. Create the project. 88 | 2. Auto resize web content. 89 | 3. Drag to send pictures. 90 | 4. Open inhibited links without additional redirect. 91 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Electronic WeChat 2 | 3 | First of all, thanks for contributing to this project. It would be appreciated if you read through this contributing guide. 4 | 5 | ## Issues 6 | 7 | - Check if your issue is already [there](https://github.com/geeeeeeeeek/electronic-wechat/issues). 8 | 9 | - Check if your issue is `Electronic WeChat` related rather than upstream related. 10 | 11 | - Follow the guide in the issue template. 12 | 13 | ## Pull Requests 14 | 15 | PR are always welcomed. It's better if you put up an issue before firing a PR. **Remember**, the smaller your focus, the better chance to get merged. 16 | 17 | ## Be a collaborator! 18 | 19 | If you are excited about the project, and happen to have skills in Angular, Node, Electron, or else. Do not hesitate to contact me. Let's build together! 20 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | #### Description 2 | 3 | First of all, thanks for your attention to open an issue for this project. 4 | Please notice that if you are requesting a **feature**, then you should give a **brief description** of your request. 5 | If you are reporting a **bug**, please **follow the template** below. 6 | A bug report **without detailed information** required will have a **very low priority** and even be **ignored** (closed directly)! 7 | 8 | #### Specifications 9 | 10 | - Version of Electron (run `$ electron --version`): `v0.0.0` 11 | - OS: `` 12 | - Stack trace from the error message (if any) 13 | 14 | ``` 15 | 16 | ``` 17 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Zhongyi Tong 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | logo 2 | 3 | # Electronic WeChat 4 | 5 | *A better WeChat on macOS and Linux. Built with [Electron](https://github.com/atom/electron).* 6 | 7 | > **⚠️⚠️ NO LONGER IN ACTIVE DEVELOPMENT | 项目不再维护 ⚠️⚠️** 8 | > 9 | > Thanks for supporting this project for **1000** days since Feb 16, 2016. 10 | > 11 | > It started with the idea to make WeChat better on MacOS when the official support was abscent. It was de facto dead when Tencent rolled out a new WeChat and started to block other third-party clients. For me, it's no longer worthwhile to hack a lot to accomplish little. Hope this project had been helpful to you in any way. You're welcome to fork or make copies with a reference. HAPPY HACKING. 12 | > 13 | > 感谢历史上的用户和贡献者,你们已经陪伴这个项目走过了 **1000** 个日子。我曾经想要打造一个更好的 Mac 微信客户端,因为官方版本几年没有更新、bug 层出。而在腾讯自己开始了定期更新并限制第三方客户端时,这个项目实际已经没有什么意义。这个项目目前作为一个存档供大家学习。希望它曾经对你有所帮助,你也可以 fork 或者转载(标注来源)来进行修改。祝你玩得愉快。 14 | > 15 | > **SPECIAL THANKS TO | 特别感谢** 16 | > 17 | > [Kulbear](https://github.com/Kulbear), 18 | > [arrowrowe](https://github.com/arrowrowe), 19 | > [Rocka](https://github.com/rocka), 20 | > [CC](https://github.com/iamcc), 21 | > [xgdgsc](https://github.com/xgdgsc), 22 | > [死水微澜](https://github.com/ripples-alive), 23 | > [Jason](https://github.com/gzzhanghao), 24 | > [Ce Gao](https://github.com/gaocegege), 25 | > [viko16](https://github.com/viko16), 26 | > [卡晨](https://github.com/awmleer), 27 | > [Ray](https://github.com/ray26), 28 | > [尹良灿](https://github.com/wenLiangcan), 29 | > [gehuangyi20](https://github.com/gehuangyi20), 30 | > [Kevin Tan](https://github.com/stkevintan), 31 | > [Jiaye Wu](https://github.com/wujysh), 32 | > [loufq](https://github.com/loufq), 33 | > [Miaow](https://github.com/miaowing), 34 | > [Chuan Ji](https://github.com/jichu4n), 35 | > [Oaker](https://github.com/cyio), 36 | > [Fengshuang Li](https://github.com/lfs1102), 37 | > [Song Li](https://github.com/boltomli), 38 | > [afon](https://github.com/samurai00), 39 | > [lional wang](https://github.com/3dseals), 40 | > [Haochen Tong](https://github.com/hexchain), 41 | > [Zhuoyun Wei](https://github.com/wzyboy), 42 | > [rivershang](https://github.com/rivershang), 43 | > [Ivan Jiang](https://github.com/iplus26), 44 | > [oBlank](https://github.com/oblank), 45 | > [Cheng Gu](https://github.com/gucheen), 46 | > [NullMDR](https://github.com/NullMDR), 47 | > [ReadmeCritic](https://github.com/ReadmeCritic). 48 | --- 49 | 50 | **Important:** If you want to build the app by yourself rather than download the release directly, please consider to use the source code from [the production branch](https://github.com/geeeeeeeeek/electronic-wechat/tree/production), the master branch is under development and we cannot guarantee it to be stable. 51 | 52 | [![Gitter](https://badges.gitter.im/geeeeeeeeek/electronic-wechat.svg)](https://gitter.im/geeeeeeeeek/electronic-wechat?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge) 53 | [![Build Status](https://travis-ci.org/geeeeeeeeek/electronic-wechat.svg?branch=master)](https://travis-ci.org/geeeeeeeeek/electronic-wechat) 54 | [![Build Status](https://img.shields.io/github/stars/geeeeeeeeek/electronic-wechat.svg)](https://github.com/geeeeeeeeek/electronic-wechat) 55 | [![Build Status](https://img.shields.io/github/forks/geeeeeeeeek/electronic-wechat.svg)](https://github.com/geeeeeeeeek/electronic-wechat) 56 | [![Build Status](https://img.shields.io/badge/README-切换语言-yellow.svg)](README_zh.md) 57 | 58 | ![qq20160428-0 2x](https://cloud.githubusercontent.com/assets/7262715/14876747/ff691ade-0d49-11e6-8435-cb1fac91b3c2.png) 59 | 60 | ## Features ([CHANGELOG](CHANGELOG.md)) 61 | 62 | - **Modern UI and all features from Web WeChat.** 63 | - **Block message recall.** 64 | - **Stickers showing support.** [[?]](https://github.com/geeeeeeeeek/electronic-wechat/issues/2) 65 | - Share subscribed passages on Weibo, Qzone, Facebook, Twitter, Evernote, and email. 66 | - Mention users in a group chat. 67 | - Drag and drop to send photos. 68 | - Behaves like a native app, based on dozens of optimization. 69 | - Removes URL link redirects and takes you directly to blocked websites (e.g. taobao.com). 70 | 71 | ## How To Use 72 | 73 | To clone and run this repository you'll need [Git](https://git-scm.com) and [Node.js](https://nodejs.org/en/download/) (which comes with [npm](https://www.npmjs.com/)) installed on your computer. From your command line: 74 | 75 | ``` bash 76 | # Clone this repository 77 | git clone https://github.com/geeeeeeeeek/electronic-wechat.git 78 | # Go into the repository 79 | cd electronic-wechat 80 | # Install dependencies and run the app 81 | npm install && npm start 82 | ``` 83 | 84 | To pack into an app, simply type one of these: 85 | 86 | ``` shell 87 | npm run build:osx 88 | npm run build:linux 89 | npm run build:win32 90 | npm run build:win64 91 | ``` 92 | 93 | **New:** Install with your familiar package manager. Check out [images maintained by the community](https://github.com/geeeeeeeeek/electronic-wechat/wiki/System-Support-Matrix#%E7%A4%BE%E5%8C%BA%E8%B4%A1%E7%8C%AE%E7%9A%84%E5%AE%89%E8%A3%85%E5%8C%85)! 94 | 95 | **New:** Or, with homebrew! 96 | 97 | ```bash 98 | brew cask install electronic-wechat 99 | ``` 100 | 101 | #### [Download Released App](https://github.com/geeeeeeeeek/electronic-wechat/releases) 102 | 103 | #### License [MIT](LICENSE.md) 104 | 105 | *Electronic WeChat* is released by this open source project. While Web WeChat is a major component in the app, it should be noted that this is a community release and not an official WeChat release. 106 | -------------------------------------------------------------------------------- /README_zh.md: -------------------------------------------------------------------------------- 1 | logo 2 | 3 | # Electronic WeChat 4 | 5 | [![Gitter](https://badges.gitter.im/geeeeeeeeek/electronic-wechat.svg)](https://gitter.im/geeeeeeeeek/electronic-wechat?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge) [![Build Status](https://travis-ci.org/geeeeeeeeek/electronic-wechat.svg?branch=master)](https://travis-ci.org/geeeeeeeeek/electronic-wechat) [English](README.md) 6 | 7 | **Mac OS X 和 Linux 下更好用的微信客户端. 更多功能, 更少bug. 使用[Electron](https://github.com/atom/electron)构建.** 8 | 9 | **Important:** 如果你希望在自己的电脑上构建 Electronic WeChat,请使用 [production branch](https://github.com/geeeeeeeeek/electronic-wechat/tree/production),master branch 包含正在开发的部分,并且不能保证是稳定的版本——尽管 production 版本也有bug :D 10 | 11 | ![qq20160428-0 2x](https://cloud.githubusercontent.com/assets/7262715/14876747/ff691ade-0d49-11e6-8435-cb1fac91b3c2.png) 12 | 13 | ## 应用特性 ([更新日志](CHANGELOG.md)) 14 | 15 | - **来自网页版微信的更现代的界面和更丰富的功能** 16 | - **阻止消息撤回** 17 | - **显示表情贴纸** [[?]](https://github.com/geeeeeeeeek/electronic-wechat/issues/2) 18 | - 公众号文章支持一键分享到微博、QQ 空间、Facebook、Twitter、Evernote 和邮件 19 | - 拖入图片、文件即可发送 20 | - 群聊 @ 提及成员 21 | - 原生应用体验,未读消息小红点、消息通知等数十项优化 22 | - 去除外链重定向,直接打开淘宝等网站 23 | - 没有原生客户端万年不修复的bug 24 | 25 | ## 如何使用 26 | 27 | 在下载和运行这个项目之前,你需要在电脑上安装 [Git](https://git-scm.com) 和 [Node.js](https://nodejs.org/en/download/) (来自 [npm](https://www.npmjs.com/))。在命令行中输入: 28 | 29 | ``` bash 30 | # 下载仓库 31 | git clone https://github.com/geeeeeeeeek/electronic-wechat.git 32 | # 进入仓库 33 | cd electronic-wechat 34 | # 安装依赖, 运行应用 35 | npm install && npm start 36 | ``` 37 | 38 | 根据你的平台打包应用: 39 | 40 | ``` shell 41 | npm run build:osx 42 | npm run build:linux 43 | npm run build:win 44 | ``` 45 | 46 | **提示:** 如果 `npm install` 下载缓慢,你可以使用 [淘宝镜像(cnpm)](http://npm.taobao.org/) 替代 npm 。 47 | 48 | **新渠道:** 使用你熟悉的包管理工具安装。请查看 [社区贡献的镜像](https://github.com/geeeeeeeeek/electronic-wechat/wiki/System-Support-Matrix#%E7%A4%BE%E5%8C%BA%E8%B4%A1%E7%8C%AE%E7%9A%84%E5%AE%89%E8%A3%85%E5%8C%85) 。 49 | 50 | **新渠道:** homebrew 安装也已支持 (更新至 electronic-wechat v1.2.0)! 51 | 52 | ```bash 53 | brew cask install electronic-wechat 54 | ``` 55 | 56 | #### [下载开箱即用的稳定版应用](https://github.com/geeeeeeeeek/electronic-wechat/releases) 57 | 58 | #### 项目使用 [MIT](LICENSE.md) 许可 59 | 60 | *Electronic WeChat* 是这个开源项目发布的产品。网页版微信是其中重要的一部分,但请注意这是一个社区发布的产品,而 *不是* 官方微信团队发布的产品。 61 | -------------------------------------------------------------------------------- /assets/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geeeeeeeeek/electronic-wechat/dc50c871d9b5928234fdf91350ad5a90717804f3/assets/icon.icns -------------------------------------------------------------------------------- /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geeeeeeeeek/electronic-wechat/dc50c871d9b5928234fdf91350ad5a90717804f3/assets/icon.png -------------------------------------------------------------------------------- /assets/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geeeeeeeeek/electronic-wechat/dc50c871d9b5928234fdf91350ad5a90717804f3/assets/loading.gif -------------------------------------------------------------------------------- /assets/status_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geeeeeeeeek/electronic-wechat/dc50c871d9b5928234fdf91350ad5a90717804f3/assets/status_bar.png -------------------------------------------------------------------------------- /assets/status_bar@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geeeeeeeeek/electronic-wechat/dc50c871d9b5928234fdf91350ad5a90717804f3/assets/status_bar@2x.png -------------------------------------------------------------------------------- /assets/tray_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geeeeeeeeek/electronic-wechat/dc50c871d9b5928234fdf91350ad5a90717804f3/assets/tray_black.png -------------------------------------------------------------------------------- /assets/tray_unread_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geeeeeeeeek/electronic-wechat/dc50c871d9b5928234fdf91350ad5a90717804f3/assets/tray_unread_black.png -------------------------------------------------------------------------------- /assets/tray_unread_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geeeeeeeeek/electronic-wechat/dc50c871d9b5928234fdf91350ad5a90717804f3/assets/tray_unread_white.png -------------------------------------------------------------------------------- /assets/tray_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geeeeeeeeek/electronic-wechat/dc50c871d9b5928234fdf91350ad5a90717804f3/assets/tray_white.png -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "osx" : { 3 | "title": "Electronic Wechat", 4 | "background": "icon.png", 5 | "icon": "icon.icns", 6 | "icon-size": 80, 7 | "contents": [ 8 | { "x": 438, "y": 344, "type": "link", "path": "/Applications" }, 9 | { "x": 192, "y": 344, "type": "file" } 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "electronic-wechat", 3 | "version": "2.0.0", 4 | "description": "An Electron application for WeChat", 5 | "main": "src/main.js", 6 | "scripts": { 7 | "start": "electron src/main.js", 8 | "build": "./scripts/build-all.sh", 9 | "build:osx": "./scripts/build.sh darwin x64", 10 | "build:osx64": "./scripts/build.sh darwin x64", 11 | "build:linux32": "./scripts/build.sh linux ia32", 12 | "build:linux": "./scripts/build.sh linux x64", 13 | "build:linux64": "./scripts/build.sh linux x64", 14 | "build:win": ".\\scripts\\build-win32.bat win32 ia32", 15 | "build:win32": ".\\scripts\\build-win32.bat win32 ia32", 16 | "build:win64": ".\\scripts\\build-win32.bat win32 x64" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "https://github.com/geeeeeeeeek/wechat-electron.git" 21 | }, 22 | "keywords": [ 23 | "Electron", 24 | "WeChat", 25 | "微信", 26 | "Web" 27 | ], 28 | "author": "Zhongyi Tong", 29 | "license": "MIT", 30 | "bugs": { 31 | "url": "https://github.com/geeeeeeeeek/wechat-electron/issues" 32 | }, 33 | "homepage": "https://github.com/geeeeeeeeek/wechat-electron/", 34 | "dependencies": { 35 | "electron": "1.4.15", 36 | "electron-packager": "^8.5.1", 37 | "nconf": "^0.8.4", 38 | "pinyin": "^2.8.0", 39 | "emojione": "^2.2.7", 40 | "electron-localshortcut": "1.1.0", 41 | "is-xfce": "^1.0.2" 42 | }, 43 | "devDependencies": { 44 | "babel-eslint": "^7.1.1", 45 | "eslint": "^3.15.0", 46 | "eslint-config-airbnb": "^14.1.0", 47 | "eslint-plugin-import": "^2.2.0", 48 | "eslint-plugin-jsx-a11y": "^4.0.0", 49 | "eslint-plugin-react": "^6.9.0" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /scripts/build-all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if ! hash electron-packager 2>/dev/null; then 4 | RED='\033[0;31m' 5 | NC='\033[0m' 6 | echo "${RED}Error${NC}: you need to npm install electron-packager. Aborting." 7 | exit 1 8 | fi 9 | 10 | function build() { 11 | ./scripts/build.sh $@ 12 | } 13 | 14 | build darwin x64 15 | build linux ia32 16 | build linux x64 17 | #build win32 ia32 18 | -------------------------------------------------------------------------------- /scripts/build-win32.bat: -------------------------------------------------------------------------------- 1 | set PLATFORM=%1% 2 | set ARCH=%2% 3 | set APP_NAME="Electronic WeChat" 4 | 5 | set ignore_list="dist|scripts|\.idea|.*\.md|.*\.yml|node_modules/nodejieba" 6 | 7 | electron-packager . "%APP_NAME%" --platform=%PLATFORM% --arch=%ARCH% --electronVersion=1.4.15 --app-version=1.4.0 --asar --icon=assets\icon.png --overwrite --out=.\dist --ignore=%ignore_list% 8 | -------------------------------------------------------------------------------- /scripts/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if ! hash electron-packager 2>/dev/null; then 4 | RED='\033[0;31m' 5 | NC='\033[0m' 6 | echo "${RED}Error${NC}: you need to npm install electron-packager. Aborting." 7 | exit 1 8 | fi 9 | 10 | if [ "$#" -ne 2 ]; then 11 | echo -e "Usage: ./script/build.sh " 12 | echo -e " platform: darwin, linux, win32" 13 | echo -e " arch: ia32, x64" 14 | exit 1 15 | fi 16 | 17 | PLATFORM=$1 18 | ARCH=$2 19 | 20 | echo "Start packaging for $PLATFORM $ARCH." 21 | 22 | if [ $PLATFORM = "linux" ]; then 23 | APP_NAME="electronic-wechat" 24 | else 25 | APP_NAME="Electronic WeChat" 26 | fi 27 | 28 | ignore_list="dist|scripts|\.idea|.*\.md|.*\.yml|node_modules/nodejieba" 29 | 30 | electron-packager . "${APP_NAME}" --platform=$PLATFORM --arch=$ARCH --electronVersion=1.4.15 --app-version=1.4.0 --asar --icon=assets/icon.icns --overwrite --out=./dist --ignore=${ignore_list} 31 | 32 | if [ $? -eq 0 ]; then 33 | echo -e "$(tput setaf 2)Packaging for $PLATFORM $ARCH succeeded.$(tput sgr0)\n" 34 | fi 35 | 36 | if [ $PLATFORM = "darwin" ]; then 37 | ditto -rsrcFork ./dist/Electronic\ WeChat-darwin-x64/Electronic\ WeChat.app /Applications/Electronic\ WeChat.app 38 | echo "$(tput setaf 3)App copied to /Applications. You can open Electronic WeChat there or from Spotlight.$(tput sgr0)" 39 | fi 40 | -------------------------------------------------------------------------------- /scripts/qiniu.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | case "$(uname -s)" in 4 | 5 | Linux*) 6 | wget http://devtools.qiniu.com/qiniu-devtools-linux_amd64-current.tar.gz -O dist/qiniu-devtools.tar.gz 7 | ;; 8 | 9 | Darwin) 10 | wget http://devtools.qiniu.io/qiniu-devtools-darwin_amd64-current.tar.gz -O dist/qiniu-devtools.tar.gz 11 | ;; 12 | 13 | *) 14 | ;; 15 | 16 | esac 17 | 18 | mkdir dist/qiniu-devtools 19 | tar -xvf dist/qiniu-devtools.tar.gz -C dist/qiniu-devtools 20 | rm -rf /tmp/qiniu 21 | mkdir /tmp/qiniu 22 | cp dist/mac-osx.tar.gz /tmp/qiniu 23 | cp dist/linux-x64.tar.gz /tmp/qiniu 24 | cp dist/linux-ia32.tar.gz /tmp/qiniu 25 | 26 | echo '{ 27 | "src": "/tmp/qiniu", 28 | "dest": "qiniu:access_key='$QINIU_ACCESS_KEY'&secret_key='$QINIU_SECRET_KEY'&bucket=flymeos-cancro", 29 | "debug_level": 1 30 | }' > qiniu-config.json 31 | ./dist/qiniu-devtools/qrsync qiniu-config.json 32 | -------------------------------------------------------------------------------- /scripts/tar-all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd dist 4 | 5 | echo 'Start compressing for Mac OS X.' 6 | tar zcf 'mac-osx.tar.gz' 'Electronic WeChat-darwin-x64' 7 | echo 'Compressing for Mac OS X succeed.' 8 | 9 | echo 'Start compressing for Linux x64.' 10 | tar zcf 'linux-x64.tar.gz' 'electronic-wechat-linux-x64' 11 | echo 'Compressing for Linux x64 succeed.' 12 | 13 | echo 'Start compressing for Linux ia32.' 14 | tar zcf 'linux-ia32.tar.gz' 'electronic-wechat-linux-ia32' 15 | echo 'Compressing for Linux ia32 succeed.' 16 | 17 | cd .. 18 | -------------------------------------------------------------------------------- /src/common.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Zhongyi on 3/26/16. 3 | */ 4 | 5 | 'use strict'; 6 | 7 | class Common { 8 | 9 | } 10 | Common.ELECTRON = 'Electron'; 11 | Common.ELECTRONIC_WECHAT = 'Electronic WeChat'; 12 | Common.DEBUG_MODE = false; 13 | Common.WINDOW_SIZE = { 14 | width: 800, 15 | height: 600, 16 | }; 17 | Common.WINDOW_SIZE_LOGIN = { 18 | width: 380, 19 | height: 540, 20 | }; 21 | Common.WINDOW_SIZE_LOADING = { 22 | width: 380, 23 | height: 120, 24 | }; 25 | Common.WINDOW_SIZE_SETTINGS = { 26 | width: 800, 27 | height: 600, 28 | }; 29 | 30 | Common.USER_AGENT = { 31 | freebsd: 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36', 32 | sunos: 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36', 33 | win32: 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36', 34 | linux: 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36', 35 | darwin: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.1 Safari/537.36', 36 | }; 37 | 38 | Common.WEB_WECHAT = 'https://wx.qq.com/?lang=en_US'; 39 | Common.GITHUB = 'https://github.com/geeeeeeeeek/electronic-wechat'; 40 | Common.GITHUB_RELEASES = 'https://github.com/geeeeeeeeek/electronic-wechat/releases'; 41 | Common.GITHUB_ISSUES = 'https://github.com/geeeeeeeeek/electronic-wechat/issues'; 42 | Common.GITHUB_API_HOST = 'api.github.com'; 43 | Common.GITHUB_API_RELEASE_LATEST_PATH = '/repos/geeeeeeeeek/electronic-wechat/releases/latest'; 44 | 45 | Common.UPDATE_ERROR_ELECTRON = `Failed to get the local version. If you are using debug mode(by \`npm start\`), this error would happen. Use packed app instead or manually check for updates.\n\n${Common.GITHUB_RELEASES}`; 46 | Common.UPDATE_ERROR_EMPTY_RESPONSE = 'Failed to fetch release info.'; 47 | Common.UPDATE_ERROR_UNKNOWN = 'Something went wrong.'; 48 | Common.UPDATE_NA_TITLE = 'No Update Available'; 49 | Common.UPDATE_ERROR_NETWORK = 'Connection hang up unexpectedly. Check your network settings.'; 50 | Common.UPDATE_ERROR_LATEST = (version) => { 51 | return `You are using the latest version(${version}).`; 52 | }; 53 | 54 | Common.MENTION_MENU_INITIAL_X = 300; 55 | Common.MENTION_MENU_OFFSET_X = 30; 56 | Common.MENTION_MENU_INITIAL_Y = 140; 57 | Common.MENTION_MENU_OFFSET_Y = 45; 58 | Common.MENTION_MENU_WIDTH = 120; 59 | Common.MENTION_MENU_OPTION_HEIGHT = 30; 60 | Common.MENTION_MENU_OPTION_DEFAULT_NUM = 4; 61 | Common.MENTION_MENU_HINT_TEXT = 'Mention:'; 62 | 63 | Common.MESSAGE_PREVENT_RECALL = 'Blocked a message recall.'; 64 | Common.EMOJI_MAXIUM_SIZE = 120; 65 | 66 | Common.languageTitle = 'Language(Need to Restart)'; 67 | Common.languageDesc = 'Select a default language for WeChat!'; 68 | Common.recallTitle = 'Prevent Message Recall'; 69 | Common.recallDesc = 'Message recall feature might be annoying'; 70 | Common.instanceTitle = 'Allow Multiple Instance'; 71 | Common.instanceDesc = 'Multiple instance can login with different accounts'; 72 | Common.iconTitle = 'File Path (In Development)'; 73 | Common.iconDesc = 'Set a default file path'; 74 | Common.trayTitle = 'Tray Icon color (Black/White)'; 75 | Common.trayDesc = 'Select a color to match your desktop theme'; 76 | 77 | Common.UPGRADE = 'UPGRADE'; 78 | Common.FEEDBACK = 'FEEDBACK'; 79 | 80 | Common.MENU = { 81 | about: 'About Electronic Wechat', 82 | service: 'Service', 83 | hide: 'Hide Application', 84 | hideOther: 'Hide Others', 85 | showAll: 'Show All', 86 | pref: 'Preference', 87 | quit: 'Quit', 88 | edit: 'Edit', 89 | undo: 'Undo', 90 | redo: 'Redo', 91 | cut: 'Cut', 92 | copy: 'Copy', 93 | paste: 'Paste', 94 | selectAll: 'Select All', 95 | view: 'View', 96 | reload: 'Reload This Window', 97 | toggleFullScreen: 'Toggle Full Screen', 98 | searchContacts: 'Search Contacts', 99 | devtool: 'Toggle DevTools', 100 | window: 'Window', 101 | min: 'Minimize', 102 | close: 'Close', 103 | allFront: 'Bring All to Front', 104 | help: 'Help', 105 | repo: 'GitHub Repository', 106 | feedback: 'Report Issue', 107 | checkRelease: 'Check for New Release', 108 | }; 109 | 110 | module.exports = Common; 111 | -------------------------------------------------------------------------------- /src/common_cn.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Zhongyi on 3/26/16. 3 | */ 4 | 'use strict'; 5 | class Common { 6 | 7 | } 8 | Common.ELECTRON = 'Electron'; 9 | Common.ELECTRONIC_WECHAT = 'Electronic WeChat'; 10 | Common.DEBUG_MODE = false; 11 | Common.WINDOW_SIZE = { 12 | width: 800, 13 | height: 600, 14 | }; 15 | Common.WINDOW_SIZE_LOGIN = { 16 | width: 380, 17 | height: 540, 18 | }; 19 | Common.WINDOW_SIZE_LOADING = { 20 | width: 380, 21 | height: 120, 22 | }; 23 | Common.WINDOW_SIZE_SETTINGS = { 24 | width: 800, 25 | height: 600, 26 | }; 27 | 28 | Common.USER_AGENT = { 29 | 'freebsd': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36', 30 | 'sunos': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36', 31 | 'win32': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36', 32 | 'linux': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36', 33 | 'darwin': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.1 Safari/537.36' 34 | } 35 | 36 | Common.WEB_WECHAT = 'https://wx.qq.com/?lang=zh_CN'; 37 | Common.GITHUB = 'https://github.com/geeeeeeeeek/electronic-wechat'; 38 | Common.GITHUB_RELEASES = 'https://github.com/geeeeeeeeek/electronic-wechat/releases'; 39 | Common.GITHUB_ISSUES = 'https://github.com/geeeeeeeeek/electronic-wechat/issues'; 40 | Common.GITHUB_API_HOST = 'api.github.com'; 41 | Common.GITHUB_API_RELEASE_LATEST_PATH = '/repos/geeeeeeeeek/electronic-wechat/releases/latest'; 42 | 43 | Common.UPDATE_ERROR_ELECTRON = 'Failed to get the local version. If you are using debug mode(by `npm start`), this error would happen. Use packed app instead or manually check for updates.\n\n' + Common.GITHUB_RELEASES; 44 | Common.UPDATE_ERROR_EMPTY_RESPONSE = '没能获取最新的更新信息'; 45 | Common.UPDATE_ERROR_UNKNOWN = '不造什么出错了...'; 46 | Common.UPDATE_NA_TITLE = '没有可用的更新'; 47 | Common.UPDATE_ERROR_NETWORK = '网络连接出错,请检查你的网络'; 48 | Common.UPDATE_ERROR_LATEST = (version) => { 49 | return `已经在使用最新版 - (${version})`; 50 | }; 51 | 52 | Common.MENTION_MENU_INITIAL_X = 300; 53 | Common.MENTION_MENU_OFFSET_X = 30; 54 | Common.MENTION_MENU_INITIAL_Y = 140; 55 | Common.MENTION_MENU_OFFSET_Y = 45; 56 | Common.MENTION_MENU_WIDTH = 120; 57 | Common.MENTION_MENU_OPTION_HEIGHT = 30; 58 | Common.MENTION_MENU_OPTION_DEFAULT_NUM = 4; 59 | 60 | Common.MENTION_MENU_HINT_TEXT = '选择回复的人:'; 61 | 62 | Common.MESSAGE_PREVENT_RECALL = '阻止了一次撤回'; 63 | 64 | Common.EMOJI_MAXIUM_SIZE = 120; 65 | 66 | Common.MENU = { 67 | about: '关于 Electronic Wechat', 68 | service: '服务', 69 | hide: '隐藏应用', 70 | hideOther: '隐藏其他窗口', 71 | showAll: '显示全部窗口', 72 | pref: '偏好', 73 | quit: '退出', 74 | edit: '编辑', 75 | undo: '撤销', 76 | redo: '取消撤销', 77 | cut: '剪切', 78 | copy: '复制', 79 | paste: '粘贴', 80 | selectAll: '选择全部', 81 | view: '视图', 82 | reload: '重新加载当前窗口', 83 | toggleFullScreen:'切换全屏', 84 | searchContacts:'搜索联系人', 85 | devtool: '开发者工具', 86 | window: '窗口', 87 | min: '最小化', 88 | close: '关闭', 89 | allFront: '全部打开', 90 | help: '帮助', 91 | repo: 'GitHub 目录', 92 | feedback: '联系我们', 93 | checkRelease: '检查更新', 94 | }; 95 | 96 | module.exports = Common; 97 | -------------------------------------------------------------------------------- /src/configuration.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function getUserHome() { 4 | return process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME']; 5 | } 6 | 7 | const nconf = require('nconf').file({ 8 | file: `${getUserHome()}/.ew.json`, 9 | }); 10 | 11 | function saveSettings(settingKey, settingValue) { 12 | nconf.set(settingKey, settingValue); 13 | nconf.save(); 14 | } 15 | 16 | function readSettings(settingKey) { 17 | nconf.load(); 18 | return nconf.get(settingKey); 19 | } 20 | 21 | module.exports = { 22 | saveSettings, 23 | readSettings, 24 | }; 25 | -------------------------------------------------------------------------------- /src/handlers/menu.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { remote, shell, ipcRenderer } = require('electron'); 4 | const AppConfig = require('../configuration'); 5 | 6 | const { Menu, app } = remote; 7 | 8 | const lan = AppConfig.readSettings('language'); 9 | let Common; 10 | if (lan === 'zh-CN') { 11 | Common = require('../common_cn'); 12 | } else { 13 | Common = require('../common'); 14 | } 15 | 16 | class MenuHandler { 17 | create() { 18 | const template = this.getTemplate(remote.process.platform); 19 | if (template) { 20 | const menuFromTemplate = Menu.buildFromTemplate(template); 21 | Menu.setApplicationMenu(menuFromTemplate); 22 | } 23 | } 24 | 25 | getTemplate(platform) { 26 | const darwinTemplate = [ 27 | { 28 | label: Common.ELECTRONIC_WECHAT, 29 | submenu: [ 30 | { 31 | label: Common.MENU.about, 32 | selector: 'orderFrontStandardAboutPanel:', 33 | }, 34 | { 35 | type: 'separator', 36 | }, 37 | { 38 | label: Common.MENU.service, 39 | submenu: [], 40 | }, 41 | { 42 | type: 'separator', 43 | }, 44 | { 45 | label: Common.MENU.hide, 46 | accelerator: 'Command+H', 47 | selector: 'hide:', 48 | }, 49 | { 50 | label: Common.MENU.hideOther, 51 | accelerator: 'Command+Alt+H', 52 | selector: 'hideOtherApplications:', 53 | }, 54 | { 55 | label: Common.MENU.showAll, 56 | selector: 'unhideAllApplications:', 57 | }, 58 | { 59 | type: 'separator', 60 | }, 61 | { 62 | label: Common.MENU.pref, 63 | click: MenuHandler._preference, 64 | }, 65 | { 66 | type: 'separator', 67 | }, 68 | { 69 | label: Common.MENU.quit, 70 | accelerator: 'Command+Q', 71 | click: MenuHandler._quitApp, 72 | }, 73 | ], 74 | }, 75 | { 76 | label: Common.MENU.edit, 77 | submenu: [ 78 | { 79 | label: Common.MENU.undo, 80 | accelerator: 'Command+Z', 81 | selector: 'undo:', 82 | }, 83 | { 84 | label: Common.MENU.redo, 85 | accelerator: 'Shift+Command+Z', 86 | selector: 'redo:', 87 | }, 88 | { 89 | type: 'separator', 90 | }, 91 | { 92 | label: Common.MENU.cut, 93 | accelerator: 'Command+X', 94 | selector: 'cut:', 95 | }, 96 | { 97 | label: Common.MENU.copy, 98 | accelerator: 'Command+C', 99 | selector: 'copy:', 100 | }, 101 | { 102 | label: Common.MENU.paste, 103 | accelerator: 'Command+V', 104 | selector: 'paste:', 105 | }, 106 | { 107 | label: Common.MENU.selectAll, 108 | accelerator: 'Command+A', 109 | selector: 'selectAll:', 110 | }, 111 | { 112 | type: 'separator', 113 | }, 114 | { 115 | label: Common.MENU.searchContacts, 116 | accelerator: 'Command+F', 117 | click: () => { 118 | $('#search_bar input')[0].focus(); 119 | }, 120 | }, 121 | ], 122 | }, 123 | { 124 | label: Common.MENU.view, 125 | submenu: [ 126 | { 127 | label: Common.MENU.reload, 128 | accelerator: 'Command+R', 129 | click: MenuHandler._reload, 130 | }, 131 | { 132 | label: Common.MENU.devtool, 133 | accelerator: 'Alt+Command+I', 134 | click: MenuHandler._devTools, 135 | }, 136 | ], 137 | }, 138 | { 139 | label: Common.MENU.window, 140 | submenu: [ 141 | { 142 | label: Common.MENU.min, 143 | accelerator: 'Command+M', 144 | selector: 'performMiniaturize:', 145 | }, 146 | { 147 | label: Common.MENU.close, 148 | accelerator: 'Command+W', 149 | selector: 'performClose:', 150 | }, 151 | { 152 | label: Common.MENU.toggleFullScreen, 153 | accelerator: 'Ctrl+Command+F', 154 | click: (item, focusedWindow) => { 155 | if (focusedWindow) { 156 | focusedWindow.setFullScreen(!focusedWindow.isFullScreen()); 157 | } 158 | }, 159 | }, 160 | { 161 | type: 'separator', 162 | }, 163 | { 164 | label: Common.MENU.allFront, 165 | selector: 'arrangeInFront:', 166 | }, 167 | ], 168 | }, 169 | { 170 | label: Common.MENU.help, 171 | submenu: [ 172 | { 173 | label: Common.MENU.repo, 174 | click: MenuHandler._github, 175 | }, 176 | { 177 | type: 'separator', 178 | }, { 179 | label: Common.MENU.feedback, 180 | click: MenuHandler._githubIssues, 181 | }, { 182 | label: Common.MENU.checkRelease, 183 | click: MenuHandler._update, 184 | }], 185 | }, 186 | ]; 187 | const linuxTemplate = [ 188 | { 189 | label: Common.MENU.window, 190 | submenu: [ 191 | { 192 | label: Common.MENU.pref, 193 | click: MenuHandler._preference, 194 | }, 195 | { 196 | label: Common.MENU.reload, 197 | accelerator: 'Ctrl+R', 198 | click: MenuHandler._reload, 199 | }, 200 | { 201 | label: Common.MENU.toggleFullScreen, 202 | accelerator: 'F11', 203 | click: (item, focusedWindow) => { 204 | if (focusedWindow) { 205 | focusedWindow.setFullScreen(!focusedWindow.isFullScreen()); 206 | } 207 | }, 208 | }, 209 | { 210 | type: 'separator', 211 | }, 212 | { 213 | label: Common.MENU.searchContacts, 214 | accelerator: 'Ctrl+F', 215 | click: () => { 216 | $('#search_bar input')[0].focus(); 217 | }, 218 | }, 219 | { 220 | label: Common.MENU.devtool, 221 | accelerator: 'Ctrl+Shift+I', 222 | click: MenuHandler._devTools, 223 | }, 224 | { 225 | type: 'separator', 226 | }, 227 | { 228 | label: Common.MENU.quit, 229 | accelerator: 'Ctrl+Q', 230 | click: MenuHandler._quitApp, 231 | }, 232 | ], 233 | }, 234 | { 235 | label: Common.MENU.help, 236 | submenu: [ 237 | { 238 | label: Common.MENU.repo, 239 | click: MenuHandler._github, 240 | }, 241 | { 242 | type: 'separator', 243 | }, { 244 | label: Common.MENU.feedback, 245 | click: MenuHandler._githubIssues, 246 | }, { 247 | label: Common.MENU.checkRelease, 248 | click: MenuHandler._update, 249 | }], 250 | }, 251 | ]; 252 | 253 | if (platform === 'darwin') { 254 | return darwinTemplate; 255 | } else if (platform === 'linux') { 256 | return linuxTemplate; 257 | } 258 | } 259 | 260 | static _quitApp() { 261 | app.exit(0); 262 | } 263 | 264 | static _reload() { 265 | ipcRenderer.send('reload'); 266 | } 267 | 268 | static _devTools() { 269 | remote.getCurrentWindow().toggleDevTools(); 270 | } 271 | 272 | static _github() { 273 | shell.openExternal(Common.GITHUB); 274 | } 275 | 276 | static _githubIssues() { 277 | shell.openExternal(Common.GITHUB_ISSUES); 278 | } 279 | 280 | static _update() { 281 | ipcRenderer.send('update'); 282 | } 283 | 284 | static _preference() { 285 | ipcRenderer.send('open-settings-window'); 286 | } 287 | } 288 | module.exports = MenuHandler; 289 | -------------------------------------------------------------------------------- /src/handlers/message.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const qs = require('querystring'); 4 | const url = require('url'); 5 | 6 | class MessageHandler { 7 | handleRedirectMessage(origin) { 8 | return qs.parse(url.parse(origin).query).requrl || origin; 9 | } 10 | } 11 | 12 | module.exports = MessageHandler; 13 | -------------------------------------------------------------------------------- /src/handlers/update.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Zhongyi on 3/25/16. 3 | */ 4 | 5 | 'use strict'; 6 | 7 | const { dialog, shell, app, nativeImage } = require('electron'); 8 | const AppConfig = require('../configuration'); 9 | const https = require('https'); 10 | const path = require('path'); 11 | 12 | const lan = AppConfig.readSettings('language'); 13 | let Common; 14 | if (lan === 'zh-CN') { 15 | Common = require('../common_cn'); 16 | } else { 17 | Common = require('../common'); 18 | } 19 | 20 | class UpdateHandler { 21 | checkForUpdate(version, silent) { 22 | UpdateHandler.CHECKED = true; 23 | const promise = new Promise((res, rej) => { 24 | if (Common.ELECTRON === app.getName()) { 25 | rej(Common.UPDATE_ERROR_ELECTRON); 26 | } 27 | const req = https.get({ 28 | host: Common.GITHUB_API_HOST, 29 | headers: { 'user-agent': Common.USER_AGENT }, 30 | path: Common.GITHUB_API_RELEASE_LATEST_PATH, 31 | }, (response) => { 32 | let body = ''; 33 | response.on('data', (d) => { 34 | body += d; 35 | }); 36 | response.on('end', () => { 37 | this._parseUpdateData(body, version, res, rej); 38 | }); 39 | }); 40 | req.on('error', (err) => { 41 | rej(Common.UPDATE_ERROR_NETWORK); 42 | }); 43 | req.end(); 44 | }).then((fetched) => { 45 | this.showDialog(fetched.name, fetched.description, 'Update', (response) => { 46 | if (!response) return; 47 | shell.openExternal(fetched.url); 48 | }); 49 | }).catch((message) => { 50 | if (silent) return; 51 | if (!message) { 52 | message = Common.UPDATE_ERROR_UNKNOWN; 53 | } 54 | this.showDialog(Common.UPDATE_NA_TITLE, message, 'OK'); 55 | }); 56 | } 57 | 58 | showDialog(message, detail, positiveButton, callback) { 59 | const iconImage = nativeImage.createFromPath(path.join(__dirname, '../assets/icon.png')); 60 | 61 | dialog.showMessageBox({ 62 | type: 'info', 63 | buttons: ['Cancel', positiveButton], 64 | defaultId: 1, 65 | cancelId: 0, 66 | title: message, 67 | message, 68 | detail, 69 | icon: iconImage, 70 | }, callback); 71 | } 72 | 73 | _parseUpdateData(body, version, res, rej) { 74 | const data = JSON.parse(body); 75 | if (!data || !data.tag_name) rej(Common.UPDATE_ERROR_EMPTY_RESPONSE); 76 | const fetched = { 77 | version: data.tag_name, 78 | is_prerelease: data.prerelease, 79 | name: data.name, 80 | url: data.html_url, 81 | description: data.body, 82 | }; 83 | 84 | const versionRegex = /^v[0-9]+\.[0-9]+\.*[0-9]*$/; 85 | if (versionRegex.test(fetched.version) && fetched.version > version && !fetched.is_prerelease) { 86 | res(fetched); 87 | } else { 88 | rej(Common.UPDATE_ERROR_LATEST(version)); 89 | } 90 | } 91 | } 92 | 93 | UpdateHandler.CHECKED = false; 94 | 95 | module.exports = UpdateHandler; 96 | -------------------------------------------------------------------------------- /src/inject/badge_count.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Zhongyi on 4/12/16. 3 | */ 4 | 'use strict'; 5 | const { ipcRenderer } = require('electron'); 6 | 7 | class BadgeCount { 8 | static init() { 9 | setInterval(() => { 10 | let count = 0; 11 | $('.icon.web_wechat_reddot_middle').each(function () { 12 | count += parseInt(this.textContent, 10); 13 | }); 14 | if (count > 0) { 15 | ipcRenderer.send('badge-changed', count.toString()); 16 | } else { 17 | ipcRenderer.send('badge-changed', ''); 18 | } 19 | }, 1500); 20 | } 21 | } 22 | 23 | module.exports = BadgeCount; 24 | -------------------------------------------------------------------------------- /src/inject/css.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Zhongyi on 2/23/16. 3 | */ 4 | 'use strict'; 5 | const Common = require('../common'); 6 | 7 | class CSSInjector { 8 | } 9 | 10 | CSSInjector.commonCSS = ` 11 | div.header, div.title_wrap { 12 | -webkit-app-region: drag; 13 | } 14 | div.title.poi { 15 | -webkit-app-region: no-drag; 16 | } 17 | div.header .avatar, div.header .info { 18 | -webkit-app-region: no-drag; 19 | } 20 | div.main { 21 | height: 100% !important; 22 | min-height: 0 !important; 23 | padding-top: 0 !important; 24 | } 25 | div.main_inner { 26 | max-width: none !important; 27 | min-width: 0 !important; 28 | } 29 | div.message_empty { 30 | margin-top: 50px; 31 | } 32 | div.img_preview_container div.img_opr_container { 33 | bottom: 50px !important; 34 | } 35 | p.copyright { 36 | display: none !important 37 | } 38 | a.web_wechat_screencut { 39 | display: none !important; 40 | } 41 | * { 42 | -webkit-user-select: none; 43 | cursor: default !important; 44 | -webkit-user-drag: none; 45 | } 46 | pre, input { 47 | -webkit-user-select: initial; 48 | cursor: initial !important; 49 | } 50 | html, body { 51 | width: 100%; 52 | height: 100%; 53 | overflow: hidden; 54 | } 55 | 56 | div.login_box { 57 | top: initial; 58 | left: initial; 59 | margin-left: initial; 60 | margin-top: initial; 61 | width: 100%; 62 | height: 100%; 63 | } 64 | div.login { 65 | min-width: 0; 66 | min-height: 0; 67 | width: 100%; 68 | height: 100%; 69 | overflow: hidden; 70 | } 71 | div.lang, div.copyright { 72 | display: none !important 73 | } 74 | /* Group mention: user selection box */ 75 | div#userSelectionBox select option:hover { 76 | background: #eeeeee; 77 | } 78 | div#userSelectionBox select option { 79 | padding: 4px 10px; 80 | text-overflow: hidden; 81 | font-size: 14px; 82 | } 83 | .user_select_hint_text { 84 | padding: 4px 10px; 85 | font-size: 14px; 86 | background: #eeeeee; 87 | } 88 | div#userSelectionBox select { 89 | width: 120px; 90 | border: none; 91 | outline: none; 92 | height: inherit; 93 | } 94 | div#userSelectionBox { 95 | box-shadow: 1px 1px 10px #ababab; 96 | background: #fff; 97 | display: none; 98 | position: fixed; 99 | bottom: ${Common.MENTION_MENU_INITIAL_Y}px; 100 | left: ${Common.MENTION_MENU_INITIAL_X}px; 101 | } 102 | span.measure_text { 103 | padding-left: 20px; 104 | outline: 0; 105 | border: 0; 106 | font-size: 14px; 107 | } 108 | img.emojione { 109 | width: 20px; 110 | height: 20px; 111 | } 112 | @media (max-width: 512px) { 113 | .panel { 114 | width: 75px !important; 115 | transition: width .3s; 116 | } 117 | .panel .header, 118 | .chat_item { 119 | padding: 8px 16px !important; 120 | } 121 | .header, 122 | .panel .tab, 123 | .search_bar, 124 | .chat_item .info, 125 | .chat_item .ext { 126 | display: none !important 127 | } 128 | .nav_view { 129 | top: 36px !important 130 | } 131 | .chat_item.active { 132 | border-left: 2px solid #02b300 !important 133 | } 134 | } 135 | `; 136 | 137 | CSSInjector.osxCSS = ` 138 | div.header div.avatar img.img { 139 | width: 24px; 140 | height: 24px; 141 | } 142 | div.header { 143 | padding-top: 38px; 144 | padding-bottom: 8px; 145 | } 146 | span.display_name { 147 | width: 172px !important; 148 | } 149 | @media (max-width: 512px) { 150 | .nav_view { 151 | top: 36px !important 152 | } 153 | } 154 | `; 155 | 156 | module.exports = CSSInjector; 157 | -------------------------------------------------------------------------------- /src/inject/emoji_parser.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by chenwl on 9/29/16. 3 | */ 4 | 5 | var emojione = require('emojione'); 6 | 7 | // 8 | const emojiSpanRegex = /<\/span>/g; 9 | 10 | function unicodeToString(point) { 11 | const offset = point - 0x10000; 12 | const lead = 0xd800 + (offset >> 10); 13 | const trail = 0xdc00 + (offset & 0x3ff); 14 | return String.fromCharCode(lead, trail); 15 | } 16 | 17 | class EmojiParser { 18 | static emojiSpanToString(str) { 19 | return str.replace(emojiSpanRegex, function(span, emojiHex) { 20 | const point = parseInt(emojiHex, 16); 21 | return unicodeToString(point); 22 | }); 23 | } 24 | 25 | static emojiToImage(str) { 26 | return emojione.unicodeToImage(EmojiParser.emojiSpanToString(str)); 27 | } 28 | } 29 | 30 | module.exports = EmojiParser; 31 | -------------------------------------------------------------------------------- /src/inject/mention_menu.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Zhongyi on 4/9/16. 3 | */ 4 | 5 | 'use strict'; 6 | const Common = require('../common'); 7 | const pinyin = require('pinyin'); 8 | 9 | class MentionMenu { 10 | 11 | static init() { 12 | const $box = $('
'); 13 | 14 | const $div = $('
'); 15 | $div.html(Common.MENTION_MENU_HINT_TEXT); 16 | $div.addClass('user_select_hint_text'); 17 | $box.append($div); 18 | 19 | const $select = $(' 39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
    47 | 50 | 53 | 59 |
60 |
61 |
62 |
    63 | 66 | 69 | 75 |
76 |
77 |
78 |
    79 | 82 | 85 | 88 |
89 |
90 |
91 |
    92 | 95 | 98 | 104 |
105 |
106 |
107 | 108 | 197 | 198 | 199 | 200 | -------------------------------------------------------------------------------- /src/windows/views/splash.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Starting App 8 | 9 | 10 | 11 |
12 | 13 | Starting App 14 |
15 | 16 | 17 | 18 | --------------------------------------------------------------------------------