Commit 93b715cd authored by 2breakegg's avatar 2breakegg

Merge branch 'dev' of https://github.com/moecube/moecube into dev

parents 4996814c 2eb5e626
<i *ngIf="update_status === 'error'" (click)="retry()" class="fa fa-exclamation-circle" <i *ngIf="update_status === 'error'" (click)="autoUpdater.checkForUpdates()" class="fa fa-exclamation-circle"
i18n-title title="更新出错,点击重试"></i> i18n-title title="更新出错,点击重试"></i>
<i *ngIf="update_status === 'checking-for-update'" class="fa fa-spinner fa-pulse fa-spin" <i *ngIf="update_status === 'checking-for-update'" class="fa fa-spinner fa-pulse fa-spin"
i18n-title title="正在检查更新"></i> i18n-title title="正在检查更新"></i>
<i *ngIf="update_status === 'update-available'" class="fa fa-refresh fa-spin" <i *ngIf="update_status === 'update-available'" class="fa fa-refresh fa-spin"
i18n-title title="正在下载更新"></i> i18n-title title="正在下载更新"></i>
<i *ngIf="update_status === 'update-downloaded'" (click)="install()" class="fa fa-angle-double-up" <i *ngIf="update_status === 'update-downloaded'" (click)="autoUpdater.quitAndInstall()" class="fa fa-angle-double-up"
i18n-title title="下载更新完成,点击安装"></i> i18n-title title="下载更新完成,点击安装"></i>
/** /**
* Created by zh99998 on 16/9/2. * Created by zh99998 on 16/9/2.
*/ */
import { Component, OnInit } from '@angular/core'; import { Component, OnDestroy, OnInit } from '@angular/core';
import { remote } from 'electron'; import { remote } from 'electron';
@Component({ @Component({
selector: 'update', selector: 'update',
templateUrl: './update.component.html', templateUrl: './update.component.html',
styleUrls: ['./update.component.css'], styleUrls: ['./update.component.css'],
}) })
export class UpdateComponent implements OnInit { export class UpdateComponent implements OnInit, OnDestroy {
autoUpdater: Electron.AutoUpdater = remote.getGlobal('autoUpdater');
events = new Map<string, Function>();
status: string; status: string;
error: string; error: string;
readonly autoUpdater: Electron.AutoUpdater = remote.getGlobal('autoUpdater');
ngOnInit() { ngOnInit() {
this.autoUpdater.on('error', (error) => { for (let event of ['error', 'checking-for-update', 'update-available', 'update-not-available', 'update-downloaded']) {
this.status = 'error'; const listener = () => this.status = event;
}); this.autoUpdater.on(event, listener);
this.autoUpdater.on('checking-for-update', () => { this.events.set(event, listener);
this.status = 'checking-for-update'; }
}); window.addEventListener('unload', () => this.ngOnDestroy());
this.autoUpdater.on('update-available', () => {
this.status = 'update-available';
});
this.autoUpdater.on('update-not-available', () => {
this.status = 'update-not-available';
});
this.autoUpdater.on('update-downloaded', () => {
this.status = 'update-downloaded';
});
}
retry() {
this.autoUpdater.checkForUpdates();
} }
install() { ngOnDestroy() {
this.autoUpdater.quitAndInstall(); for (let [event, listener] of this.events) {
this.autoUpdater.removeListener(event, listener);
}
this.events.clear();
} }
} }
'use strict'; 'use strict';
const { ipcMain, app, shell, BrowserWindow, Menu, Tray } = require('electron'); const { app, shell, BrowserWindow, Menu, Tray } = require('electron');
const { autoUpdater } = require('electron-updater'); const { autoUpdater } = require('electron-updater');
const isDev = require('electron-is-dev'); const isDev = require('electron-is-dev');
const child_process = require('child_process'); const child_process = require('child_process');
const path = require('path'); const path = require('path');
const net = require('net');
const readline = require('readline');
const { EOL } = require('os');
// 提权 // 提权
function handleElevate() { function handleElevate() {
...@@ -16,13 +19,13 @@ function handleElevate() { ...@@ -16,13 +19,13 @@ function handleElevate() {
if (process.argv[1] === '-e') { if (process.argv[1] === '-e') {
if (process.platform === 'darwin') { if (process.platform === 'darwin') {
require('electron').app.dock.hide(); app.dock.hide();
} }
let elevate = JSON.parse(new Buffer(process.argv[2], 'base64').toString()); let elevate = JSON.parse(new Buffer(process.argv[2], 'base64').toString());
require('net').connect(elevate['ipc'], function () { net.connect(elevate['ipc'], function () {
process.send = (message, sendHandle, options, callback) => this.write(JSON.stringify(message) + require('os').EOL, callback); process.send = (message, sendHandle, options, callback) => this.write(JSON.stringify(message) + EOL, callback);
this.on('end', () => process.emit('disconnect')); this.on('end', () => process.emit('disconnect'));
require('readline').createInterface({ input: this }).on('line', (line) => process.emit('message', JSON.parse(line))); readline.createInterface({ input: this }).on('line', (line) => process.emit('message', JSON.parse(line)));
process.argv = elevate['arguments'][1]; process.argv = elevate['arguments'][1];
require('./' + elevate['arguments'][0]); require('./' + elevate['arguments'][0]);
}); });
...@@ -57,45 +60,16 @@ if (!process.env['NODE_ENV']) { ...@@ -57,45 +60,16 @@ if (!process.env['NODE_ENV']) {
// 自动更新 // 自动更新
let updateWindow; let updateWindow;
// 置 global 后可以在页面进程里取
global.autoUpdater = autoUpdater; global.autoUpdater = autoUpdater;
autoUpdater.on('error', (event) => { autoUpdater.on('update-downloaded', () => {
global.update_status = 'error'; updateWindow = new BrowserWindow({ width: 640, height: 360 });
console.log('autoUpdater', 'error', event); updateWindow.loadURL(`file://${__dirname}/update/index.html`);
}); updateWindow.on('closed', () => updateWindow = null);
autoUpdater.on('checking-for-update', () => {
global.update_status = 'checking-for-update';
console.log('autoUpdater', 'checking-for-update');
});
autoUpdater.on('update-available', () => {
global.update_status = 'update-available';
console.log('autoUpdater', 'update-available');
});
autoUpdater.on('update-not-available', () => {
global.update_status = 'update-not-available';
console.log('autoUpdater', 'update-not-available');
});
autoUpdater.on('update-downloaded', (event) => {
global.update_status = 'update-downloaded';
console.log('autoUpdater', 'update-downloaded', event);
updateWindow = new BrowserWindow({
width: 640,
height: 360,
});
updateWindow.loadURL(process.env['NODE_ENV'] === 'development' ? 'http://localhost:3000' : `file://${__dirname}/update/index.html`);
updateWindow.webContents.on('new-window', function (e, url) {
e.preventDefault();
shell.openExternal(url);
});
updateWindow.on('closed', function () {
updateWindow = null;
});
ipcMain.on('update', (event, arg) => {
autoUpdater.quitAndInstall();
});
}); });
// Aria2c // Aria2c
function createAria2c() { const aria2 = (() => {
let aria2c_path; let aria2c_path;
switch (process.platform) { switch (process.platform) {
case 'win32': case 'win32':
...@@ -116,8 +90,7 @@ function createAria2c() { ...@@ -116,8 +90,7 @@ function createAria2c() {
throw 'unsupported platform'; throw 'unsupported platform';
} }
return child_process.spawn(aria2c_path, ['--enable-rpc', '--rpc-allow-origin-all', '--continue', '--split=10', '--min-split-size=1M', '--max-connection-per-server=10', '--remove-control-file', '--allow-overwrite'], { stdio: 'ignore' }); return child_process.spawn(aria2c_path, ['--enable-rpc', '--rpc-allow-origin-all', '--continue', '--split=10', '--min-split-size=1M', '--max-connection-per-server=10', '--remove-control-file', '--allow-overwrite'], { stdio: 'ignore' });
} })();
const aria2c = createAria2c();
// Keep a global reference of the window object, if you don't, the window will // Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected. // be closed automatically when the JavaScript object is garbage collected.
...@@ -157,36 +130,26 @@ function createWindow() { ...@@ -157,36 +130,26 @@ function createWindow() {
}); });
} }
function toggleMainWindow() {
if (mainWindow.isVisible()) {
mainWindow.hide();
} else {
mainWindow.show();
}
}
// 托盘 // 托盘
let tray; let tray;
function createTray() { function createTray() {
tray = new Tray(path.join(process.env['NODE_ENV'] === 'production' ? process.resourcesPath : app.getAppPath(), 'assets', 'icon.ico')); tray = new Tray(path.join(process.env['NODE_ENV'] === 'production' ? process.resourcesPath : app.getAppPath(), 'assets', 'icon.ico'));
tray.on('click', (event) => { tray.on('click', () => event.metaKey ? mainWindow.webContents.openDevTools() : toggleMainWindow());
console.log(event);
if (event.metaKey) {
mainWindow.webContents.openDevTools();
} else {
mainWindow.isVisible() ? mainWindow.hide() : mainWindow.show();
}
});
const contextMenu = Menu.buildFromTemplate([
// {label: '游戏', type: 'normal', click: (menuItem, browserWindow, event)=>{}},
// {label: '社区', type: 'normal', click: (menuItem, browserWindow, event)=>{}},
// {label: '切换账号', type: 'normal', click: (menuItem, browserWindow, event)=>{}},
{
label: '显示主界面', type: 'normal', click: () => {
mainWindow.isVisible() ? mainWindow.hide() : mainWindow.show();
}
},
{
label: '退出', type: 'normal', click: app.quit
}
]);
tray.setToolTip('MoeCube'); tray.setToolTip('MoeCube');
tray.setContextMenu(contextMenu); tray.setContextMenu(Menu.buildFromTemplate([
{ label: '显示主界面', type: 'normal', click: toggleMainWindow },
{ label: '退出', type: 'normal', click: app.quit }
]));
} }
// This method will be called when Electron has finished // This method will be called when Electron has finished
// initialization and is ready to create browser windows. // initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs. // Some APIs can only be used after this event occurs.
...@@ -209,7 +172,8 @@ app.on('window-all-closed', function () { ...@@ -209,7 +172,8 @@ app.on('window-all-closed', function () {
} }
}); });
app.on('activate', function () { app.on('activate', function (event) {
console.log(event);
// On OS X it's common to re-create a window in the currentCube when the // On OS X it's common to re-create a window in the currentCube when the
// dock icon is clicked and there are no other windows open. // dock icon is clicked and there are no other windows open.
if (mainWindow === null) { if (mainWindow === null) {
...@@ -222,6 +186,6 @@ app.on('activate', function () { ...@@ -222,6 +186,6 @@ app.on('activate', function () {
app.on('quit', () => { app.on('quit', () => {
// windows 在非 detach 模式下会自动退出子进程 // windows 在非 detach 模式下会自动退出子进程
if (process.platform !== 'win32') { if (process.platform !== 'win32') {
aria2c.kill(); aria2.kill();
} }
}); });
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
"@angular/animations": "latest", "@angular/animations": "latest",
"@angular/common": "latest", "@angular/common": "latest",
"@angular/compiler": "latest", "@angular/compiler": "latest",
"@angular/compiler-cli": "^4.0.2", "@angular/compiler-cli": "latest",
"@angular/core": "latest", "@angular/core": "latest",
"@angular/forms": "latest", "@angular/forms": "latest",
"@angular/http": "latest", "@angular/http": "latest",
...@@ -28,14 +28,14 @@ ...@@ -28,14 +28,14 @@
"@angular/platform-browser-dynamic": "latest", "@angular/platform-browser-dynamic": "latest",
"@angular/platform-server": "latest", "@angular/platform-server": "latest",
"@angular/router": "latest", "@angular/router": "latest",
"@types/uuid": "^2.0.29", "@types/uuid": "latest",
"angular-in-memory-web-api": "latest", "angular-in-memory-web-api": "latest",
"aria2": "latest", "aria2": "latest",
"bootstrap": "next", "bootstrap": "next",
"candy": "https://github.com/moecube/candy/releases/download/v2.2.0/candy.tar.gz", "candy": "https://github.com/moecube/candy/releases/download/v2.2.0/candy.tar.gz",
"candy-shop": "zh99998/candy-plugins#patch-5", "candy-shop": "zh99998/candy-plugins#patch-5",
"core-js": "latest", "core-js": "latest",
"electron-cookies": "^1.1.0", "electron-cookies": "latest",
"electron-is-dev": "latest", "electron-is-dev": "latest",
"electron-schema": "moecube/electron-schema", "electron-schema": "moecube/electron-schema",
"electron-sudo": "moecube/electron-sudo#moecube", "electron-sudo": "moecube/electron-sudo#moecube",
......
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<!--<meta name="description" content="">-->
<!--<meta name="author" content="">-->
<!--<link rel="icon" href="../../favicon.ico">-->
<title id="title"></title> <title id="title"></title>
<!-- Bootstrap core CSS --> <!-- Bootstrap core CSS -->
<link href="../node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet"> <link href="../node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="../node_modules/vue/dist/vue.min.js"></script> <script src="../node_modules/vue/dist/vue.min.js"></script>
<style> <style>
h1 { h1 {
margin-top: 10px; margin-top: 10px;
margin-bottom: 20px; margin-bottom: 20px;
text-align: center; text-align: center;
} }
#actions { #actions {
margin-top: 20px; margin-top: 20px;
text-align: center; text-align: center;
} }
</style> </style>
</head> </head>
<body> <body>
<div id="vueApp"> <div id="vueApp">
<div class="container"> <div class="container">
<h1>{{pageText.updateTitle}}</h1> <h1>{{pageText.updateTitle}}</h1>
<p v-for="(msg, index) in pageText.updateMsg">{{msg}}</p> <p v-for="(msg, index) in pageText.updateMsg">{{msg}}</p>
<p>{{pageText.updateFailed.p1}} <p>{{pageText.updateFailed.p1}}
<a href="https://moecube.com" target="_blank">{{pageText.updateFailed.p2}}</a> {{pageText.updateFailed.p3}} <a href="https://moecube.com" target="_blank">{{pageText.updateFailed.p2}}</a> {{pageText.updateFailed.p3}} </p>
</p> <p id="actions">
<p id="actions"> <button @click="onClose" type="button" class="btn btn-secondary">{{pageText.actions.close}}</button>
<button @click="onClose" type="button" class="btn btn-secondary">{{pageText.actions.close}}</button> <button @click="onUpdate" type="button" class="btn btn-primary">{{pageText.actions.update}}</button>
<button @click="onUpdate" type="button" class="btn btn-primary">{{pageText.actions.update}}</button> </p>
</p> </div>
</div> </div>]\.=
</div>
<script> <script>
const { ipcRenderer, remote } = require('electron'); const { remote } = require('electron');
const lang = require('./lang.js'); const autoUpdater = remote.getGlobal('autoUpdater');
const lang = require('./lang.json');
new Vue({ new Vue({
el: '#vueApp', el: '#vueApp',
created: function () { created: function () {
let locale = localStorage.getItem('locale') || remote.app.getLocale(); let locale = localStorage.getItem('locale') || remote.app.getLocale();
if (locale.startsWith('zh-')) { if (locale.startsWith('zh-')) {
locale = 'zh-CN'; locale = 'zh-CN';
} else { } else {
locale = 'en-US'; locale = 'en-US';
} }
this.pageText = lang['update'][locale]; this.pageText = lang['update'][locale];
document.getElementById('title').innerHTML = this.pageText.pageTitle; document.getElementById('title').innerHTML = this.pageText.pageTitle;
}, },
methods: { methods: {
onClose(){ onClose(){
window.close(); window.close();
}, },
onUpdate(){ onUpdate(){
ipcRenderer.send('update'); autoUpdater.quitAndInstall();
} }
}, },
data: { data: {
message: 'Hello Vue!', message: 'Hello Vue!',
pageText: {} pageText: {}
} }
}); });
</script> </script>
</body> </body>
</html> </html>
module.exports = { {
"update": { "update": {
"zh-CN": { "zh-CN": {
"pageTitle":"更新消息", "pageTitle": "更新消息",
"updateTitle":"AppModule 更新下载完毕", "updateTitle": "AppModule 更新下载完毕",
"updateMsg":[ "updateMsg": [
"点击【现在安装更新】,会立即关闭 AppModule 平台及正在运行中的游戏,并安装更新。", "点击【现在安装更新】,会立即关闭 AppModule 平台及正在运行中的游戏,并安装更新。",
"点击【下次启动时安装更新】,会在 AppModule 平台退出之后进行更新。", "点击【下次启动时安装更新】,会在 AppModule 平台退出之后进行更新。",
"你也可以随时点击平台上的更新按钮安装哦!" "你也可以随时点击平台上的更新按钮安装哦!"
], ],
"updateFailed":{ "updateFailed": {
"p1":"如果自动更新失败,请至", "p1": "如果自动更新失败,请至",
"p2":"https://moecube.com", "p2": "https://moecube.com",
"p3":"手动下载最新版本" "p3": "手动下载最新版本"
}, },
"actions":{ "actions": {
"update":"(。・`ω´・) 现在安装更新", "update": "(。・`ω´・) 现在安装更新",
"close":"下次启动时安装更新 _(:3 」∠)_" "close": "下次启动时安装更新 _(:3 」∠)_"
} }
}, },
"en-US": { "en-US": {
"pageTitle":"Update", "pageTitle": "Update",
"updateTitle":"Update downloaded", "updateTitle": "Update downloaded",
"updateMsg":[ "updateMsg": [
"If you install now, AppModule will go offline and update immediately, your gaming value may be affected.", "If you install now, AppModule will go offline and update immediately, your gaming value may be affected.",
"If you install later, then the update will be automatically installed when you start-up AppModule next time.", "If you install later, then the update will be automatically installed when you start-up AppModule next time.",
"You may also click the Update button to install the update anytime." "You may also click the Update button to install the update anytime."
], ],
"updateFailed":{ "updateFailed": {
"p1":"", "p1": "",
"p2":"", "p2": "",
"p3":"" "p3": ""
}, },
"actions":{ "actions": {
"update":"(。・`ω´・) Install Now", "update": "(。・`ω´・) Install Now",
"close":"Install Later _(:3 」∠)_" "close": "Install Later _(:3 」∠)_"
} }
} }
}, },
"other-page":{ "other-page": {
"zh-CN":{}, "zh-CN": {},
"en-US":{} "en-US": {}
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment