Commit 4abe323c authored by 神楽坂玲奈's avatar 神楽坂玲奈

Revert "update dependencies"

This reverts commit cd8508f4.
parent a6a5a285
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -4,41 +4,41 @@
"license": "UNLISENCED",
"scripts": {
"ng": "ng",
"start": "ng serve --base-href /mobile/ --deploy-url /mobile/ --locale zh-CN --output-path mobile --open",
"start": "ng serve --base-href /mobile/ --deploy-url /mobile --locale zh-CN --output-path mobile --open",
"build": "ng build --base-href /mobile/ --locale zh-CN --aot --build-optimizer --extract-css --prod",
"build:dev": "ng build --base-href /mobile2/ --locale zh-CN --aot --build-optimizer --extract-css",
"lint": "ng lint --type-check --fix"
},
"dependencies": {
"@angular/animations": "5.2.10",
"@angular/cdk": "^5.2.5",
"@angular/common": "5.2.10",
"@angular/compiler": "5.2.10",
"@angular/core": "5.2.10",
"@angular/forms": "5.2.10",
"@angular/http": "5.2.10",
"@angular/material": "^5.2.5",
"@angular/platform-browser": "5.2.10",
"@angular/platform-browser-dynamic": "5.2.10",
"@angular/router": "5.2.10",
"core-js": "^2.5.5",
"@angular/animations": "^4.3.6",
"@angular/cdk": "^2.0.0-beta.8",
"@angular/common": "^4.3.6",
"@angular/compiler": "^4.3.6",
"@angular/core": "^4.3.6",
"@angular/forms": "^4.3.6",
"@angular/http": "^4.3.6",
"@angular/material": "^2.0.0-beta.8",
"@angular/platform-browser": "^4.3.6",
"@angular/platform-browser-dynamic": "^4.3.6",
"@angular/router": "^4.3.6",
"core-js": "^2.5.0",
"font-awesome": "^4.7.0",
"hammerjs": "^2.0.8",
"lodash": "^4.17.10",
"lodash": "^4.17.4",
"material-design-icons": "^3.0.1",
"rxjs": "^5.5.10",
"webdav": "^1.5.2",
"zone.js": "^0.8.26"
"rxjs": "^5.4.3",
"webdav": "https://github.com/moecube/webdav-client/releases/download/v1.0.1/webdav-1.0.1.tgz",
"zone.js": "^0.8.17"
},
"devDependencies": {
"@angular/cli": "1.7.4",
"@angular/compiler-cli": "5.2.10",
"@angular/language-service": "5.2.10",
"@angular/service-worker": "5.2.10",
"@types/lodash": "^4.14.108",
"@types/node": "^9.6.6",
"codelyzer": "^4.3.0",
"tslint": "^5.9.1",
"typescript": "2.6.2"
"@angular/cli": "^1.3.2",
"@angular/compiler-cli": "^4.3.6",
"@angular/language-service": "^4.3.6",
"@angular/service-worker": "^1.0.0-beta.16",
"@types/lodash": "^4.14.74",
"@types/node": "^8.0.25",
"codelyzer": "~3.1.1",
"tslint": "^5.6.0",
"typescript": "~2.3.3"
}
}
module.exports = {
printWidth: 140,
singleQuote: true
};
import { CdkTableModule } from '@angular/cdk';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpModule, JsonpModule } from '@angular/http';
import {
MatAutocompleteModule,
MatButtonModule,
MatCardModule,
MatCheckboxModule,
MatDialogModule,
MatGridListModule,
MatIconModule,
MatInputModule,
MatListModule,
MatMenuModule,
MatProgressSpinnerModule,
MatSelectModule,
MatSlideToggleModule,
MatSnackBarModule,
MatTableModule,
MatToolbarModule
MdAutocompleteModule,
MdButtonModule,
MdCardModule,
MdCheckboxModule,
MdDialogModule,
MdGridListModule,
MdIconModule,
MdInputModule,
MdListModule,
MdMenuModule,
MdProgressSpinnerModule,
MdSelectModule,
MdSlideToggleModule,
MdSnackBarModule,
MdTableModule,
MdToolbarModule
} from '@angular/material';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
......@@ -55,27 +56,29 @@ import { YGOProService } from './ygopro.service';
HttpModule,
AppRoutingModule,
BrowserAnimationsModule,
MatInputModule,
MatSelectModule,
MatCheckboxModule,
MatButtonModule,
MatSlideToggleModule,
MatCardModule,
MatGridListModule,
MatIconModule,
MatTableModule,
MatListModule,
MatDialogModule,
MatToolbarModule,
MatSnackBarModule,
MatAutocompleteModule,
MdInputModule,
MdSelectModule,
MdCheckboxModule,
MdButtonModule,
MdSlideToggleModule,
MdCardModule,
MdGridListModule,
MdIconModule,
MdTableModule,
CdkTableModule,
MdListModule,
MdDialogModule,
MdToolbarModule,
MdSnackBarModule,
MdAutocompleteModule,
ReactiveFormsModule,
JsonpModule,
MatMenuModule,
MatProgressSpinnerModule
MdMenuModule,
MdProgressSpinnerModule
],
providers: [YGOProService, StorageService],
bootstrap: [AppComponent],
entryComponents: [MatchDialogComponent, ResultDialogComponent]
})
export class AppModule {}
export class AppModule {
}
......@@ -35,33 +35,33 @@ input::placeholder {
/*color: lightgray;*/
/*}*/
mat-input-container {
md-input-container {
width: 100%;
}
[mat-raised-button] {
[md-raised-button] {
border-radius: 0;
box-shadow: none;
}
[mat-button], [mat-raised-button] {
[md-button], [md-raised-button] {
width: 100%;
height: 100%;
}
a[mat-button], a[mat-raised-button] {
a[md-button], a[md-raised-button] {
display: flex;
align-items: center;
justify-content: center;
}
mat-card-content {
md-card-content {
display: flex;
flex-direction: row;
}
[mat-card-avatar] {
[md-card-avatar] {
width: 128px;
height: 72px;
object-fit: cover;
......
<!--https://github.com/google/material-design-icons/blob/master/iconfont/codepoints-->
<mat-toolbar color="primary">
<button id="menu" mat-icon-button (click)="ygopro.openDrawer()">
<mat-icon>menu</mat-icon>
<md-toolbar color="primary">
<button id="menu" md-icon-button (click)="ygopro.openDrawer()">
<md-icon>menu</md-icon>
</button>
<form (submit)="search(key)">
<input type=search placeholder="卡片搜索" name="key" [(ngModel)]="key" matAutocomplete="auto" [formControl]="searchCtrl">
<input type=search placeholder="卡片搜索" name="key" [(ngModel)]="key" mdAutocomplete="auto" [formControl]="searchCtrl">
<mat-autocomplete #auto="matAutocomplete">
<mat-option *ngFor="let card of suggestion | async" [value]="card" (onSelectionChange)="search(card)">
<md-autocomplete #auto="mdAutocomplete">
<md-option *ngFor="let card of suggestion | async" [value]="card" (onSelectionChange)="search(card)">
{{ card }}
</mat-option>
</mat-autocomplete>
</md-option>
</md-autocomplete>
</form>
<button mat-icon-button *ngIf="storage.working">
<mat-icon class="fa-spin">sync</mat-icon>
<button md-icon-button *ngIf="storage.working">
<md-icon class="fa-spin">sync</md-icon>
</button>
<a href="https://accounts.moecube.com/profiles" target="_blank" mat-icon-button>
<a href="https://accounts.moecube.com/profiles" target="_blank" md-icon-button>
<img id="avatar" [src]="login.user.avatar_url">
</a>
<button mat-icon-button [matMenuTriggerFor]="menu">
<mat-icon>add</mat-icon>
<button md-icon-button [mdMenuTriggerFor]="menu">
<md-icon>add</md-icon>
</button>
<mat-menu #menu="matMenu">
<a [href]="login.logout()" mat-menu-item>切换用户</a>
<button mat-menu-item>大厅版本 {{version}}</button>
<button mat-menu-item *ngIf="build">应用版本 {{build.version_name}}</button>
</mat-menu>
</mat-toolbar>
<md-menu #menu="mdMenu">
<a [href]="login.logout()" md-menu-item>切换用户</a>
<button md-menu-item>大厅版本 {{version}}</button>
<button md-menu-item *ngIf="build">应用版本 {{build.version_name}}</button>
</md-menu>
</md-toolbar>
<mat-grid-list cols="4" rowHeight="100px" gutterSize="0">
<!--<mat-grid-tile>-->
<!--<a href="https://accounts.moecube.com/profiles" id="avatar" mat-raised-button [style.background-image]="'url(' + login.user.avatar_url + ')'">{{login.user.username}}</a>-->
<!--</mat-grid-tile>-->
<mat-grid-tile>
<button mat-raised-button color="primary" (click)="ygopro.request_match('athletic')">
<mat-icon fontSet="fa" fontIcon="fa-futbol-o"></mat-icon>
<md-grid-list cols="4" rowHeight="100px" gutterSize="0">
<!--<md-grid-tile>-->
<!--<a href="https://accounts.moecube.com/profiles" id="avatar" md-raised-button [style.background-image]="'url(' + login.user.avatar_url + ')'">{{login.user.username}}</a>-->
<!--</md-grid-tile>-->
<md-grid-tile>
<button md-raised-button color="primary" (click)="ygopro.request_match('athletic')">
<md-icon fontSet="fa" fontIcon="fa-futbol-o"></md-icon>
<br>竞技匹配
</button>
</mat-grid-tile>
<mat-grid-tile>
<button mat-raised-button color="primary" (click)="ygopro.request_match('entertain')">
<mat-icon>toys</mat-icon>
</md-grid-tile>
<md-grid-tile>
<button md-raised-button color="primary" (click)="ygopro.request_match('entertain')">
<md-icon>toys</md-icon>
<br>娱乐匹配
</button>
</mat-grid-tile>
<mat-grid-tile><a mat-raised-button color="primary" routerLink="/ygopro/rooms">
<mat-icon>games</mat-icon>
<br>房间列表</a></mat-grid-tile>
<mat-grid-tile><a mat-raised-button color="primary" routerLink="/ygopro/rooms/new">
<mat-icon>&#xe146;</mat-icon><!--add_box-->
<br>创建房间</a></mat-grid-tile>
<mat-grid-tile><a mat-raised-button routerLink="/ygopro/windbot">
<mat-icon>&#xe195;</mat-icon><!-- airplanemode_active -->
<br>单人模式</a></mat-grid-tile>
<mat-grid-tile><a mat-raised-button routerLink="/ygopro/watch">
<mat-icon>&#xe417;</mat-icon><!--remove_red_eye-->
<br>观战</a></mat-grid-tile>
<!--<mat-grid-tile>-->
<!--<button mat-raised-button (click)="ygopro.watch_replay()">-->
<!--<mat-icon>history</mat-icon>-->
</md-grid-tile>
<md-grid-tile><a md-raised-button color="primary" routerLink="/ygopro/rooms">
<md-icon>games</md-icon>
<br>房间列表</a></md-grid-tile>
<md-grid-tile><a md-raised-button color="primary" routerLink="/ygopro/rooms/new">
<md-icon>&#xe146;</md-icon><!--add_box-->
<br>创建房间</a></md-grid-tile>
<md-grid-tile><a md-raised-button routerLink="/ygopro/windbot">
<md-icon>&#xe195;</md-icon><!-- airplanemode_active -->
<br>单人模式</a></md-grid-tile>
<md-grid-tile><a md-raised-button routerLink="/ygopro/watch">
<md-icon>&#xe417;</md-icon><!--remove_red_eye-->
<br>观战</a></md-grid-tile>
<!--<md-grid-tile>-->
<!--<button md-raised-button (click)="ygopro.watch_replay()">-->
<!--<md-icon>history</md-icon>-->
<!--<br>观看录像-->
<!--</button>-->
<!--</mat-grid-tile>-->
<mat-grid-tile>
<button mat-raised-button (click)="ygopro.edit_deck()">
<mat-icon>edit</mat-icon>
<!--</md-grid-tile>-->
<md-grid-tile>
<button md-raised-button (click)="ygopro.edit_deck()">
<md-icon>edit</md-icon>
<br>编辑卡组
</button>
</mat-grid-tile>
<mat-grid-tile><a mat-raised-button href="https://ygobbs.com" target="_blank">
<mat-icon>forum</mat-icon>
<br>社区</a></mat-grid-tile>
<mat-grid-tile><a mat-raised-button [href]="arena_url" target="_blank">
<mat-icon fontSet="fa" fontIcon="fa-trophy"></mat-icon>
<br>决斗数据库</a></mat-grid-tile>
<mat-grid-tile>
<button mat-raised-button (click)="ygopro.backHome()"><span class="icon">233</span><br>直连</button>
</mat-grid-tile>
</mat-grid-list>
</md-grid-tile>
<md-grid-tile><a md-raised-button href="https://ygobbs.com" target="_blank">
<md-icon>forum</md-icon>
<br>社区</a></md-grid-tile>
<md-grid-tile><a md-raised-button [href]="arena_url" target="_blank">
<md-icon fontSet="fa" fontIcon="fa-trophy"></md-icon>
<br>决斗数据库</a></md-grid-tile>
<md-grid-tile>
<button md-raised-button (click)="ygopro.backHome()"><span class="icon">233</span><br>直连</button>
</md-grid-tile>
</md-grid-list>
<mat-card *ngIf="ygopro.points">
<mat-grid-list id="points" cols="4" rowHeight="20px">
<mat-grid-tile>
<md-card *ngIf="ygopro.points">
<md-grid-list id="points" cols="4" rowHeight="20px">
<md-grid-tile>
<dt>竞技排名</dt>
</mat-grid-tile>
<mat-grid-tile>
</md-grid-tile>
<md-grid-tile>
<dd>{{ygopro.points.arena_rank}}</dd>
</mat-grid-tile>
<mat-grid-tile>
</md-grid-tile>
<md-grid-tile>
<dt>娱乐排名</dt>
</mat-grid-tile>
<mat-grid-tile>
</md-grid-tile>
<md-grid-tile>
<dd>{{ygopro.points.exp_rank}}</dd>
</mat-grid-tile>
<mat-grid-tile>
</md-grid-tile>
<md-grid-tile>
<dt>竞技胜率</dt>
</mat-grid-tile>
<mat-grid-tile>
</md-grid-tile>
<md-grid-tile>
<dd>{{ygopro.points.athletic_wl_ratio}}%</dd>
</mat-grid-tile>
<mat-grid-tile>
</md-grid-tile>
<md-grid-tile>
<dt>经验</dt>
</mat-grid-tile>
<mat-grid-tile>
</md-grid-tile>
<md-grid-tile>
<dd>{{ygopro.points.exp}}</dd>
</mat-grid-tile>
<mat-grid-tile>
</md-grid-tile>
<md-grid-tile>
<dt>胜场</dt>
</mat-grid-tile>
<mat-grid-tile>
</md-grid-tile>
<md-grid-tile>
<dd>{{ygopro.points.athletic_win}}</dd>
</mat-grid-tile>
<mat-grid-tile>
</md-grid-tile>
<md-grid-tile>
<dt>胜场</dt>
</mat-grid-tile>
<mat-grid-tile>
</md-grid-tile>
<md-grid-tile>
<dd>{{ygopro.points.entertain_win}}</dd>
</mat-grid-tile>
<mat-grid-tile>
</md-grid-tile>
<md-grid-tile>
<dt>负场</dt>
</mat-grid-tile>
<mat-grid-tile>
</md-grid-tile>
<md-grid-tile>
<dd>{{ygopro.points.athletic_lose}}</dd>
</mat-grid-tile>
<mat-grid-tile>
</md-grid-tile>
<md-grid-tile>
<dt>负场</dt>
</mat-grid-tile>
<mat-grid-tile>
</md-grid-tile>
<md-grid-tile>
<dd>{{ygopro.points.entertain_lose}}</dd>
</mat-grid-tile>
<mat-grid-tile>
</md-grid-tile>
<md-grid-tile>
<dt>平局</dt>
</mat-grid-tile>
<mat-grid-tile>
</md-grid-tile>
<md-grid-tile>
<dd>{{ygopro.points.athletic_draw}}</dd>
</mat-grid-tile>
<mat-grid-tile>
</md-grid-tile>
<md-grid-tile>
<dt>平局</dt>
</mat-grid-tile>
<mat-grid-tile>
</md-grid-tile>
<md-grid-tile>
<dd>{{ygopro.points.entertain_draw}}</dd>
</mat-grid-tile>
<mat-grid-tile>
</md-grid-tile>
<md-grid-tile>
<dt>总场</dt>
</mat-grid-tile>
<mat-grid-tile>
</md-grid-tile>
<md-grid-tile>
<dd>{{ygopro.points.athletic_all}}</dd>
</mat-grid-tile>
<mat-grid-tile>
</md-grid-tile>
<md-grid-tile>
<dt>总场</dt>
</mat-grid-tile>
<mat-grid-tile>
</md-grid-tile>
<md-grid-tile>
<dd>{{ygopro.points.entertain_all}}</dd>
</mat-grid-tile>
</mat-grid-list>
</mat-card>
<mat-card *ngFor="let item of ygopro.news" class="example-card">
</md-grid-tile>
</md-grid-list>
</md-card>
<md-card *ngFor="let item of ygopro.news" class="example-card">
<a [href]="item.url" target="_blank">
<mat-card-header>
<img *ngIf="item.image" mat-card-avatar [src]="item.image">
<mat-card-title>{{item.title}}</mat-card-title>
<mat-card-subtitle>{{item.updated_at | date}}</mat-card-subtitle>
</mat-card-header>
<md-card-header>
<img *ngIf="item.image" md-card-avatar [src]="item.image">
<md-card-title>{{item.title}}</md-card-title>
<md-card-subtitle>{{item.updated_at | date}}</md-card-subtitle>
</md-card-header>
</a>
</mat-card>
</md-card>
<mat-card *ngFor="let item of ygopro.topics | async">
<md-card *ngFor="let item of ygopro.topics | async">
<a [href]="item.url" target="_blank">
<mat-card-header>
<img *ngIf="item.image_url" mat-card-avatar [src]="item.image_url">
<mat-card-title>{{item.title}}</mat-card-title>
<mat-card-subtitle>by {{item.last_poster_username}} / {{item.last_posted_at | date}}
</mat-card-subtitle>
</mat-card-header>
<md-card-header>
<img *ngIf="item.image_url" md-card-avatar [src]="item.image_url">
<md-card-title>{{item.title}}</md-card-title>
<md-card-subtitle>by {{item.last_poster_username}} / {{item.last_posted_at | date}}
</md-card-subtitle>
</md-card-header>
</a>
</mat-card>
</md-card>
mat-icon {
md-icon {
width: 96px;
height: 96px;
font-size: 96px;
}
mat-dialog-content {
md-dialog-content {
display: flex;
}
mat-dialog-actions {
md-dialog-actions {
justify-content: flex-end
}
ul {
......
<h2 mat-dialog-title *ngIf="arena == 'athletic'">竞技匹配</h2>
<h2 mat-dialog-title *ngIf="arena == 'entertain'">娱乐匹配</h2>
<h2 md-dialog-title *ngIf="arena == 'athletic'">竞技匹配</h2>
<h2 md-dialog-title *ngIf="arena == 'entertain'">娱乐匹配</h2>
<mat-dialog-content>
<mat-icon *ngIf="arena == 'athletic'" fontSet="fa" fontIcon="fa-futbol-o" class="fa-spin"></mat-icon>
<mat-icon *ngIf="arena == 'entertain'" class="fa-spin">toys</mat-icon>
<md-dialog-content>
<md-icon *ngIf="arena == 'athletic'" fontSet="fa" fontIcon="fa-futbol-o" class="fa-spin"></md-icon>
<md-icon *ngIf="arena == 'entertain'" class="fa-spin">toys</md-icon>
<ul>
<dt>预计等待时间</dt>
<dd>{{expect_wait | async | date: 'mm:ss'}}</dd>
<dt>实际等待时间</dt>
<dd>{{actual_wait | async | date: 'mm:ss'}}</dd>
</ul>
</mat-dialog-content>
<mat-dialog-actions>
<button mat-button mat-dialog-close>取消</button>
</mat-dialog-actions>
</md-dialog-content>
<md-dialog-actions>
<button md-button md-dialog-close>取消</button>
</md-dialog-actions>
import { Component, Inject, OnDestroy, OnInit } from '@angular/core';
import { Headers, Http } from '@angular/http';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
import { MD_DIALOG_DATA, MdDialogRef } from '@angular/material';
import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription';
import { LoginService } from '../login.service';
......@@ -14,39 +14,34 @@ const offset = new Date().getTimezoneOffset() * 60 * second;
styleUrls: ['./match.component.css']
})
export class MatchDialogComponent implements OnInit, OnDestroy {
expect_wait = this.http.get('https://api.mycard.moe/ygopro/match/stats/' + this.arena).map(response => response.json() * second + offset);
actual_wait = Observable.timer(0, second).map(timestamp => timestamp * second + offset);
matching: Subscription;
constructor(
@Inject(MAT_DIALOG_DATA) public arena: string,
private dialogRef: MatDialogRef<MatchDialogComponent>,
private http: Http,
private login: LoginService
) {}
constructor(@Inject(MD_DIALOG_DATA) public arena: string,
private dialogRef: MdDialogRef<MatchDialogComponent>,
private http: Http,
private login: LoginService) {
}
ngOnInit() {
this.matching = this.http
.post('https://api.mycard.moe/ygopro/match', null, {
headers: new Headers({
Authorization: 'Basic ' + Buffer.from(this.login.user.username + ':' + this.login.user.external_id).toString('base64')
}),
params: { arena: this.arena, locale: 'zh-CN' }
})
.map(response => response.json())
.subscribe(
data => {
this.dialogRef.close(data);
},
error => {
alert(`匹配失败`);
this.dialogRef.close();
}
);
this.matching = this.http.post('https://api.mycard.moe/ygopro/match', null, {
headers: new Headers({
Authorization: 'Basic ' + Buffer.from(this.login.user.username + ':' + this.login.user.external_id).toString('base64')
}),
params: {arena: this.arena, locale: 'zh-CN'}
}).map(response => response.json()).subscribe((data) => {
this.dialogRef.close(data);
}, (error) => {
alert(`匹配失败`);
this.dialogRef.close();
});
}
ngOnDestroy() {
this.matching.unsubscribe();
}
}
......@@ -11,7 +11,7 @@ form {
/*margin: 0 10px;*/
/*}*/
mat-select {
md-select {
padding: 1.2734375em 0;
}
......
<app-toolbar>创建房间</app-toolbar>
<form (submit)="ygopro.create_room(room, host_password)" ngNativeValidate>
<mat-input-container *ngIf="!room.private" class="full-width">
<input matInput placeholder="游戏标题" name="title" [(ngModel)]="room.title" minlength="1" maxlength="12" required>
<mat-hint align="end">{{room.title?.length || 0}} / 12</mat-hint>
</mat-input-container>
<mat-input-container *ngIf="room.private" class="full-width">
<mat-placeholder>
<mat-icon>&#xe0da;</mat-icon><!-- vpn_key -->
<md-input-container *ngIf="!room.private" class="full-width">
<input mdInput placeholder="游戏标题" name="title" [(ngModel)]="room.title" minlength="1" maxlength="12" required>
<md-hint align="end">{{room.title?.length || 0}} / 12</md-hint>
</md-input-container>
<md-input-container *ngIf="room.private" class="full-width">
<md-placeholder>
<md-icon>&#xe0da;</md-icon><!-- vpn_key -->
<span>房间密码</span>
</mat-placeholder>
<input #hostPasswordInput matInput name="title" [(ngModel)]="host_password" readonly>
<button type="button" mat-icon-button matSuffix (click)="copy(host_password)">
<mat-icon>&#xe14d;</mat-icon><!-- content_copy -->
</md-placeholder>
<input #hostPasswordInput mdInput name="title" [(ngModel)]="host_password" readonly>
<button type="button" md-icon-button mdSuffix (click)="copy(host_password)">
<md-icon>&#xe14d;</md-icon><!-- content_copy -->
</button>
<button type="button" mat-icon-button matSuffix (click)="share(host_password)">
<mat-icon>share</mat-icon>
<button type="button" md-icon-button mdSuffix (click)="share(host_password)">
<md-icon>share</md-icon>
</button>
<mat-hint align="end">把这个分享给你的朋友</mat-hint>
</mat-input-container>
<mat-select class="full-width" placeholder="卡片允许" name="rule" [(ngModel)]="room.options.rule" required>
<mat-option [value]="0">OCG</mat-option>
<mat-option [value]="1">TCG</mat-option>
<mat-option [value]="2">OCG & TCG</mat-option>
<mat-option [value]="3">专有卡禁止</mat-option>
</mat-select>
<mat-select class="full-width" placeholder="决斗模式" name="mode" [(ngModel)]="room.options.mode" (ngModelChange)="set_start_lp()" required>
<mat-option [value]="0">单局模式</mat-option>
<mat-option [value]="1">比赛模式</mat-option>
<mat-option [value]="2">TAG</mat-option>
</mat-select>
<md-hint align="end">把这个分享给你的朋友</md-hint>
</md-input-container>
<md-select class="full-width" placeholder="卡片允许" name="rule" [(ngModel)]="room.options.rule" required>
<md-option [value]="0">OCG</md-option>
<md-option [value]="1">TCG</md-option>
<md-option [value]="2">OCG & TCG</md-option>
<md-option [value]="3">专有卡禁止</md-option>
</md-select>
<md-select class="full-width" placeholder="决斗模式" name="mode" [(ngModel)]="room.options.mode" (ngModelChange)="set_start_lp()" required>
<md-option [value]="0">单局模式</md-option>
<md-option [value]="1">比赛模式</md-option>
<md-option [value]="2">TAG</md-option>
</md-select>
<!--<h2>额外选项</h2>-->
<!--<mat-slide-toggle #extra class="example-margin" color="primary">额外选项</mat-slide-toggle>-->
<!--<md-slide-toggle #extra class="example-margin" color="primary">额外选项</md-slide-toggle>-->
<mat-input-container class="full-width">
<input name="start_lp" [(ngModel)]="room.options.start_lp" matInput type="number" min="1" max="65536" placeholder="初始 LP" required>
</mat-input-container>
<mat-input-container class="full-width">
<input name="start_hand" [(ngModel)]="room.options.start_hand" matInput type="number" min="0" max="16" placeholder="初始手牌数" required>
</mat-input-container>
<mat-input-container class="full-width">
<input name="draw_count" [(ngModel)]="room.options.draw_count" matInput type="number" min="0" max="16" placeholder="每回合抽卡" required>
</mat-input-container>
<md-input-container class="full-width">
<input name="start_lp" [(ngModel)]="room.options.start_lp" mdInput type="number" min="1" max="65536" placeholder="初始 LP" required>
</md-input-container>
<md-input-container class="full-width">
<input name="start_hand" [(ngModel)]="room.options.start_hand" mdInput type="number" min="0" max="16" placeholder="初始手牌数" required>
</md-input-container>
<md-input-container class="full-width">
<input name="draw_count" [(ngModel)]="room.options.draw_count" mdInput type="number" min="0" max="16" placeholder="每回合抽卡" required>
</md-input-container>
<mat-checkbox class="full-width" name="room.private" [(ngModel)]="room.private">私密房间</mat-checkbox>
<mat-checkbox class="full-width" name="room.enable_priority" [(ngModel)]="room.options.enable_priority">旧规则
</mat-checkbox>
<mat-checkbox class="full-width" name="room.no_check_deck" [(ngModel)]="room.options.no_check_deck">不检查卡组</mat-checkbox>
<mat-checkbox class="full-width" name="room.no_shuffle_deck" [(ngModel)]="room.options.no_shuffle_deck">不洗切卡组
</mat-checkbox>
<md-checkbox class="full-width" name="room.private" [(ngModel)]="room.private">私密房间</md-checkbox>
<md-checkbox class="full-width" name="room.enable_priority" [(ngModel)]="room.options.enable_priority">旧规则
</md-checkbox>
<md-checkbox class="full-width" name="room.no_check_deck" [(ngModel)]="room.options.no_check_deck">不检查卡组</md-checkbox>
<md-checkbox class="full-width" name="room.no_shuffle_deck" [(ngModel)]="room.options.no_shuffle_deck">不洗切卡组
</md-checkbox>
<div id="actions">
<!--<button routerLink="/ygopro/lobby" mat-raised-button>返回大厅</button>-->
<button type="submit" color="primary" mat-raised-button>创建游戏</button>
<!--<button routerLink="/ygopro/lobby" md-raised-button>返回大厅</button>-->
<button type="submit" color="primary" md-raised-button>创建游戏</button>
</div>
</form>
import { Component, ElementRef, HostBinding, ViewChild } from '@angular/core';
import { MatSnackBar } from '@angular/material';
import { MdSnackBar } from '@angular/material';
import { LoginService } from '../login.service';
import { routerTransition } from '../router.animations';
import { YGOProService } from '../ygopro.service';
......@@ -27,7 +27,7 @@ export class NewRoomComponent {
options: {...this.ygopro.default_options}
};
constructor(public ygopro: YGOProService, private login: LoginService, private snackBar: MatSnackBar) {
constructor(public ygopro: YGOProService, private login: LoginService, private snackBar: MdSnackBar) {
}
copy(host_password: string) {
......
mat-list-item /deep/ .mat-list-item-content {
md-list-item /deep/ .mat-list-item-content {
justify-content: space-between;
height: 28px !important;
padding: 0
}
mat-grid-list {
md-grid-list {
font-size: 14px;
}
mat-grid-tile dt, mat-grid-tile dd {
md-grid-tile dt, md-grid-tile dd {
width: 100%;
}
mat-grid-tile {
md-grid-tile {
text-align: left;
}
mat-grid-tile dd {
md-grid-tile dd {
margin: 0;
text-align: left;
}
......
<h2 mat-dialog-title *ngIf="result === 'win'">胜利</h2>
<h2 mat-dialog-title *ngIf="result === 'lose'">败北</h2>
<h2 mat-dialog-title *ngIf="result === 'draw'">平局</h2>
<mat-dialog-content>
<mat-list [ngClass]="result" *ngIf="dp || exp || firstWin">
<mat-list-item *ngIf="dp">
<h2 md-dialog-title *ngIf="result === 'win'">胜利</h2>
<h2 md-dialog-title *ngIf="result === 'lose'">败北</h2>
<h2 md-dialog-title *ngIf="result === 'draw'">平局</h2>
<md-dialog-content>
<md-list [ngClass]="result" *ngIf="dp || exp || firstWin">
<md-list-item *ngIf="dp">
<dt>D.P</dt>
<dd>{{dp}}</dd>
</mat-list-item>
<mat-list-item *ngIf="exp">
</md-list-item>
<md-list-item *ngIf="exp">
<dt>EXP</dt>
<dd>{{exp}}</dd>
</mat-list-item>
<mat-list-item *ngIf="firstWin">
</md-list-item>
<md-list-item *ngIf="firstWin">
<dt>D.P (首胜)</dt>
<dd>{{firstWin}}</dd>
</mat-list-item>
</mat-list>
</mat-dialog-content>
<mat-dialog-actions>
<button mat-button mat-dialog-close>关闭</button>
</md-list-item>
</md-list>
</md-dialog-content>
<md-dialog-actions>
<button md-button md-dialog-close>关闭</button>
<!-- Can optionally provide a result for the closing dialog. -->
<button mat-button (click)="again()">再来一局</button>
</mat-dialog-actions>
<button md-button (click)="again()">再来一局</button>
</md-dialog-actions>
import { Component, Inject } from '@angular/core';
import { Http } from '@angular/http';
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material';
import { MD_DIALOG_DATA, MdDialog, MdDialogRef } from '@angular/material';
import { LoginService } from '../login.service';
import { MatchDialogComponent } from '../match/match.component';
......@@ -15,11 +15,11 @@ export class ResultDialogComponent {
exp: string | undefined;
firstWin: string | undefined;
constructor(@Inject(MAT_DIALOG_DATA) public last: any,
constructor(@Inject(MD_DIALOG_DATA) public last: any,
public login: LoginService,
private http: Http,
public dialog: MatDialog,
private dialogRef: MatDialogRef<MatchDialogComponent>) {
public dialog: MdDialog,
private dialogRef: MdDialogRef<MatchDialogComponent>) {
if (this.last.userscorea === this.last.userscoreb) {
this.result = 'draw';
} else if (this.last.winner === this.login.user.username) {
......
......@@ -26,7 +26,7 @@
flex: 2
}
mat-table {
md-table {
flex: 1;
padding-bottom: 36px;
}
......
<app-toolbar>房间列表</app-toolbar>
<div class="hint" *ngIf="dataSource.loading"><mat-spinner></mat-spinner></div>
<div class="hint" *ngIf="dataSource.loading"><md-spinner></md-spinner></div>
<div class="hint" *ngIf="dataSource.empty">现在没有等待中的游戏,可以自行创建一个房间或者去匹配</div>
<div class="hint" *ngIf="dataSource.error">网络错误</div>
<mat-table #table [dataSource]="dataSource">
<md-table #table [dataSource]="dataSource">
<!--- Note that these columns can be defined in any order.
The actual rendered columns are set as a property on room row definition" -->
<!-- ID Column -->
<ng-container matColumnDef="title">
<mat-header-cell class="game-title" *matHeaderCellDef>游戏标题</mat-header-cell>
<mat-cell class="game-title" *matCellDef="let room">{{room.title}}</mat-cell>
<ng-container cdkColumnDef="title">
<md-header-cell class="game-title" *cdkHeaderCellDef>游戏标题</md-header-cell>
<md-cell class="game-title" *cdkCellDef="let room">{{room.title}}</md-cell>
</ng-container>
<!-- Progress Column -->
<ng-container matColumnDef="users">
<mat-header-cell *matHeaderCellDef>玩家</mat-header-cell>
<mat-cell *matCellDef="let room">
<ng-container cdkColumnDef="users">
<md-header-cell *cdkHeaderCellDef>玩家</md-header-cell>
<md-cell *cdkCellDef="let room">
<img *ngFor="let user of room.users" class="avatar" [src]="login.avatar(user.username)">
</mat-cell>
</md-cell>
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="mode">
<mat-header-cell *matHeaderCellDef>决斗模式</mat-header-cell>
<mat-cell *matCellDef="let room">
<ng-container cdkColumnDef="mode">
<md-header-cell *cdkHeaderCellDef>决斗模式</md-header-cell>
<md-cell *cdkCellDef="let room">
<span *ngIf="room.options.mode === 0">单局模式</span>
<span *ngIf="room.options.mode === 1">比赛模式</span>
<span *ngIf="room.options.mode === 2">TAG</span>
</mat-cell>
</md-cell>
</ng-container>
<!-- Color Column -->
<ng-container matColumnDef="extra">
<mat-header-cell *matHeaderCellDef>额外选项</mat-header-cell>
<mat-cell *matCellDef="let room">
<ng-container cdkColumnDef="extra">
<md-header-cell *cdkHeaderCellDef>额外选项</md-header-cell>
<md-cell *cdkCellDef="let room">
<span *ngIf="room.options.rule != ygopro.default_options.rule">{{{'0': 'OCG', '1': 'TCG', '2': 'O/T', '3': '专有卡禁止'}[room.options.rule]}}</span>
<span *ngIf="room.options.start_lp != ygopro.default_options.start_lp">{{room.options.start_lp}} LP</span>
<span *ngIf="room.options.start_hand != ygopro.default_options.start_hand">{{room.options.start_hand}} 初始</span>
......@@ -44,14 +44,14 @@
<span *ngIf="room.options.enable_priority != ygopro.default_options.enable_priority">旧规则</span>
<span *ngIf="room.options.no_check_deck != ygopro.default_options.no_check_deck">不检查</span>
<span *ngIf="room.options.no_shuffle_deck != ygopro.default_options.no_shuffle_deck">不洗卡</span>
</mat-cell>
</md-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let room; columns: displayedColumns;" (click)="ygopro.join_room(room)"></mat-row>
</mat-table>
<md-header-row *cdkHeaderRowDef="displayedColumns"></md-header-row>
<md-row *cdkRowDef="let room; columns: displayedColumns;" (click)="ygopro.join_room(room)"></md-row>
</md-table>
<form (submit)="ygopro.join_private(joinPassword.value)" ngNativeValidate>
<input #joinPassword placeholder="在这输入你朋友的私密房间密码就可以进去了哦!" required>
<button mat-raised-button color="primary">加入私密房间</button>
<button md-raised-button color="primary">加入私密房间</button>
</form>
......@@ -120,7 +120,7 @@ export class StorageService {
this.working = true;
// console.log('download', local_path, remote_path, index_path, time);
const data: Uint8Array = await this.client.getFileContents(remote_path);
window.ygopro.writeFile(local_path, Buffer.from(<ArrayBuffer>data.buffer).toString('base64'));
window.ygopro.writeFile(local_path, Buffer.from(data.buffer).toString('base64'));
window.ygopro.setFileLastModified(local_path, time);
// console.log(local_path, time);
localStorage.setItem(index_path, time.toString());
......
<mat-toolbar color="primary">
<button mat-icon-button (click)="history.back()">
<mat-icon>&#xe5c4;</mat-icon><!--arrow_back--></button>
<md-toolbar color="primary">
<button md-icon-button (click)="history.back()">
<md-icon>&#xe5c4;</md-icon><!--arrow_back--></button>
<span><ng-content></ng-content></span>
</mat-toolbar>
</md-toolbar>
<app-toolbar>观战</app-toolbar>
<div class="hint" *ngIf="dataSource.loading"><mat-spinner></mat-spinner></div>
<div class="hint" *ngIf="dataSource.loading"><md-spinner></md-spinner></div>
<div class="hint" *ngIf="dataSource.empty">现在没有进行中的游戏</div>
<div class="hint" *ngIf="dataSource.error">网络错误</div>
<mat-table #table [dataSource]="dataSource">
<md-table #table [dataSource]="dataSource">
<!--- Note that these columns can be defined in any order.
The actual rendered columns are set as a property on room row definition" -->
<!-- ID Column -->
<ng-container matColumnDef="mode">
<mat-header-cell *matHeaderCellDef>游戏模式</mat-header-cell>
<mat-cell *matCellDef="let room">
<ng-container cdkColumnDef="mode">
<md-header-cell *cdkHeaderCellDef>游戏模式</md-header-cell>
<md-cell *cdkCellDef="let room">
<span i18n *ngIf="room.id.startsWith('AI#')">单人模式</span>
<span i18n *ngIf="room.arena === 'athletic'">竞技匹配</span>
<span i18n *ngIf="room.arena === 'entertain'">娱乐匹配</span>
<span i18n *ngIf="!(room.arena || room.id.startsWith('AI#')) && room.options.mode === 0">单局模式</span>
<span i18n *ngIf="!(room.arena || room.id.startsWith('AI#')) && room.options.mode === 1">比赛模式</span>
<span i18n *ngIf="!(room.arena || room.id.startsWith('AI#')) && room.options.mode === 2">TAG</span>
</mat-cell>
</md-cell>
</ng-container>
<!-- ID Column -->
<ng-container matColumnDef="title">
<mat-header-cell class="game-title" *matHeaderCellDef>游戏标题</mat-header-cell>
<mat-cell class="game-title" *matCellDef="let room">
<ng-container cdkColumnDef="title">
<md-header-cell class="game-title" *cdkHeaderCellDef>游戏标题</md-header-cell>
<md-cell class="game-title" *cdkCellDef="let room">
<span *ngIf="room.private">{{room.users[0] && room.users[0].username}}的私密房间</span>
<span i18n *ngIf="room.arena || room.id.startsWith('AI#')">{{room.users[0] && room.users[0].username}} Vs. {{room.users[1] && room.users[1].username}}</span>
<span *ngIf="!(room.arena || room.id.startsWith('AI#') || room.private)">{{room.title}}</span>
</mat-cell>
</md-cell>
</ng-container>
<!-- Progress Column -->
<ng-container matColumnDef="users">
<mat-header-cell *matHeaderCellDef>玩家</mat-header-cell>
<mat-cell *matCellDef="let room">
<ng-container cdkColumnDef="users">
<md-header-cell *cdkHeaderCellDef>玩家</md-header-cell>
<md-cell *cdkCellDef="let room">
<img *ngFor="let user of room.users" class="avatar" [src]="login.avatar(user.username)">
</mat-cell>
</md-cell>
</ng-container>
<!-- Color Column -->
<ng-container matColumnDef="extra">
<mat-header-cell *matHeaderCellDef>额外选项</mat-header-cell>
<mat-cell *matCellDef="let room">
<ng-container cdkColumnDef="extra">
<md-header-cell *cdkHeaderCellDef>额外选项</md-header-cell>
<md-cell *cdkCellDef="let room">
<span *ngIf="room.options.rule != ygopro.default_options.rule">{{{'0': 'OCG', '1': 'TCG', '2': 'O/T', '3': '专有卡禁止'}[room.options.rule]}}</span>
<span *ngIf="room.options.start_lp != ygopro.default_options.start_lp">{{room.options.start_lp}} LP</span>
<span *ngIf="room.options.start_hand != ygopro.default_options.start_hand">{{room.options.start_hand}} 初始</span>
......@@ -51,10 +51,10 @@
<span *ngIf="room.options.enable_priority != ygopro.default_options.enable_priority">旧规则</span>
<span *ngIf="room.options.no_check_deck != ygopro.default_options.no_check_deck">不检查</span>
<span *ngIf="room.options.no_shuffle_deck != ygopro.default_options.no_shuffle_deck">不洗卡</span>
</mat-cell>
</md-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let room; columns: displayedColumns;" (click)="ygopro.join_room(room)"></mat-row>
</mat-table>
<md-header-row *cdkHeaderRowDef="displayedColumns"></md-header-row>
<md-row *cdkRowDef="let room; columns: displayedColumns;" (click)="ygopro.join_room(room)"></md-row>
</md-table>
<app-toolbar>单人模式</app-toolbar>
<mat-list>
<h3 mat-subheader>选择对手</h3>
<mat-list-item (click)="ygopro.join_windbot()">
<mat-icon mat-list-icon>&#xe195;</mat-icon><!-- airplanemode_active -->
<h4 mat-line>随机</h4>
</mat-list-item>
<mat-list-item *ngFor="let windbot of ygopro.windbot" (click)="ygopro.join_windbot(windbot)">
<img mat-list-icon [src]="login.avatar(windbot)">
<h4 mat-line>{{windbot}}</h4>
</mat-list-item>
</mat-list>
<md-list>
<h3 md-subheader>选择对手</h3>
<md-list-item (click)="ygopro.join_windbot()">
<md-icon md-list-icon>&#xe195;</md-icon><!-- airplanemode_active -->
<h4 md-line>随机</h4>
</md-list-item>
<md-list-item *ngFor="let windbot of ygopro.windbot" (click)="ygopro.join_windbot(windbot)">
<img md-list-icon [src]="login.avatar(windbot)">
<h4 md-line>{{windbot}}</h4>
</md-list-item>
</md-list>
import { DataSource } from '@angular/cdk';
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { MdDialog } from '@angular/material';
import { sortBy } from 'lodash';
import { Observable } from 'rxjs/Observable';
import { LoginService } from './login.service';
import { MatchDialogComponent } from './match/match.component';
import { ResultDialogComponent } from './result/result.dialog';
import { StorageService } from './storage.service';
import { MatDialog } from '@angular/material';
import { DataSource } from '@angular/cdk/collections';
export interface User {
admin: boolean;
......@@ -23,10 +23,10 @@ export interface Room {
id?: string;
title?: string;
server?: Server;
private?: boolean;
'private'?: boolean;
options: Options;
arena?: string;
users?: { username: string; position: number }[];
users?: { username: string, position: number }[];
}
export interface Options {
......@@ -42,6 +42,7 @@ export interface Options {
time_limit?: number;
}
export interface Server {
id?: string;
url?: string;
......@@ -109,6 +110,7 @@ export interface Points {
@Injectable()
export class YGOProService {
news: News[];
windbot: string[];
topics: Observable<any>;
......@@ -129,62 +131,52 @@ export class YGOProService {
time_limit: 180
};
readonly servers: Server[] = [
{
id: 'tiramisu',
url: 'wss://tiramisu.mycard.moe:7923',
address: '112.124.105.11',
port: 7911,
custom: true,
replay: true
},
{
id: 'tiramisu-athletic',
url: 'wss://tiramisu.mycard.moe:8923',
address: '112.124.105.11',
port: 8911,
custom: false,
replay: true
}
];
constructor(private login: LoginService, private http: Http, private dialog: MatDialog, private storage: StorageService) {
readonly servers: Server[] = [{
id: 'tiramisu',
url: 'wss://tiramisu.mycard.moe:7923',
address: '112.124.105.11',
port: 7911,
custom: true,
replay: true
}, {
id: 'tiramisu-athletic',
url: 'wss://tiramisu.mycard.moe:8923',
address: '112.124.105.11',
port: 8911,
custom: false,
replay: true
}];
constructor(private login: LoginService, private http: Http, private dialog: MdDialog, private storage: StorageService) {
this.load().catch(alert);
}
async load() {
const apps: App[] = await this.http
.get('https://api.mycard.moe/apps.json')
.map(response => response.json())
.toPromise();
const apps: App[] = await this.http.get('https://api.mycard.moe/apps.json').map(response => response.json()).toPromise();
const app = apps.find(_app => _app.id === 'ygopro')!;
this.news = app.news['zh-CN'];
this.windbot = (<YGOProData>app.data).windbot['zh-CN'];
this.topics = this.http.get('https://ygobbs.com/top/quarterly.json').map(response =>
response
.json()
.topic_list.topics.slice(0, 5)
.map((topic: any) => ({
...topic,
url: new URL(`/t/${topic.slug}/${topic.id}`, 'https://ygobbs.com').toString(),
image_url: topic.image_url && new URL(topic.image_url, 'https://ygobbs.com').toString()
}))
);
this.topics = this.http.get('https://ygobbs.com/top/quarterly.json').map(
response => response.json().topic_list.topics.slice(0, 5).map((topic: any) => ({
...topic,
url: new URL(`/t/${topic.slug}/${topic.id}`, 'https://ygobbs.com').toString(),
image_url: topic.image_url && new URL(topic.image_url, 'https://ygobbs.com').toString()
})));
this.storage.sync('ygopro');
this.load_points();
await this.load_result(false);
this.listen_result();
}
async load_result(load_points = true) {
const last = await this.http
.get('https://mycard.moe/ygopro/api/history', {
params: { username: this.login.user.username, type: 0, page_num: 1 }
})
.map(response => response.json().data[0])
.toPromise();
const last = await this.http.get('https://mycard.moe/ygopro/api/history', {
params: {username: this.login.user.username, type: 0, page_num: 1}
}).map((response) => response.json().data[0]).toPromise();
// 从来没打过
if (!last) {
......@@ -209,10 +201,7 @@ export class YGOProService {
if (load_points) {
this.load_points();
}
const again = await this.dialog
.open(ResultDialogComponent, { data: last })
.afterClosed()
.toPromise();
const again = await this.dialog.open(ResultDialogComponent, {data: last}).afterClosed().toPromise();
if (again) {
this.request_match(last.type);
}
......@@ -220,20 +209,18 @@ export class YGOProService {
}
async request_match(arena: string) {
const data = await this.dialog
.open(MatchDialogComponent, { data: arena, disableClose: true })
.afterClosed()
.toPromise();
const data = await this.dialog.open(MatchDialogComponent, {data: arena, disableClose: true}).afterClosed().toPromise();
if (data) {
this.join(data['password'], { address: data['address'], port: data['port'] });
this.join(data['password'], {address: data['address'], port: data['port']});
}
}
listen_result() {
// 那些兼容性的垃圾事儿
// https://www.html5rocks.com/en/tutorials/pagevisibility/intro/
const hidden = ['hidden', 'webkitHidden', 'mozHidden', 'msHidden', 'oHidden'].find(prop => prop in document);
const hidden = ['hidden', 'webkitHidden', 'mozHidden', 'msHidden', 'oHidden'].find((prop) => prop in document);
if (hidden) {
const evtname = hidden.replace(/[H|h]idden/, '') + 'visibilitychange';
Observable.fromEvent(document, evtname).subscribe(() => {
......@@ -251,10 +238,8 @@ export class YGOProService {
}
async load_points() {
this.points = await this.http
.get('https://api.mycard.moe/ygopro/arena/user', { params: { username: this.login.user.username } })
.map(response => response.json())
.toPromise();
this.points = await this.http.get('https://api.mycard.moe/ygopro/arena/user', {params: {username: this.login.user.username}}).map(
response => response.json()).toPromise();
}
create_room(room: Room, host_password: string) {
......@@ -262,28 +247,27 @@ export class YGOProService {
// 建主密码 https://docs.google.com/document/d/1rvrCGIONua2KeRaYNjKBLqyG9uybs9ZI-AmzZKNftOI/edit
options_buffer.writeUInt8((room.private ? 2 : 1) << 4, 1);
options_buffer.writeUInt8(
(room.options.rule << 5) |
(room.options.mode << 3) |
(room.options.enable_priority ? 1 << 2 : 0) |
(room.options.no_check_deck ? 1 << 1 : 0) |
(room.options.no_shuffle_deck ? 1 : 0),
2
);
room.options.rule << 5 |
room.options.mode << 3 |
(room.options.enable_priority ? 1 << 2 : 0) |
(room.options.no_check_deck ? 1 << 1 : 0) |
(room.options.no_shuffle_deck ? 1 : 0)
, 2);
options_buffer.writeUInt16LE(room.options.start_lp, 3);
options_buffer.writeUInt8((room.options.start_hand << 4) | room.options.draw_count, 5);
options_buffer.writeUInt8(room.options.start_hand << 4 | room.options.draw_count, 5);
let checksum = 0;
for (let i = 1; i < options_buffer.length; i++) {
checksum -= options_buffer.readUInt8(i);
}
options_buffer.writeUInt8(checksum & 0xff, 0);
options_buffer.writeUInt8(checksum & 0xFF, 0);
const secret = this.login.user.external_id % 65535 + 1;
for (let i = 0; i < options_buffer.length; i += 2) {
options_buffer.writeUInt16LE(options_buffer.readUInt16LE(i) ^ secret, i);
}
const password =
options_buffer.toString('base64') + (room.private ? host_password : room.title!.replace(/\s/, String.fromCharCode(0xfeff)));
const password = options_buffer.toString('base64') + (room.private ? host_password :
room.title!.replace(/\s/, String.fromCharCode(0xFEFF)));
// let room_id = crypto.createHash('md5').update(password + this.loginService.user.username).digest('base64')
// .slice(0, 10).replace('+', '-').replace('/', '_');
......@@ -302,7 +286,7 @@ export class YGOProService {
for (let i = 1; i < options_buffer.length; i++) {
checksum -= options_buffer.readUInt8(i);
}
options_buffer.writeUInt8(checksum & 0xff, 0);
options_buffer.writeUInt8(checksum & 0xFF, 0);
const secret = this.login.user.external_id % 65535 + 1;
for (let i = 0; i < options_buffer.length; i += 2) {
......@@ -321,14 +305,14 @@ export class YGOProService {
for (let i = 1; i < options_buffer.length; i++) {
checksum -= options_buffer.readUInt8(i);
}
options_buffer.writeUInt8(checksum & 0xff, 0);
options_buffer.writeUInt8(checksum & 0xFF, 0);
const secret = this.login.user.external_id % 65535 + 1;
for (let i = 0; i < options_buffer.length; i += 2) {
options_buffer.writeUInt16LE(options_buffer.readUInt16LE(i) ^ secret, i);
}
const name = options_buffer.toString('base64') + password.replace(/\s/, String.fromCharCode(0xfeff));
const name = options_buffer.toString('base64') + password.replace(/\s/, String.fromCharCode(0xFEFF));
this.join(name, this.servers[0]);
}
......@@ -345,12 +329,10 @@ export class YGOProService {
window.ygopro.join(server.address, server.port, this.login.user.username, password);
} catch (error) {
console.error(error);
alert(
JSON.stringify({
method: 'join',
params: [server.address, server.port, this.login.user.username, password]
})
);
alert(JSON.stringify({
method: 'join',
params: [server.address, server.port, this.login.user.username, password]
}));
}
}
......@@ -359,7 +341,7 @@ export class YGOProService {
window.ygopro.edit_deck();
} catch (error) {
console.error(error);
alert(JSON.stringify({ method: 'edit_deck', params: [] }));
alert(JSON.stringify({method: 'edit_deck', params: []}));
}
}
......@@ -368,7 +350,7 @@ export class YGOProService {
window.ygopro.watch_replay();
} catch (error) {
console.error(error);
alert(JSON.stringify({ method: 'watch_replay', params: [] }));
alert(JSON.stringify({method: 'watch_replay', params: []}));
}
}
......@@ -377,7 +359,7 @@ export class YGOProService {
window.ygopro.puzzle_mode();
} catch (error) {
console.error(error);
alert(JSON.stringify({ method: 'puzzle_mode', params: [] }));
alert(JSON.stringify({method: 'puzzle_mode', params: []}));
}
}
......@@ -386,7 +368,7 @@ export class YGOProService {
window.ygopro.openDrawer();
} catch (error) {
console.error(error);
alert(JSON.stringify({ method: 'openDrawer', params: [] }));
alert(JSON.stringify({method: 'openDrawer', params: []}));
}
}
......@@ -395,7 +377,7 @@ export class YGOProService {
window.ygopro.backHome();
} catch (error) {
console.error(error);
alert(JSON.stringify({ method: 'backHome', params: [] }));
alert(JSON.stringify({method: 'backHome', params: []}));
}
}
......@@ -404,18 +386,21 @@ export class YGOProService {
window.ygopro.share(text);
} catch (error) {
console.error(error);
alert(JSON.stringify({ method: 'share', params: [text] }));
alert(JSON.stringify({method: 'share', params: [text]}));
}
}
}
type Message =
| { event: 'init'; data: Room[] }
| { event: 'update'; data: Room }
| { event: 'create'; data: Room }
| { event: 'delete'; data: string };
{ event: 'init', data: Room[] }
| { event: 'update', data: Room }
| { event: 'create', data: Room }
| { event: 'delete', data: string };
export class RoomListDataSource extends DataSource<any> {
export class RoomListDataSource extends DataSource<Room> {
loading = true;
empty = false;
error: any;
......@@ -426,57 +411,52 @@ export class RoomListDataSource extends DataSource<Room> {
/** Connect function called by the table to retrieve one stream containing the data to render. */
connect(): Observable<Room[]> {
return (
Observable.combineLatest(
this.servers.map(server => {
const url = new URL(server.url!);
url.searchParams.set('filter', this.filter);
// 协议处理
return Observable.webSocket<Message>(url.toString()).scan((rooms: Room[], message: Message, index: number) => {
switch (message.event) {
case 'init':
return message.data.map(room => ({ server: server, ...room }));
case 'create':
return rooms.concat({ server: server, ...message.data });
case 'update':
Object.assign(rooms.find(room => room.id === message.data.id), message.data);
return rooms;
case 'delete':
return rooms.filter(room => room.id !== message.data);
}
}, []);
// 把多个服务器的数据拼接起来,这里是 combineLatest 的第二个参数
}),
(...sources: Room[][]) => (<Room[]>[]).concat(...sources)
)
// 房间排序
.map(
rooms =>
sortBy(rooms, room => {
if (room.arena === 'athletic') {
return 0;
} else if (room.arena === 'entertain') {
return 1;
} else if (room.id!.startsWith('AI#')) {
return 5;
} else {
return room.options.mode + 2;
}
})
// loading、empty、error
)
.filter(rooms => {
this.loading = false;
this.empty = rooms.length === 0;
return true;
})
.catch(error => {
this.loading = false;
this.error = error;
return [];
return Observable.combineLatest(this.servers.map(server => {
const url = new URL(server.url!);
url.searchParams.set('filter', this.filter);
// 协议处理
return Observable.webSocket({url: url.toString()})
.scan((rooms: Room[], message: Message) => {
switch (message.event) {
case 'init':
return message.data.map(room => ({server: server, ...room}));
case 'create':
return rooms.concat({server: server, ...message.data});
case 'update':
Object.assign(rooms.find(room => room.id === message.data.id), message.data);
return rooms;
case 'delete':
return rooms.filter(room => room.id !== message.data);
}
}, []);
// 把多个服务器的数据拼接起来,这里是 combineLatest 的第二个参数
}), (...sources: Room[][]) => (<Room[]>[]).concat(...sources))
// 房间排序
.map(rooms => sortBy(rooms, (room) => {
if (room.arena === 'athletic') {
return 0;
} else if (room.arena === 'entertain') {
return 1;
} else if (room.id!.startsWith('AI#')) {
return 5;
} else {
return room.options.mode + 2;
}
})
);
// loading、empty、error
).filter((rooms) => {
this.loading = false;
this.empty = rooms.length === 0;
return true;
}).catch((error) => {
this.loading = false;
this.error = error;
return [];
});
}
disconnect() {
}
disconnect() {}
}
......@@ -15,7 +15,6 @@
"typeRoots": [
"node_modules/@types"
],
"skipLibCheck": true,
"lib": [
"esnext",
"dom.iterable"
......
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