Commit fc860a13 authored by 神楽坂玲奈's avatar 神楽坂玲奈

Merge branch 'v3' of github.com:mycard/mycard into v3

parents 57e1550b 0ae6f4c3
<h1>{{appsService.currentApp.name}}</h1> <h1>{{currentApp.name}}</h1>
<div *ngIf="!isInstalled"> <div *ngIf="currentApp.status.status === 'init'">
<div *ngIf="!appsService.getDownloadInfo(appsService.currentApp)"> <button type="button" class="btn btn-primary" data-toggle="modal" (click)="updateInstallConfig()"
<button type="button" (click)="updateInstallConfig()" class="btn btn-primary" data-toggle="modal" data-target="#install-modal">安装 data-target="#install-modal">安装
</button> </button>
<button type="button" class="btn btn-secondary">导入</button> <button type="button" class="btn btn-secondary">导入</button>
<!--<button type="button" class="btn btn-secondary">正版代购</button>--> <!--<button type="button" class="btn btn-secondary">正版代购</button>-->
</div>
<div *ngIf="appsService.getDownloadInfo(appsService.currentApp)">
<div *ngIf="appsService.getDownloadInfo(appsService.currentApp).status === 'install'">正在安装...</div>
<div *ngIf="appsService.getDownloadInfo(appsService.currentApp).status === 'wait'">等待安装...</div>
<progress *ngIf="appsService.getDownloadInfo(appsService.currentApp).status === 'active'" class="progress progress-striped progress-animated" value="{{appsService.getDownloadInfo(appsService.currentApp).progress}}" max="100"></progress>
</div>
</div> </div>
<div *ngIf="isInstalled && (appsService.currentApp.id != 'ygopro')"> <div *ngIf="currentApp.status.status === 'installing'">正在安装...</div>
<button (click)="startApp(appsService.currentApp)" type="button" class="btn btn-primary">运行</button> <div *ngIf="currentApp.status.status==='waiting'">等待安装...</div>
<progress *ngIf="currentApp.status.status === 'downloading'"
class="progress progress-striped progress-animated"
value="{{currentApp.status.progress}}" max="{{currentApp.status.total}}"></progress>
<div *ngIf="currentApp.status.status==='ready' && (currentApp.id != 'ygopro')">
<button (click)="startApp(currentApp)" type="button" class="btn btn-primary">运行</button>
<button type="button" data-toggle="modal" data-target="#settings-modal" class="btn btn-secondary">设置</button> <button type="button" data-toggle="modal" data-target="#settings-modal" class="btn btn-secondary">设置</button>
<!--<button (click)="appsService.browse(appsService.currentApp)" type="button" class="btn btn-secondary">游览本地文件</button>--> <!--<button (click)="appsService.browse(currentApp)" type="button" class="btn btn-secondary">游览本地文件</button>-->
<div id="network" *ngIf="appsService.currentApp.network && appsService.currentApp.network.protocol == 'maotama'"> <div id="network" *ngIf="currentApp.network && currentApp.network.protocol == 'maotama'">
<div class="input-group"> <div class="input-group">
<input *ngIf="appsService.connections.get(appsService.currentApp)" [value]="appsService.connections.get(appsService.currentApp).address || 'Loading...'" readonly type="text" class="form-control" aria-label="Text input with dropdown button" title="address"> <input *ngIf="appsService.connections.get(currentApp)"
[value]="appsService.connections.get(currentApp).address || 'Loading...'" readonly
type="text" class="form-control" aria-label="Text input with dropdown button" title="address">
<div class="input-group-btn"> <div class="input-group-btn">
<button *ngIf="!appsService.connections.get(appsService.currentApp)" (click)="appsService.network(appsService.currentApp, appsService.currentApp.network.servers[0])" type="button" class="btn btn-secondary"> <button *ngIf="!appsService.connections.get(currentApp)"
(click)="appsService.network(currentApp, currentApp.network.servers[0])"
type="button" class="btn btn-secondary">
联机 联机
</button> </button>
<button *ngIf="appsService.connections.get(appsService.currentApp)" (click)="copy(appsService.connections.get(appsService.currentApp).address)" [disabled]="!appsService.connections.get(appsService.currentApp).address" type="button" class="btn btn-secondary"> <button *ngIf="appsService.connections.get(currentApp)"
(click)="copy(appsService.connections.get(currentApp).address)"
[disabled]="!appsService.connections.get(currentApp).address" type="button"
class="btn btn-secondary">
复制 复制
</button> </button>
<button type="button" class="btn btn-secondary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" style="height: 38px;"> <button type="button" class="btn btn-secondary dropdown-toggle dropdown-toggle-split"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" style="height: 38px;">
<span class="sr-only">Toggle Dropdown</span> <span class="sr-only">Toggle Dropdown</span>
</button> </button>
<div class="dropdown-menu" [class.dropdown-menu-right]="appsService.connections.get(appsService.currentApp)"> <div class="dropdown-menu"
[class.dropdown-menu-right]="appsService.connections.get(currentApp)">
<h6 class="dropdown-header">选择服务器</h6> <h6 class="dropdown-header">选择服务器</h6>
<a *ngFor="let server of appsService.currentApp.network.servers" (click)="appsService.network(appsService.currentApp, server)" class="dropdown-item" href="#">{{server.id}}</a> <a *ngFor="let server of currentApp.network.servers"
(click)="appsService.network(currentApp, server)" class="dropdown-item"
href="#">{{server.id}}</a>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<ygopro *ngIf="isInstalled && (appsService.currentApp.id == 'ygopro')"></ygopro> <ygopro *ngIf="currentApp.status.status==='ready'&& (currentApp.id == 'ygopro')" [app]="currentApp"></ygopro>
<br> <br>
...@@ -82,9 +92,13 @@ ...@@ -82,9 +92,13 @@
<button type="button" class="btn btn-danger btn-sm">卸载</button> <button type="button" class="btn btn-danger btn-sm">卸载</button>
</td> </td>
<td *ngIf="!checkInstall(mod.id)"> <td *ngIf="!checkInstall(mod.id)">
<button *ngIf="!appsService.getDownloadInfo(mod.id)" (click)="install(mod.id)" type="button" class="btn btn-primary btn-sm">安装 <button *ngIf="!appsService.getDownloadInfo(mod.id)" (click)="install(mod.id)" type="button"
class="btn btn-primary btn-sm">安装
</button> </button>
<progress *ngIf="appsService.getDownloadInfo(mod.id) && appsService.getDownloadInfo(mod.id).status === 'active'" class="progress progress-striped progress-animated" value="{{appsService.getDownloadInfo(mod.id).progress}}" max="100"></progress> <progress
*ngIf="appsService.getDownloadInfo(mod.id) && appsService.getDownloadInfo(mod.id).status === 'active'"
class="progress progress-striped progress-animated"
value="{{appsService.getDownloadInfo(mod.id).progress}}" max="100"></progress>
<div *ngIf="appsService.getDownloadInfo(mod.id) && appsService.getDownloadInfo(mod.id).status === 'wait'"> <div *ngIf="appsService.getDownloadInfo(mod.id) && appsService.getDownloadInfo(mod.id).status === 'wait'">
等待安装... 等待安装...
</div> </div>
...@@ -97,10 +111,12 @@ ...@@ -97,10 +111,12 @@
</table> </table>
</div> </div>
<div *ngIf="isInstalled"> <div *ngIf="currentApp.isInstalled()">
<h2>本地文件</h2> <h2>本地文件</h2>
<button (click)="appsService.browse(appsService.currentApp)" type="button" class="btn btn-secondary">浏览本地文件</button> <button (click)="appsService.browse(currentApp)" type="button" class="btn btn-secondary">浏览本地文件</button>
<button (click)="uninstall()" type="button" class="btn btn-secondary">{{'uninstall'|translate}}</button> <button (click)="uninstall(currentApp.id)" type="button" class="btn btn-secondary">
{{'uninstall'|translate}}
</button>
</div> </div>
<div class="modal fade" id="settings-modal" tabindex="-1"> <div class="modal fade" id="settings-modal" tabindex="-1">
...@@ -133,7 +149,7 @@ ...@@ -133,7 +149,7 @@
</div> </div>
<div id="local-files" role="tabpanel" class="tab-pane fade"> <div id="local-files" role="tabpanel" class="tab-pane fade">
<div class="list-inline"> <div class="list-inline">
<button type="button" [disabled]="!isInstalled" (click)="uninstall()"> <button type="button" [disabled]="!currentApp.isInstalled()" (click)="uninstall()">
{{'uninstall'|translate}} {{'uninstall'|translate}}
</button> </button>
<i *ngIf="uninstalling" class="fa fa-circle-o-notch fa-spin fa-3x fa-fw"></i> <i *ngIf="uninstalling" class="fa fa-circle-o-notch fa-spin fa-3x fa-fw"></i>
...@@ -148,41 +164,46 @@ ...@@ -148,41 +164,46 @@
</div> </div>
</div> </div>
</div><!-- Modal --> </div><!-- Modal -->
<div class="modal fade" id="install-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" *ngIf="installConfig"> <div class="modal fade" id="install-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"
*ngIf="installConfig">
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
<form id="install-form" class="modal-content" (ngSubmit)="install()" #theForm="ngForm"> <form id="install-form" class="modal-content" (ngSubmit)="install()" #theForm="ngForm">
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"> <button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span> <span aria-hidden="true">&times;</span>
</button> </button>
<h4 class="modal-title" id="myModalLabel">{{'install'|translate}} {{name}}</h4> <h4 class="modal-title" id="myModalLabel">{{'install'|translate}} {{currentApp.name}}</h4>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<p>即将开始安装 {{name}}</p> <p>即将开始安装 {{currentApp.name}}</p>
<!-- 安装位置选择只在 windows 下存在, 为了方便调试暂时不加ngif --> <!-- 安装位置选择只在 windows 下存在, 为了方便调试暂时不加ngif -->
<h4>{{'install_path'|translate}}</h4> <h4>{{'install_path'|translate}}</h4>
<div class="form-group"> <div class="form-group">
<select class="form-control" name="installPath" [(ngModel)]="installConfig.installPath" title="path"> <select class="form-control" name="installPath" [(ngModel)]="installConfig.installLibrary"
<option *ngFor="let library of settingsService.getLibraries()" value="{{library['path']}}"> title="path">
{{ library['path']}} <option *ngFor="let library of libraries" value="{{library}}">
{{ library}}
</option> </option>
</select> </select>
</div> </div>
<h4>{{'shortcut'|translate}}</h4> <h4>{{'shortcut'|translate}}</h4>
<div class="checkbox"> <div class="checkbox">
<label> <label>
<input type="checkbox" name="application" [(ngModel)]="installConfig.createShortcut"> {{'create_shortcut'|translate}} <input type="checkbox" name="application" [(ngModel)]="installConfig.createShortcut">
{{'create_shortcut'|translate}}
</label> </label>
</div> </div>
<div class="checkbox"> <div class="checkbox">
<label> <label>
<input type="checkbox" name="desktop" [(ngModel)]="installConfig.createDesktopShortcut"> {{'create_desktop_shortcut'|translate}} <input type="checkbox" name="desktop" [(ngModel)]="installConfig.createDesktopShortcut">
{{'create_desktop_shortcut'|translate}}
</label> </label>
</div> </div>
<h4>{{'additions'|translate}}</h4> <h4>{{'additions'|translate}}</h4>
<div *ngFor="let reference of installConfig.references"> <div *ngFor="let reference of installConfig.references">
<label> <label>
<input type="checkbox" [(ngModel)]="reference.id" name="references" value="{{reference.id}}"> {{reference.name}} <input type="checkbox" [(ngModel)]="reference.install" name="references" value="{{reference.app.id}}">
{{reference.app.name}}
</label> </label>
</div> </div>
</div> </div>
......
import {Component, OnInit} from "@angular/core"; import {Component, OnInit, Input, ChangeDetectorRef} from "@angular/core";
import {AppsService} from "./apps.service"; import {AppsService} from "./apps.service";
import {InstallConfig} from "./install-config"; import {InstallConfig} from "./install-config";
import {SettingsService} from "./settings.sevices"; import {SettingsService} from "./settings.sevices";
import {App} from "./app"; import {App} from "./app";
import {DownloadService} from "./download.service"; import {DownloadService} from "./download.service";
import {clipboard, remote} from "electron"; import {clipboard, remote, ipcRenderer} from "electron";
import * as path from "path"; import * as path from "path";
import * as child_process from "child_process"; import * as child_process from "child_process";
import {InstallService} from "./install.service";
declare var Notification;
declare var $; declare var $;
@Component({ @Component({
selector: 'app-detail', selector: 'app-detail',
templateUrl: 'app/app-detail.component.html', templateUrl: 'app/app-detail.component.html',
styleUrls: ['app/app-detail.component.css'], styleUrls: ['app/app-detail.component.css'],
providers: [DownloadService]
}) })
export class AppDetailComponent implements OnInit { export class AppDetailComponent implements OnInit {
@Input()
currentApp: App;
platform = process.platform; platform = process.platform;
installConfig: InstallConfig; installConfig: InstallConfig;
constructor(private appsService: AppsService, private settingsService: SettingsService, private downloadService: DownloadService) { constructor(private appsService: AppsService, private settingsService: SettingsService,
private downloadService: DownloadService, private installService: InstallService,
private ref: ChangeDetectorRef) {
} }
ngOnInit() { ngOnInit() {
this.updateInstallConfig(); // this.updateInstallConfig();
ipcRenderer.on('download-message-reply', (event, arg)=> {
console.log(arg);
});
ipcRenderer.send("download-message", "ping")
} }
updateInstallConfig() { updateInstallConfig() {
this.installConfig = this.appsService.getInstallConfig(this.appsService.currentApp); this.installConfig = new InstallConfig(this.currentApp);
this.installConfig.installPath = this.settingsService.getDefaultLibrary().path; this.installConfig.installLibrary = this.settingsService.getDefaultLibrary().path;
} this.installConfig.references = [];
for (let reference of this.currentApp.references.values()) {
get name() { this.installConfig.references.push(new InstallConfig(reference))
let currentApp = this.appsService.currentApp;
if (currentApp) {
return currentApp.name[this.settingsService.getLocale()];
} }
return "Loading";
};
get isInstalled() {
let currentApp = this.appsService.currentApp;
return !!(currentApp.local && currentApp.local.path);
} }
get libraries(): string[] {
return this.settingsService.getLibraries().map((item)=>item.path);
}
get news() { get news() {
let currentApp = this.appsService.currentApp; return this.currentApp.news;
if (currentApp) {
return currentApp.news;
}
} }
get friends() { get friends() {
...@@ -63,35 +63,36 @@ export class AppDetailComponent implements OnInit { ...@@ -63,35 +63,36 @@ export class AppDetailComponent implements OnInit {
} }
get mods() { get mods() {
let contains = ["optional", "language", "emulator"]; // let contains = ["optional", "language", "emulator"];
//
let currentApp = this.appsService.currentApp; // let currentApp = this.appsService.currentApp;
if (currentApp) { // if (currentApp) {
if (currentApp.references[process.platform] && currentApp.references[process.platform].length > 0) { // if (currentApp.references[process.platform] && currentApp.references[process.platform].length > 0) {
let refs = currentApp.references[process.platform]; // let refs = currentApp.references[process.platform];
refs = refs.filter((ref)=> { // refs = refs.filter((ref)=> {
return contains.includes(ref.type); // return contains.includes(ref.type);
}); // });
refs = refs.map((ref)=> { // refs = refs.map((ref)=> {
let tmp = Object.create(ref); // let tmp = Object.create(ref);
switch (tmp.type) { // switch (tmp.type) {
case "optional": // case "optional":
tmp.type = "选项"; // tmp.type = "选项";
break; // break;
case "language": // case "language":
tmp.type = "语言"; // tmp.type = "语言";
break; // break;
default: // default:
break; // break;
} // }
//console.log(tmp.type); // //console.log(tmp.type);
return tmp; // return tmp;
}); // });
return refs; // return refs;
//return this.currentApp.references[process.platform]; //return this.currentApp.references[process.platform];
} // }
} // }
return [];
} }
uninstalling: boolean; uninstalling: boolean;
...@@ -99,23 +100,64 @@ export class AppDetailComponent implements OnInit { ...@@ -99,23 +100,64 @@ export class AppDetailComponent implements OnInit {
uninstall(id: string) { uninstall(id: string) {
if (confirm("确认删除?")) { if (confirm("确认删除?")) {
this.uninstalling = true; this.uninstalling = true;
this.appsService.uninstall(id).then(()=> { // this.appsService.uninstall(id).then(()=> {
this.uninstalling = false; // this.uninstalling = false;
} // }
); // );
} }
} }
async install() {
install() {
$('#install-modal').modal('hide'); $('#install-modal').modal('hide');
this.appsService.download();
let currentApp = this.currentApp;
let options = this.installConfig;
let dependencies = currentApp.findDependencies();
let apps = dependencies.concat(currentApp).filter((app)=>!app.isInstalled());
for (let reference of options.references) {
if (reference.install) {
apps.push(reference.app);
apps.push(...reference.app.findDependencies())
}
}
let downloadPath = path.join(this.installConfig.installLibrary, "downloading");
try {
let downloadApps = await this.downloadService.addUris(apps, downloadPath);
this.downloadService.getProgress(currentApp)
.subscribe((progress)=> {
currentApp.status.status = "downloading";
currentApp.status.progress = progress.progress;
currentApp.status.total = progress.total;
this.ref.detectChanges();
},
(error)=> {
},
()=> {
currentApp.status.status = "waiting";
this.ref.detectChanges();
});
await Promise.all(downloadApps.map((app)=> {
return this.downloadService.getComplete(app)
.then((completeApp: App)=> {
return this.installService.add(completeApp, options);
});
}));
currentApp.status.status = "ready";
} catch (e) {
new Notification(currentApp.name, {body: "下载失败"});
}
} }
selectDir() { selectDir() {
let dir = remote.dialog.showOpenDialog({properties: ['openFile', 'openDirectory']}); let dir = remote.dialog.showOpenDialog({properties: ['openFile', 'openDirectory']});
console.log(dir); console.log(dir);
this.appsService.installConfig.installDir = dir[0]; // this.appsService.installConfig.installDir = dir[0];
return dir[0]; return dir[0];
} }
...@@ -131,12 +173,8 @@ export class AppDetailComponent implements OnInit { ...@@ -131,12 +173,8 @@ export class AppDetailComponent implements OnInit {
let open = ''; let open = '';
let openApp = app.actions.get("main").open; let openApp = app.actions.get("main").open;
if (openApp) { if (openApp) {
if (this.isInstalled) { open = path.join(openApp.local.path, openApp.actions.get("main").execute);
open = path.join(openApp.local.path, openApp.actions.get("main").execute); args.push(execute);
args.push(execute);
} else {
console.error('open app not found');
}
} else { } else {
//没有需要通过open启动依赖,直接启动程序 //没有需要通过open启动依赖,直接启动程序
open = execute; open = execute;
......
...@@ -4,5 +4,24 @@ ...@@ -4,5 +4,24 @@
export class AppLocal { export class AppLocal {
path: string; path: string;
version: string; version: string;
files: string[]; files: Map<string,string>;
update(local) {
this.path = local.path;
this.version = local.version;
let files = new Map<string,string>();
for (let filename of Object.keys(local.files)) {
files.set(filename, local.files[filename]);
}
this.files = files;
}
toJSON() {
let t = {};
for (let [k,v] of this.files) {
t[k] = v;
}
return {path: this.path, version: this.version, files: t};
}
} }
import {AppLocal} from "./app-local"; import {AppLocal} from "./app-local";
/* export enum Category {
export enum Reference_Type { game, // 游戏
runtime, // directx music, // 音乐
emulator, // wine, np2 book, // 图书
dependency, // runtime, // 运行库
optional, // fxtz emulator, // 模拟器
language, language, // 语言包
host expansion, // 资料片
} module, // 创意工坊
*/ }
/*
export enum App_Category { // export enum Status{
game, // downloading,
music, // init,
book, // installing,
runtime, // directx // ready,
emulator, // wine, np2 // updating,
language // uninstalling,
} // waiting,
*/ // }
export class AppStatus {
progress: number;
total: number;
status: string;
}
export class App { export class App {
id: string; id: string;
name: string; // i18n _name: string; // i18n
get name() {
return this._name;
}
set name(a) {
this._name = a;
}
description: string; //i18n description: string; //i18n
author: string; // English Only author: string; // English Only
homepage: string; homepage: string;
category: string; category: Category;
parent: App; parent: App;
actions: Map<string,{execute: string, args: string[], env: {}, open: App}>; actions: Map<string,{execute: string, args: string[], env: {}, open: App}>;
references: Map<string,App>; references: Map<string,App>;
dependencies: Map<string,App>; dependencies: Map<string,App>;
locales: string[]; locales: string[];
download: {[platform: string]: string}; // meta4 url download: string; // meta4 url
news: {title: string, url: string, image: string}[]; news: {title: string, url: string, image: string}[];
network: any; network: any;
tags: string[]; tags: string[];
version: {[platform: string]: string}; version: string;
local: AppLocal; local: AppLocal;
status: AppStatus;
isInstalled(): boolean {
return this.local !== undefined;
}
constructor(app) { constructor(app) {
this.id = app.id; this.id = app.id;
...@@ -46,7 +64,7 @@ export class App { ...@@ -46,7 +64,7 @@ export class App {
this.description = app.description; this.description = app.description;
this.author = app.author; this.author = app.author;
this.homepage = app.homepage; this.homepage = app.homepage;
this.category = app.category; this.category = Category[app.category as string];
this.actions = app.actions; this.actions = app.actions;
this.dependencies = app.dependencies; this.dependencies = app.dependencies;
this.parent = app.parent; this.parent = app.parent;
...@@ -57,8 +75,20 @@ export class App { ...@@ -57,8 +75,20 @@ export class App {
this.network = app.network; this.network = app.network;
this.tags = app.tags; this.tags = app.tags;
this.version = app.version; this.version = app.version;
this.local = app.local;
} }
findDependencies(): App[] {
if (this.dependencies && this.dependencies.size > 0) {
let set = new Set();
for (let dependency of this.dependencies.values()) {
dependency.findDependencies()
.forEach((value)=> {
set.add(value);
});
set.add(dependency);
}
return Array.from(set);
}
return [];
}
} }
:host {
/*background-color: darkslategray;*/
width: 280px;
flex-shrink: 0;
overflow-y: auto;
background-color: #f5f5f5;
border-right: 1px solid #eee;
}
a {
display: block;
padding: 10px 20px 10px 20px;
}
.active {
background-color: #428bca;
}
.active > a {
color: #fff;
}
span {
margin-left: 8px;
}
\ No newline at end of file
<span *ngIf="grouped_apps.installed">已安装</span>
<ul *ngIf="grouped_apps.installed" class="nav nav-sidebar">
<li *ngFor="let app of grouped_apps.installed" [class.active]="app===appsService.currentApp">
<a (click)="chooseApp(app)" href="#">{{app.name}}</a>
</li>
</ul><span *ngIf="grouped_apps.yugioh">游戏王</span>
<ul *ngIf="grouped_apps.yugioh" class="nav nav-sidebar">
<li *ngFor="let app of grouped_apps.yugioh" [class.active]="app===appsService.currentApp">
<a (click)="chooseApp(app)" href="#">{{app.name}}</a>
</li>
</ul><span *ngIf="grouped_apps.touhou">东方 Project</span>
<ul *ngIf="grouped_apps.touhou" class="nav nav-sidebar">
<li *ngFor="let app of grouped_apps.touhou" [class.active]="app===appsService.currentApp">
<a (click)="chooseApp(app)" href="#">{{app.name}}</a>
</li>
</ul><span *ngIf="grouped_apps.touhou_pc98">东方旧作</span>
<ul *ngIf="grouped_apps.touhou_pc98" class="nav nav-sidebar">
<li *ngFor="let app of grouped_apps.touhou_pc98" [class.active]="app===appsService.currentApp">
<a (click)="chooseApp(app)" href="#">{{app.name}}</a>
</li>
</ul>
\ No newline at end of file
import {Component, OnInit} from "@angular/core";
import {AppsService} from "./apps.service";
import {App} from "./app";
@Component({
selector: 'apps',
templateUrl: 'app/apps.component.html',
styleUrls: ['app/apps.component.css'],
})
export class AppsComponent implements OnInit {
constructor(private appsService: AppsService) {
}
ngOnInit() {
}
chooseApp(app: App) {
this.appsService.currentApp = app;
}
get grouped_apps() {
let contains = ["game", "music", "book"];
let apps = Array.from(this.appsService.allApps.values());
let result = {};
for (let app of apps) {
if (contains.includes(app.category)) {
let tag;
if (app.local) {
tag = 'installed';
} else {
tag = app.tags[0];
}
if (!result[tag]) {
result[tag] = []
}
result[tag].push(app)
}
}
//console.log(result)
return result
}
}
\ No newline at end of file
import {Injectable, ApplicationRef} from "@angular/core"; import {Injectable, ApplicationRef} from "@angular/core";
import {Http} from "@angular/http"; import {Http} from "@angular/http";
import {App} from "./app"; import {App, AppStatus} from "./app";
import {InstallConfig} from "./install-config"; import {InstallConfig} from "./install-config";
import {SettingsService} from "./settings.sevices"; import {SettingsService} from "./settings.sevices";
import * as os from "os"; import * as os from "os";
...@@ -10,6 +10,9 @@ import * as readline from "readline"; ...@@ -10,6 +10,9 @@ import * as readline from "readline";
import * as mkdirp from "mkdirp"; import * as mkdirp from "mkdirp";
import * as child_process from "child_process"; import * as child_process from "child_process";
import {remote} from "electron"; import {remote} from "electron";
import "rxjs/Rx";
import {AppLocal} from "./app-local";
const Aria2 = require('aria2'); const Aria2 = require('aria2');
const Sudo = require('electron-sudo').default; const Sudo = require('electron-sudo').default;
...@@ -32,30 +35,13 @@ Sudo.prototype.fork = function (modulePath, args, options) { ...@@ -32,30 +35,13 @@ Sudo.prototype.fork = function (modulePath, args, options) {
@Injectable() @Injectable()
export class AppsService { export class AppsService {
installConfig: InstallConfig; constructor(private http: Http, private settingsService: SettingsService, private ref: ApplicationRef,) {
private _currentApp: App;
get currentApp(): App {
return this._currentApp;
} }
set currentApp(app: App) {
this._currentApp = app;
}
constructor(private http: Http, private settingsService: SettingsService, private ref: ApplicationRef) { // get allApps(): Map<string,App> {
this.loadApps(()=> { // return this.data;
if (this.data.size > 0) { // }
this.currentApp = this.data.get('ygopro');
}
});
}
private data: Map<string,App>;
get allApps(): Map<string,App> {
return this.data;
}
//[{"id": "th01", "gid": "aria2gid", "status": "active/install/complete/wait", "progress": "0-100"}] //[{"id": "th01", "gid": "aria2gid", "status": "active/install/complete/wait", "progress": "0-100"}]
downloadsInfo = []; downloadsInfo = [];
...@@ -96,11 +82,11 @@ export class AppsService { ...@@ -96,11 +82,11 @@ export class AppsService {
let tarObj = { let tarObj = {
id: this.downloadsInfo[index].id, id: this.downloadsInfo[index].id,
xzFile: res.files[0].path, xzFile: res.files[0].path,
installDir: this.installConfig.installPath // installDir: this.installConfig.installLibrary
}; };
new Promise((resolve)=> { new Promise((resolve)=> {
let refs = this.searchApp(this.downloadsInfo[index].id).references; // let refs = this.searchApp(this.downloadsInfo[index].id).references;
console.log(refs); // console.log(refs);
//[{"id": "th01", "wait":["wine", "dx"], resolve: resolve, tarObj: tarObj}] //[{"id": "th01", "wait":["wine", "dx"], resolve: resolve, tarObj: tarObj}]
let waitObj; let waitObj;
...@@ -124,7 +110,7 @@ export class AppsService { ...@@ -124,7 +110,7 @@ export class AppsService {
// } // }
// }); // });
// } // }
//console.log("wait obj:", waitObj); // console.log("wait obj:", waitObj);
if (waitObj) { if (waitObj) {
this.waitInstallQueue.push(waitObj); this.waitInstallQueue.push(waitObj);
...@@ -181,40 +167,15 @@ export class AppsService { ...@@ -181,40 +167,15 @@ export class AppsService {
return dir; return dir;
} }
loadApps(callback) { loadApps() {
this.http.get('./apps.json') return this.http.get('./apps.json')
.map(response => { .toPromise()
let apps = response.json(); .then((response)=> {
let localAppData = JSON.parse(localStorage.getItem("localAppData")); let data = response.json();
apps = apps.map((app: any)=> { return this.loadAppsList(data);
if (localAppData) {
localAppData.map((v)=> {
if (v.id === app.id) {
app.local = v.local;
}
});
}
return app;
});
return apps;
}).map(this.loadAppsList)
.subscribe((apps) => {
this.data = apps;
if (typeof(callback) === 'function') {
callback();
}
}); });
} }
getLocalString(app: App, tag: string): string {
let locale = this.settingsService.getLocale();
let value = app[tag][locale];
if (!value) {
value = app[tag]["en-US"];
}
return value;
}
loadAppsList = (data: any): Map<string,App> => { loadAppsList = (data: any): Map<string,App> => {
let apps = new Map<string,App>(); let apps = new Map<string,App>();
let locale = this.settingsService.getLocale(); let locale = this.settingsService.getLocale();
...@@ -222,6 +183,17 @@ export class AppsService { ...@@ -222,6 +183,17 @@ export class AppsService {
for (let item of data) { for (let item of data) {
let app = new App(item); let app = new App(item);
let local = localStorage.getItem(app.id);
if (local) {
app.local = new AppLocal();
app.local.update(JSON.parse(local));
}
app.status = new AppStatus();
if (local) {
app.status.status = "ready";
} else {
app.status.status = "init";
}
// 去除无关语言 // 去除无关语言
['name', 'description'].forEach((key)=> { ['name', 'description'].forEach((key)=> {
...@@ -233,7 +205,7 @@ export class AppsService { ...@@ -233,7 +205,7 @@ export class AppsService {
}); });
// 去除平台无关的内容 // 去除平台无关的内容
['actions', 'dependencies', 'references', 'download'].forEach((key)=> { ['actions', 'dependencies', 'references', 'download', 'version'].forEach((key)=> {
if (app[key]) { if (app[key]) {
if (app[key][platform]) { if (app[key][platform]) {
app[key] = app[key][platform]; app[key] = app[key][platform];
...@@ -265,31 +237,20 @@ export class AppsService { ...@@ -265,31 +237,20 @@ export class AppsService {
let value = app[key]; let value = app[key];
if (value) { if (value) {
if (Array.isArray(value)) { if (Array.isArray(value)) {
let map = new Map<string,App>();
value.forEach((appId, index, array)=> { value.forEach((appId, index, array)=> {
array[index] = apps.get(appId); map.set(appId, apps.get(appId));
}) });
app[key] = map;
} else { } else {
app[key] = apps.get(value); app[key] = apps.get(value);
} }
} }
}); });
} }
console.log(apps);
return apps; return apps;
}; };
searchApp(id): App {
return this.data.get(id);
}
checkInstall(id): boolean {
if (this.searchApp(id)) {
if (this.searchApp(id).local.path) {
return true;
}
}
return false;
}
deleteFile(path: string): Promise<string> { deleteFile(path: string): Promise<string> {
return new Promise((resolve, reject)=> { return new Promise((resolve, reject)=> {
...@@ -308,44 +269,53 @@ export class AppsService { ...@@ -308,44 +269,53 @@ export class AppsService {
}) })
} }
saveAppLocal(app: App, appLocal: AppLocal) {
localStorage.setItem(app.id, JSON.stringify(appLocal));
}
install(config: InstallConfig) {
let app = config.app;
}
uninstall(id: string) { uninstall(id: string) {
//let current = this; // //let current = this;
if (this.checkInstall(id)) { // if (this.checkInstall(id)) {
let files: string[] = this.searchApp(id).local.files.sort().reverse(); // let files: string[] = this.searchApp(id).local.files.sort().reverse();
// 删除本目录 // // 删除本目录
files.push('.'); // files.push('.');
let install_dir = this.searchApp(id).local.path; // let install_dir = this.searchApp(id).local.path;
return files // return files
.map((file)=> // .map((file)=>
()=>path.join(install_dir, file) // ()=>path.join(install_dir, file)
) // )
.reduce((promise: Promise<string>, task)=> // .reduce((promise: Promise<string>, task)=>
promise.then(task).then(this.deleteFile) // promise.then(task).then(this.deleteFile)
, Promise.resolve('')) // , Promise.resolve(''))
.then((value)=> { // .then((value)=> {
this.searchApp(id).local = null; // this.searchApp(id).local = null;
localStorage.setItem("localAppData", JSON.stringify(this.data)); // localStorage.setItem("localAppData", JSON.stringify(this.data));
}); // return Promise.resolve()
} // });
// }
} }
download() { download() {
let id = this.currentApp.id; // let id = this.currentApp.id;
if (this.downloadsInfo.findIndex((v)=> { // if (this.downloadsInfo.findIndex((v)=> {
return v.id == id // return v.id == id
}) !== -1) { // }) !== -1) {
console.log("this app is downloading") // console.log("this app is downloading")
} else { // } else {
let url = this.currentApp.download; // let url = this.currentApp.download;
this.aria2.addUri([url], {'dir': this.download_dir}, (error, gid)=> { // this.aria2.addUri([url], {'dir': this.download_dir}, (error, gid)=> {
console.log(error, gid); // console.log(error, gid);
if (error) { // if (error) {
console.error(error); // console.error(error);
} // }
this.downloadsInfo.push({"id": id, "gid": gid, "status": "active", "progress": 0}); // this.downloadsInfo.push({"id": id, "gid": gid, "status": "active", "progress": 0});
}); // });
} // }
} }
getDownloadInfo(id) { getDownloadInfo(id) {
...@@ -358,21 +328,6 @@ export class AppsService { ...@@ -358,21 +328,6 @@ export class AppsService {
} }
getInstallConfig(app: App): InstallConfig {
//let id = app.id;
this.installConfig = new InstallConfig(app);
let platform = process.platform;
let references: InstallConfig[] = [];
if (app.references[platform]) {
// app.references[platform].forEach((item)=> {
// references.push();
// });
}
this.installConfig.references = references;
return this.installConfig;
}
// tar // tar
tarQueue = []; tarQueue = [];
isExtracting = false; isExtracting = false;
...@@ -476,8 +431,8 @@ export class AppsService { ...@@ -476,8 +431,8 @@ export class AppsService {
this.downloadsInfo[downLoadsInfoIndex].status = "complete"; this.downloadsInfo[downLoadsInfoIndex].status = "complete";
// 为了卸载时能重新显示安装条 // 为了卸载时能重新显示安装条
this.downloadsInfo.splice(downLoadsInfoIndex, 1); this.downloadsInfo.splice(downLoadsInfoIndex, 1);
this.data.get(tarObj.id).local = appLocal.local; // this.data.get(tarObj.id).local = appLocal.local;
console.log(11111, this.data.get(tarObj.id), appLocal); // console.log(11111, this.data.get(tarObj.id), appLocal);
//[{"id": "th01", "wait":["wine", "dx"], resolve: resolve, tarObj: tarObj}] //[{"id": "th01", "wait":["wine", "dx"], resolve: resolve, tarObj: tarObj}]
this.waitInstallQueue = this.waitInstallQueue.map((waitObj)=> { this.waitInstallQueue = this.waitInstallQueue.map((waitObj)=> {
......
...@@ -2,24 +2,90 @@ ...@@ -2,24 +2,90 @@
* Created by weijian on 2016/10/26. * Created by weijian on 2016/10/26.
*/ */
import {Injectable} from "@angular/core"; import {Injectable, NgZone} from "@angular/core";
import {SettingsService} from "./settings.sevices"; import {Http} from "@angular/http";
import {ipcRenderer} from "electron"; import {Observable} from "rxjs/Observable";
import {EventEmitter} from "events";
import {App} from "./app";
const Aria2 = require('aria2');
@Injectable() @Injectable()
export class DownloadService { export class DownloadService {
aria2 = new Aria2();
baseURL = 'http://thief.mycard.moe/metalinks/'
appGidMap = new Map<App,string>();
gidAppMap = new Map<string,App>();
eventEmitter = new EventEmitter();
open = this.aria2.open();
constructor(private settingsService: SettingsService) { constructor(private ngZone: NgZone, private http: Http) {
ipcRenderer.send("download-message", "123"); this.aria2.onDownloadComplete = (gid)=> {
let app = this.gidAppMap.get(gid.gid);
if (app) {
this.appGidMap.delete(app);
this.gidAppMap.delete(gid.gid);
this.eventEmitter.emit(app.id, 'complete');
}
}
} }
sendEvent(event, args) { getComplete(app: App): Promise<App> {
ipcRenderer.send('') if (this.appGidMap.has(app)) {
return new Promise((resolve, reject)=> {
this.eventEmitter.once(app.id, (event)=> {
resolve(app);
})
});
}
} }
listenEvent() { getProgress(app: App): Observable<any> {
console.log(ipcRenderer); let gid = this.appGidMap.get(app);
return Observable.create((observer)=> {
let interval;
this.ngZone.runOutsideAngular(()=> {
interval = setInterval(()=> {
this.aria2.tellStatus(gid).then((status: any)=> {
if (status.status === 'complete') {
observer.complete();
} else if (status.status === "active") {
observer.next({total: status.totalLength, progress: status.completedLength})
} else if (status.status === "error") {
observer.error(status.errorCode)
}
});
}, 1000);
});
return ()=> {
clearInterval(interval);
}
});
} }
async addUris(apps: App[], path: string): Promise<App[]> {
let tasks = [];
for (let app of apps) {
let task = await this.addUri(app, path);
tasks.push(task);
}
return tasks;
}
async addUri(app: App, path: string): Promise<App> {
let id = app.id;
await this.open;
if (this.appGidMap.has(app)) {
return app;
} else {
let meta4link = `${this.baseURL}${id}.meta4`;
let response = await this.http.get(meta4link).toPromise();
let meta4 = btoa(response.text());
let gid = (await this.aria2.addMetalink(meta4, {dir: path}))[0];
this.appGidMap.set(app, gid);
this.gidAppMap.set(gid, app);
return app;
}
}
} }
...@@ -6,21 +6,18 @@ import {App} from "./app"; ...@@ -6,21 +6,18 @@ import {App} from "./app";
export class InstallConfig { export class InstallConfig {
app: App; app: App;
install: boolean; install: boolean;
installPath: string; installLibrary: string;
installDir: string; installDir: string;
createShortcut: boolean; createShortcut: boolean;
createDesktopShortcut: boolean; createDesktopShortcut: boolean;
references: InstallConfig[]; references: InstallConfig[];
constructor(app: App, installPath = ".", installDir = "", install = true, shortcut = false, desktopShortcut = false) { constructor(app: App, installLibrary = "", installDir = "", install = true, shortcut = false, desktopShortcut = false) {
this.app = app; this.app = app;
this.createShortcut = shortcut; this.createShortcut = shortcut;
this.createDesktopShortcut = desktopShortcut; this.createDesktopShortcut = desktopShortcut;
this.install = install; this.install = install;
this.installDir = installDir; this.installDir = installDir;
} this.installLibrary = installLibrary;
updateChecked() {
} }
} }
\ No newline at end of file
/**
* Created by weijian on 2016/11/2.
*/
import {Injectable} from "@angular/core";
import {App} from "./app";
import {InstallConfig} from "./install-config";
import * as path from "path";
import * as child_process from "child_process";
import * as mkdirp from "mkdirp";
import * as readline from "readline";
import * as fs from 'fs';
import {EventEmitter} from "events";
import {AppLocal} from "./app-local";
import {Http} from "@angular/http";
import ReadableStream = NodeJS.ReadableStream;
@Injectable()
export class InstallService {
tarPath: string;
installQueue: Map<App,InstallConfig> = new Map();
eventEmitter: EventEmitter = new EventEmitter();
installingQueue: Set<App> = new Set();
checksumUri = "http://thief.mycard.moe/checksums/";
constructor(private http: Http) {
if (process.platform === "win32") {
this.tarPath = path.join(process.resourcesPath, 'bin/tar.exe');
} else {
this.tarPath = "tar"
}
}
createDirectory(dir: string) {
return new Promise((resolve, reject)=> {
mkdirp(dir, resolve);
})
}
getComplete(app: App): Promise<App> {
return null;
}
extract(file: string, destPath: string) {
return new Promise((resolve, reject)=> {
let tarProcess = child_process.spawn(this.tarPath, ['xvf', file, '-C', destPath]);
let rl = readline.createInterface({
input: <ReadableStream>tarProcess.stderr,
});
rl.on('line', (input)=> {
});
tarProcess.on('exit', (code)=> {
if (code === 0) {
resolve();
} else {
reject(code);
}
})
});
}
async postInstall(app: App, appPath: string) {
let action = app.actions.get('install');
if (action) {
let env = Object.assign({}, action.env);
let command = [];
command.push(path.join(appPath, action.execute));
command.push(...action.args);
let open = action.open;
if (open) {
let openAction = open.actions.get("main");
env = Object.assign(env, openAction.env);
command.unshift(...openAction.args);
command.unshift(path.join(open.local.path, openAction.execute));
}
return new Promise((resolve, reject)=> {
let child = child_process.spawn(command.shift(), command, {
env: env,
stdio: 'inherit',
shell: true,
});
child.on('error', (error)=> {
console.log(error);
});
child.on('exit', (code)=> {
if (code === 0) {
resolve();
} else {
reject();
}
})
})
}
}
saveAppLocal(app: App) {
if (app.local) {
let a = JSON.stringify(app.local)
console.log(a);
localStorage.setItem(app.id, a);
}
}
async backupFiles(app: App, files: Iterable<string>) {
let backupPath = path.join(app.local.path, "backup");
await this.createDirectory(backupPath);
for (let file of files) {
await new Promise((resolve, reject)=> {
let oldPath = path.join(app.local.path, file);
let newPath = path.join(backupPath, file);
fs.rename(oldPath, newPath, resolve);
});
}
}
async doInstall() {
for (let app of this.installQueue.keys()) {
let depInstalled = app.findDependencies()
.every((dependency)=>dependency.isInstalled());
if (depInstalled && !this.installingQueue.has(app)) {
this.installingQueue.add(app);
let options = this.installQueue.get(app);
let checksumMap: Map<string,string> = await this.http.get(`${this.checksumUri}${app.id}`)
.map((response)=> {
let map = new Map<string,string>();
for (let line of response.text().split('\n')) {
if (line !== "") {
let [checksum,filename]=line.split(' ', 2);
map.set(filename, checksum);
}
}
return map;
}).toPromise();
let packagePath = path.join(options.installLibrary, 'downloading', `${app.id}.tar.xz`);
let destPath: string;
if (app.parent) {
let differenceSet = new Set<string>();
let parentFilesMap = app.parent.local.files;
for (let key of checksumMap.keys()) {
if (parentFilesMap.has(key)) {
differenceSet.add(key);
}
}
await this.backupFiles(app.parent, differenceSet);
destPath = app.parent.local.path;
} else {
destPath = path.join(options.installLibrary, app.id);
await this.createDirectory(destPath);
}
this.installQueue.delete(app);
await this.extract(packagePath, destPath);
await this.postInstall(app, destPath);
let local = new AppLocal();
local.path = destPath;
local.files = checksumMap;
local.version = app.version;
app.local = local;
this.saveAppLocal(app);
this.installingQueue.delete(app);
if (this.installQueue.size > 0) {
await this.doInstall()
}
}
}
}
add(app: App, options: InstallConfig) {
if (!this.installQueue.has(app)) {
this.installQueue.set(app, options);
if (!app.isInstalled()) {
this.doInstall()
}
}
}
}
\ No newline at end of file
...@@ -12,4 +12,30 @@ ...@@ -12,4 +12,30 @@
background-color: #336699; background-color: #336699;
height: 236px; height: 236px;
flex-shrink: 0; flex-shrink: 0;
}
#apps{
/*background-color: darkslategray;*/
width: 280px;
flex-shrink: 0;
overflow-y: auto;
background-color: #f5f5f5;
border-right: 1px solid #eee;
}
a {
display: block;
padding: 10px 20px 10px 20px;
}
.active {
background-color: #428bca;
}
.active > a {
color: #fff;
}
span {
margin-left: 8px;
} }
\ No newline at end of file
<!-- Begin page content --> <!-- Begin page content -->
<div id="main"> <div id="main">
<apps *ngIf="appsService.allApps"></apps> <div id="apps" *ngIf="apps">
<app-detail *ngIf="appsService._currentApp"></app-detail> <span *ngIf="grouped_apps.installed">已安装</span>
<ul *ngIf="grouped_apps.installed" class="nav nav-sidebar">
<li *ngFor="let app of grouped_apps.installed" [class.active]="app===currentApp">
<a (click)="chooseApp(app)" href="#">{{app.name}}</a>
</li>
</ul>
<span *ngIf="grouped_apps.yugioh">游戏王</span>
<ul *ngIf="grouped_apps.yugioh" class="nav nav-sidebar">
<li *ngFor="let app of grouped_apps.yugioh" [class.active]="app===currentApp">
<a (click)="chooseApp(app)" href="#">{{app.name}}</a>
</li>
</ul>
<span *ngIf="grouped_apps.touhou">东方 Project</span>
<ul *ngIf="grouped_apps.touhou" class="nav nav-sidebar">
<li *ngFor="let app of grouped_apps.touhou" [class.active]="app===currentApp">
<a (click)="chooseApp(app)" href="#">{{app.name}}</a>
</li>
</ul>
<span *ngIf="grouped_apps.touhou_pc98">东方旧作</span>
<ul *ngIf="grouped_apps.touhou_pc98" class="nav nav-sidebar">
<li *ngFor="let app of grouped_apps.touhou_pc98" [class.active]="app===currentApp">
<a (click)="chooseApp(app)" href="#">{{app.name}}</a>
</li>
</ul>
</div>
<app-detail *ngIf="currentApp" [currentApp]="currentApp"></app-detail>
<roster></roster> <roster></roster>
</div> </div>
<webview id="candy" [src]="candy_url" nodeintegration></webview> <webview id="candy" [src]="candy_url" nodeintegration></webview>
\ No newline at end of file
/** /**
* Created by zh99998 on 16/9/2. * Created by zh99998 on 16/9/2.
*/ */
import {Component} from "@angular/core"; import {Component, OnInit} from "@angular/core";
import {AppsService} from "./apps.service"; import {AppsService} from "./apps.service";
import {LoginService} from "./login.service"; import {LoginService} from "./login.service";
import {App, Category} from "./app";
import {DownloadService} from "./download.service";
@Component({ @Component({
selector: 'lobby', selector: 'lobby',
templateUrl: 'app/lobby.component.html', templateUrl: 'app/lobby.component.html',
styleUrls: ['app/lobby.component.css'], styleUrls: ['app/lobby.component.css'],
}) })
export class LobbyComponent { export class LobbyComponent implements OnInit {
candy_url; candy_url: string;
currentApp: App;
private apps: Map<string,App>;
constructor(private appsService: AppsService, private loginService: LoginService) { constructor(private appsService: AppsService, private loginService: LoginService,private downloadService:DownloadService) {
this.candy_url = './candy/index.html?jid=' + this.loginService.user.username + '@mycard.moe&password=' + this.loginService.user.external_id + '&nickname=' + this.loginService.user.username + '&autojoin=ygopro_china_north@conference.mycard.moe' this.candy_url = './candy/index.html?jid=' + this.loginService.user.username + '@mycard.moe&password=' + this.loginService.user.external_id + '&nickname=' + this.loginService.user.username + '&autojoin=ygopro_china_north@conference.mycard.moe'
} }
ngOnInit() {
this.appsService.loadApps()
.then((apps)=> {
this.apps = apps;
this.currentApp = this.apps.get("th06");
})
}
chooseApp(app: App) {
this.currentApp = app;
}
get grouped_apps() {
let contains = ["game", "music", "book"].map((value)=>Category[value]);
let result = {};
for (let app of this.apps.values()) {
if (contains.includes(app.category)) {
let tag;
if (app.isInstalled()) {
tag = 'installed';
} else {
tag = app.tags[0];
}
if (!result[tag]) {
result[tag] = []
}
result[tag].push(app)
}
}
return result
}
} }
...@@ -6,7 +6,6 @@ import {MyCardComponent} from "./mycard.component"; ...@@ -6,7 +6,6 @@ import {MyCardComponent} from "./mycard.component";
import {LoginComponent} from "./login.component"; import {LoginComponent} from "./login.component";
import {StoreComponent} from "./store.component"; import {StoreComponent} from "./store.component";
import {LobbyComponent} from "./lobby.component"; import {LobbyComponent} from "./lobby.component";
import {AppsComponent} from "./apps.component";
import {AppDetailComponent} from "./app-detail.component"; import {AppDetailComponent} from "./app-detail.component";
import {RosterComponent} from "./roster.component"; import {RosterComponent} from "./roster.component";
import {CommunityComponent} from "./community.component"; import {CommunityComponent} from "./community.component";
...@@ -15,12 +14,20 @@ import {AppsService} from "./apps.service"; ...@@ -15,12 +14,20 @@ import {AppsService} from "./apps.service";
import {TranslateModule} from "ng2-translate"; import {TranslateModule} from "ng2-translate";
import {SettingsService} from "./settings.sevices"; import {SettingsService} from "./settings.sevices";
import {LoginService} from "./login.service"; import {LoginService} from "./login.service";
import {DownloadService} from "./download.service";
import {InstallService} from "./install.service";
@NgModule({ @NgModule({
imports: [BrowserModule, FormsModule, ReactiveFormsModule, HttpModule, TranslateModule.forRoot()], imports: [BrowserModule, FormsModule, ReactiveFormsModule, HttpModule, TranslateModule.forRoot()],
declarations: [MyCardComponent, LoginComponent, StoreComponent, LobbyComponent, CommunityComponent, AppsComponent, AppDetailComponent, RosterComponent, YGOProComponent], declarations: [
MyCardComponent, LoginComponent, StoreComponent, LobbyComponent,
CommunityComponent, AppDetailComponent, RosterComponent, YGOProComponent,
],
bootstrap: [MyCardComponent], bootstrap: [MyCardComponent],
providers: [AppsService, SettingsService, LoginService], providers: [
AppsService, SettingsService, LoginService, DownloadService,
InstallService
],
schemas: [NO_ERRORS_SCHEMA] schemas: [NO_ERRORS_SCHEMA]
}) })
export class MyCard { export class MyCard {
......
...@@ -3,16 +3,32 @@ ...@@ -3,16 +3,32 @@
*/ */
import {Injectable} from "@angular/core"; import {Injectable} from "@angular/core";
import {remote} from "electron";
import * as path from "path";
@Injectable() @Injectable()
export class SettingsService { export class SettingsService {
static SETTING_LIBRARY = "library"; static SETTING_LIBRARY = "library";
libraries: [{"default": boolean,path: string}]; static defaultLibraries = [
{
"default": true,
path: path.join(remote.app.getPath("appData"), "library")
},
];
libraries: {"default": boolean,path: string}[];
getLibraries() { getLibraries() {
if (!this.libraries) { if (!this.libraries) {
let data = localStorage.getItem(SettingsService.SETTING_LIBRARY); let data = localStorage.getItem(SettingsService.SETTING_LIBRARY);
this.libraries = JSON.parse(data); if (!data) {
this.libraries = SettingsService.defaultLibraries;
localStorage.setItem(SettingsService.SETTING_LIBRARY,
JSON.stringify(SettingsService.defaultLibraries));
} else {
this.libraries = JSON.parse(data);
}
} }
return this.libraries; return this.libraries;
} }
...@@ -25,16 +41,23 @@ export class SettingsService { ...@@ -25,16 +41,23 @@ export class SettingsService {
} }
static SETTING_LOCALE = "locale"; static SETTING_LOCALE = "locale";
static defaultLocale = remote.app.getLocale();
locale: string; locale: string;
getLocale(): string { getLocale(): string {
if (!this.locale) { if (!this.locale) {
this.locale = localStorage.getItem(SettingsService.SETTING_LOCALE); let locale = localStorage.getItem(SettingsService.SETTING_LOCALE);
if (!locale) {
this.locale = SettingsService.defaultLocale;
localStorage.setItem(SettingsService.SETTING_LOCALE, SettingsService.defaultLocale);
} else {
this.locale = locale;
}
} }
return this.locale; return this.locale;
} }
setLocal(locale: string) { setLocale(locale: string) {
this.locale = locale; this.locale = locale;
localStorage.setItem(SettingsService.SETTING_LOCALE, locale); localStorage.setItem(SettingsService.SETTING_LOCALE, locale);
} }
......
/** /**
* Created by zh99998 on 16/9/2. * Created by zh99998 on 16/9/2.
*/ */
import {Component, OnInit, ChangeDetectorRef} from "@angular/core"; import {Component, OnInit, ChangeDetectorRef, Input} from "@angular/core";
import {AppsService} from "./apps.service"; import {AppsService} from "./apps.service";
import * as fs from "fs"; import * as fs from "fs";
import * as path from "path"; import * as path from "path";
...@@ -11,6 +11,7 @@ import {remote} from "electron"; ...@@ -11,6 +11,7 @@ import {remote} from "electron";
import * as ini from "ini"; import * as ini from "ini";
import {EncodeOptions} from "ini"; import {EncodeOptions} from "ini";
import {LoginService} from "./login.service"; import {LoginService} from "./login.service";
import {App} from "./app";
import {Http, Headers, URLSearchParams} from "@angular/http"; import {Http, Headers, URLSearchParams} from "@angular/http";
import "rxjs/Rx"; import "rxjs/Rx";
import {ISubscription} from "rxjs/Subscription"; import {ISubscription} from "rxjs/Subscription";
...@@ -70,7 +71,8 @@ interface Room { ...@@ -70,7 +71,8 @@ interface Room {
styleUrls: ['app/ygopro.component.css'], styleUrls: ['app/ygopro.component.css'],
}) })
export class YGOProComponent implements OnInit { export class YGOProComponent implements OnInit {
app = this.appsService.searchApp('ygopro'); @Input()
app: App;
decks: string[] = []; decks: string[] = [];
current_deck: string; current_deck: string;
......
...@@ -94,8 +94,11 @@ ...@@ -94,8 +94,11 @@
"language" "language"
], ],
"dependencies": { "dependencies": {
"win32": [], "win32": [
"th06"
],
"darwin": [ "darwin": [
"th06",
"wine" "wine"
] ]
}, },
...@@ -1384,6 +1387,7 @@ ...@@ -1384,6 +1387,7 @@
} }
}, },
"version": { "version": {
"win32": "1.06",
"darwin": "1.06" "darwin": "1.06"
}, },
"download": { "download": {
...@@ -2188,6 +2192,7 @@ ...@@ -2188,6 +2192,7 @@
} }
}, },
"version": { "version": {
"win32": "1.06",
"darwin": "1.06" "darwin": "1.06"
}, },
"download": { "download": {
......
...@@ -132,7 +132,9 @@ function createAria2c() { ...@@ -132,7 +132,9 @@ function createAria2c() {
throw 'unsupported platform'; throw 'unsupported platform';
} }
//--split=10 --min-split-size=1M --max-connection-per-server=10 //--split=10 --min-split-size=1M --max-connection-per-server=10
let aria2c = child_process.spawn(aria2c_path, ['--enable-rpc', '--rpc-allow-origin-all', "--continue", "--split=10", "--min-split-size=1M", "--max-connection-per-server=10"]); let aria2c = child_process.spawn(aria2c_path,
['--enable-rpc', '--rpc-allow-origin-all', "--continue", "--split=10", "--min-split-size=1M", "--max-connection-per-server=10"],
{stdio: 'ignore'});
aria2c.on('data', (data)=> { aria2c.on('data', (data)=> {
console.log(data); console.log(data);
}); });
......
...@@ -66,6 +66,18 @@ ...@@ -66,6 +66,18 @@
"provider": "github" "provider": "github"
} }
], ],
"extraResources": [
"bin"
],
"publish": [
{
"provider": "generic",
"url": "https://wudizhanche.mycard.moe/downloads"
},
{
"provider": "github"
}
],
"win": { "win": {
"target": [ "target": [
"nsis" "nsis"
......
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