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>
<i *ngIf="update_status === 'checking-for-update'" class="fa fa-spinner fa-pulse fa-spin"
i18n-title title="正在检查更新"></i>
<i *ngIf="update_status === 'update-available'" class="fa fa-refresh fa-spin"
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>
/**
* Created by zh99998 on 16/9/2.
*/
import { Component, OnInit } from '@angular/core';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { remote } from 'electron';
@Component({
selector: 'update',
templateUrl: './update.component.html',
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;
error: string;
readonly autoUpdater: Electron.AutoUpdater = remote.getGlobal('autoUpdater');
ngOnInit() {
this.autoUpdater.on('error', (error) => {
this.status = 'error';
});
this.autoUpdater.on('checking-for-update', () => {
this.status = 'checking-for-update';
});
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();
for (let event of ['error', 'checking-for-update', 'update-available', 'update-not-available', 'update-downloaded']) {
const listener = () => this.status = event;
this.autoUpdater.on(event, listener);
this.events.set(event, listener);
}
window.addEventListener('unload', () => this.ngOnDestroy());
}
install() {
this.autoUpdater.quitAndInstall();
ngOnDestroy() {
for (let [event, listener] of this.events) {
this.autoUpdater.removeListener(event, listener);
}
this.events.clear();
}
}
'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 isDev = require('electron-is-dev');
const child_process = require('child_process');
const path = require('path');
const net = require('net');
const readline = require('readline');
const { EOL } = require('os');
// 提权
function handleElevate() {
......@@ -16,13 +19,13 @@ function handleElevate() {
if (process.argv[1] === '-e') {
if (process.platform === 'darwin') {
require('electron').app.dock.hide();
app.dock.hide();
}
let elevate = JSON.parse(new Buffer(process.argv[2], 'base64').toString());
require('net').connect(elevate['ipc'], function () {
process.send = (message, sendHandle, options, callback) => this.write(JSON.stringify(message) + require('os').EOL, callback);
net.connect(elevate['ipc'], function () {
process.send = (message, sendHandle, options, callback) => this.write(JSON.stringify(message) + EOL, callback);
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];
require('./' + elevate['arguments'][0]);
});
......@@ -57,45 +60,16 @@ if (!process.env['NODE_ENV']) {
// 自动更新
let updateWindow;
// 置 global 后可以在页面进程里取
global.autoUpdater = autoUpdater;
autoUpdater.on('error', (event) => {
global.update_status = 'error';
console.log('autoUpdater', 'error', event);
});
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();
});
autoUpdater.on('update-downloaded', () => {
updateWindow = new BrowserWindow({ width: 640, height: 360 });
updateWindow.loadURL(`file://${__dirname}/update/index.html`);
updateWindow.on('closed', () => updateWindow = null);
});
// Aria2c
function createAria2c() {
const aria2 = (() => {
let aria2c_path;
switch (process.platform) {
case 'win32':
......@@ -116,8 +90,7 @@ function createAria2c() {
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' });
}
const aria2c = createAria2c();
})();
// 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.
......@@ -157,36 +130,26 @@ function createWindow() {
});
}
function toggleMainWindow() {
if (mainWindow.isVisible()) {
mainWindow.hide();
} else {
mainWindow.show();
}
}
// 托盘
let tray;
function createTray() {
tray = new Tray(path.join(process.env['NODE_ENV'] === 'production' ? process.resourcesPath : app.getAppPath(), 'assets', 'icon.ico'));
tray.on('click', (event) => {
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.on('click', () => event.metaKey ? mainWindow.webContents.openDevTools() : toggleMainWindow());
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
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
......@@ -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
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
......@@ -222,6 +186,6 @@ app.on('activate', function () {
app.on('quit', () => {
// windows 在非 detach 模式下会自动退出子进程
if (process.platform !== 'win32') {
aria2c.kill();
aria2.kill();
}
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<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">-->
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title id="title"></title>
<title id="title"></title>
<!-- Bootstrap core CSS -->
<link href="../node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="../node_modules/vue/dist/vue.min.js"></script>
<style>
h1 {
margin-top: 10px;
margin-bottom: 20px;
text-align: center;
}
<!-- Bootstrap core CSS -->
<link href="../node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="../node_modules/vue/dist/vue.min.js"></script>
<style>
h1 {
margin-top: 10px;
margin-bottom: 20px;
text-align: center;
}
#actions {
margin-top: 20px;
text-align: center;
}
</style>
#actions {
margin-top: 20px;
text-align: center;
}
</style>
</head>
<body>
<div id="vueApp">
<div class="container">
<h1>{{pageText.updateTitle}}</h1>
<p v-for="(msg, index) in pageText.updateMsg">{{msg}}</p>
<p>{{pageText.updateFailed.p1}}
<a href="https://moecube.com" target="_blank">{{pageText.updateFailed.p2}}</a> {{pageText.updateFailed.p3}}
</p>
<p id="actions">
<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>
</p>
</div>
</div>
<div class="container">
<h1>{{pageText.updateTitle}}</h1>
<p v-for="(msg, index) in pageText.updateMsg">{{msg}}</p>
<p>{{pageText.updateFailed.p1}}
<a href="https://moecube.com" target="_blank">{{pageText.updateFailed.p2}}</a> {{pageText.updateFailed.p3}} </p>
<p id="actions">
<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>
</p>
</div>
</div>]\.=
<script>
const { ipcRenderer, remote } = require('electron');
const lang = require('./lang.js');
const { remote } = require('electron');
const autoUpdater = remote.getGlobal('autoUpdater');
const lang = require('./lang.json');
new Vue({
el: '#vueApp',
created: function () {
let locale = localStorage.getItem('locale') || remote.app.getLocale();
if (locale.startsWith('zh-')) {
locale = 'zh-CN';
} else {
locale = 'en-US';
}
this.pageText = lang['update'][locale];
new Vue({
el: '#vueApp',
created: function () {
let locale = localStorage.getItem('locale') || remote.app.getLocale();
if (locale.startsWith('zh-')) {
locale = 'zh-CN';
} else {
locale = 'en-US';
}
this.pageText = lang['update'][locale];
document.getElementById('title').innerHTML = this.pageText.pageTitle;
},
methods: {
onClose(){
window.close();
},
onUpdate(){
ipcRenderer.send('update');
}
},
data: {
message: 'Hello Vue!',
pageText: {}
}
});
document.getElementById('title').innerHTML = this.pageText.pageTitle;
},
methods: {
onClose(){
window.close();
},
onUpdate(){
autoUpdater.quitAndInstall();
}
},
data: {
message: 'Hello Vue!',
pageText: {}
}
});
</script>
</body>
</html>
module.exports = {
{
"update": {
"zh-CN": {
"pageTitle":"更新消息",
"updateTitle":"AppModule 更新下载完毕",
"updateMsg":[
"pageTitle": "更新消息",
"updateTitle": "AppModule 更新下载完毕",
"updateMsg": [
"点击【现在安装更新】,会立即关闭 AppModule 平台及正在运行中的游戏,并安装更新。",
"点击【下次启动时安装更新】,会在 AppModule 平台退出之后进行更新。",
"你也可以随时点击平台上的更新按钮安装哦!"
],
"updateFailed":{
"p1":"如果自动更新失败,请至",
"p2":"https://moecube.com",
"p3":"手动下载最新版本"
"updateFailed": {
"p1": "如果自动更新失败,请至",
"p2": "https://moecube.com",
"p3": "手动下载最新版本"
},
"actions":{
"update":"(。・`ω´・) 现在安装更新",
"close":"下次启动时安装更新 _(:3 」∠)_"
"actions": {
"update": "(。・`ω´・) 现在安装更新",
"close": "下次启动时安装更新 _(:3 」∠)_"
}
},
"en-US": {
"pageTitle":"Update",
"updateTitle":"Update downloaded",
"updateMsg":[
"pageTitle": "Update",
"updateTitle": "Update downloaded",
"updateMsg": [
"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.",
"You may also click the Update button to install the update anytime."
],
"updateFailed":{
"p1":"",
"p2":"",
"p3":""
"updateFailed": {
"p1": "",
"p2": "",
"p3": ""
},
"actions":{
"update":"(。・`ω´・) Install Now",
"close":"Install Later _(:3 」∠)_"
"actions": {
"update": "(。・`ω´・) Install Now",
"close": "Install Later _(:3 」∠)_"
}
}
},
"other-page":{
"zh-CN":{},
"en-US":{}
"other-page": {
"zh-CN": {},
"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