Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
M
Mycard Mobile
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
MyCard
Mycard Mobile
Commits
cd8508f4
Commit
cd8508f4
authored
Apr 25, 2018
by
神楽坂玲奈
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
update dependencies
parent
02f87ee6
Changes
23
Hide whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
5488 additions
and
4634 deletions
+5488
-4634
package-lock.json
package-lock.json
+4983
-4156
package.json
package.json
+26
-26
prettier.config.js
prettier.config.js
+4
-0
src/app/app.module.ts
src/app/app.module.ts
+33
-36
src/app/lobby/lobby.component.css
src/app/lobby/lobby.component.css
+6
-6
src/app/lobby/lobby.component.html
src/app/lobby/lobby.component.html
+128
-128
src/app/match/match.component.css
src/app/match/match.component.css
+3
-3
src/app/match/match.component.html
src/app/match/match.component.html
+9
-9
src/app/match/match.component.ts
src/app/match/match.component.ts
+24
-19
src/app/new-room/new-room.component.css
src/app/new-room/new-room.component.css
+1
-1
src/app/new-room/new-room.component.html
src/app/new-room/new-room.component.html
+44
-44
src/app/new-room/new-room.component.ts
src/app/new-room/new-room.component.ts
+2
-2
src/app/result/result.dialog.css
src/app/result/result.dialog.css
+5
-5
src/app/result/result.dialog.html
src/app/result/result.dialog.html
+17
-17
src/app/result/result.dialog.ts
src/app/result/result.dialog.ts
+4
-4
src/app/room-list/room-list.component.css
src/app/room-list/room-list.component.css
+1
-1
src/app/room-list/room-list.component.html
src/app/room-list/room-list.component.html
+21
-21
src/app/storage.service.ts
src/app/storage.service.ts
+1
-1
src/app/toolbar/toolbar.component.html
src/app/toolbar/toolbar.component.html
+4
-4
src/app/watch/watch.component.html
src/app/watch/watch.component.html
+21
-21
src/app/windbot/windbot.component.html
src/app/windbot/windbot.component.html
+11
-11
src/app/ygopro.service.ts
src/app/ygopro.service.ts
+139
-119
tsconfig.json
tsconfig.json
+1
-0
No files found.
package-lock.json
View file @
cd8508f4
This source diff could not be displayed because it is too large. You can
view the blob
instead.
package.json
View file @
cd8508f4
...
...
@@ -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
"
:
"
^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
"
,
"
@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
"
,
"
font-awesome
"
:
"
^4.7.0
"
,
"
hammerjs
"
:
"
^2.0.8
"
,
"
lodash
"
:
"
^4.17.
4
"
,
"
lodash
"
:
"
^4.17.
10
"
,
"
material-design-icons
"
:
"
^3.0.1
"
,
"
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
"
"
rxjs
"
:
"
^5.
5.10
"
,
"
webdav
"
:
"
^1.5.2
"
,
"
zone.js
"
:
"
^0.8.
26
"
},
"devDependencies"
:
{
"
@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
"
"
@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
"
}
}
prettier.config.js
0 → 100644
View file @
cd8508f4
module
.
exports
=
{
printWidth
:
140
,
singleQuote
:
true
};
src/app/app.module.ts
View file @
cd8508f4
import
{
CdkTableModule
}
from
'
@angular/cdk
'
;
import
{
NgModule
}
from
'
@angular/core
'
;
import
{
FormsModule
,
ReactiveFormsModule
}
from
'
@angular/forms
'
;
import
{
HttpModule
,
JsonpModule
}
from
'
@angular/http
'
;
import
{
M
d
AutocompleteModule
,
M
d
ButtonModule
,
M
d
CardModule
,
M
d
CheckboxModule
,
M
d
DialogModule
,
M
d
GridListModule
,
M
d
IconModule
,
M
d
InputModule
,
M
d
ListModule
,
M
d
MenuModule
,
M
d
ProgressSpinnerModule
,
M
d
SelectModule
,
M
d
SlideToggleModule
,
M
d
SnackBarModule
,
M
d
TableModule
,
M
d
ToolbarModule
M
at
AutocompleteModule
,
M
at
ButtonModule
,
M
at
CardModule
,
M
at
CheckboxModule
,
M
at
DialogModule
,
M
at
GridListModule
,
M
at
IconModule
,
M
at
InputModule
,
M
at
ListModule
,
M
at
MenuModule
,
M
at
ProgressSpinnerModule
,
M
at
SelectModule
,
M
at
SlideToggleModule
,
M
at
SnackBarModule
,
M
at
TableModule
,
M
at
ToolbarModule
}
from
'
@angular/material
'
;
import
{
BrowserModule
}
from
'
@angular/platform-browser
'
;
import
{
BrowserAnimationsModule
}
from
'
@angular/platform-browser/animations
'
;
...
...
@@ -56,29 +55,27 @@ import { YGOProService } from './ygopro.service';
HttpModule
,
AppRoutingModule
,
BrowserAnimationsModule
,
MdInputModule
,
MdSelectModule
,
MdCheckboxModule
,
MdButtonModule
,
MdSlideToggleModule
,
MdCardModule
,
MdGridListModule
,
MdIconModule
,
MdTableModule
,
CdkTableModule
,
MdListModule
,
MdDialogModule
,
MdToolbarModule
,
MdSnackBarModule
,
MdAutocompleteModule
,
MatInputModule
,
MatSelectModule
,
MatCheckboxModule
,
MatButtonModule
,
MatSlideToggleModule
,
MatCardModule
,
MatGridListModule
,
MatIconModule
,
MatTableModule
,
MatListModule
,
MatDialogModule
,
MatToolbarModule
,
MatSnackBarModule
,
MatAutocompleteModule
,
ReactiveFormsModule
,
JsonpModule
,
M
d
MenuModule
,
M
d
ProgressSpinnerModule
M
at
MenuModule
,
M
at
ProgressSpinnerModule
],
providers
:
[
YGOProService
,
StorageService
],
bootstrap
:
[
AppComponent
],
entryComponents
:
[
MatchDialogComponent
,
ResultDialogComponent
]
})
export
class
AppModule
{
}
export
class
AppModule
{}
src/app/lobby/lobby.component.css
View file @
cd8508f4
...
...
@@ -35,33 +35,33 @@ input::placeholder {
/*color: lightgray;*/
/*}*/
m
d
-input-container
{
m
at
-input-container
{
width
:
100%
;
}
[
m
d
-raised-button
]
{
[
m
at
-raised-button
]
{
border-radius
:
0
;
box-shadow
:
none
;
}
[
m
d-button
],
[
md
-raised-button
]
{
[
m
at-button
],
[
mat
-raised-button
]
{
width
:
100%
;
height
:
100%
;
}
a
[
m
d-button
],
a
[
md
-raised-button
]
{
a
[
m
at-button
],
a
[
mat
-raised-button
]
{
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
}
m
d
-card-content
{
m
at
-card-content
{
display
:
flex
;
flex-direction
:
row
;
}
[
m
d
-card-avatar
]
{
[
m
at
-card-avatar
]
{
width
:
128px
;
height
:
72px
;
object-fit
:
cover
;
...
...
src/app/lobby/lobby.component.html
View file @
cd8508f4
<!--https://github.com/google/material-design-icons/blob/master/iconfont/codepoints-->
<m
d
-toolbar
color=
"primary"
>
<button
id=
"menu"
m
d
-icon-button
(click)=
"ygopro.openDrawer()"
>
<m
d-icon>
menu
</md
-icon>
<m
at
-toolbar
color=
"primary"
>
<button
id=
"menu"
m
at
-icon-button
(click)=
"ygopro.openDrawer()"
>
<m
at-icon>
menu
</mat
-icon>
</button>
<form
(submit)=
"search(key)"
>
<input
type=
search
placeholder=
"卡片搜索"
name=
"key"
[(ngModel)]=
"key"
m
d
Autocomplete=
"auto"
[formControl]=
"searchCtrl"
>
<input
type=
search
placeholder=
"卡片搜索"
name=
"key"
[(ngModel)]=
"key"
m
at
Autocomplete=
"auto"
[formControl]=
"searchCtrl"
>
<m
d-autocomplete
#auto
="
md
Autocomplete
"
>
<m
d
-option
*ngFor=
"let card of suggestion | async"
[value]=
"card"
(onSelectionChange)=
"search(card)"
>
<m
at-autocomplete
#auto
="
mat
Autocomplete
"
>
<m
at
-option
*ngFor=
"let card of suggestion | async"
[value]=
"card"
(onSelectionChange)=
"search(card)"
>
{{ card }}
</m
d
-option>
</m
d
-autocomplete>
</m
at
-option>
</m
at
-autocomplete>
</form>
<button
m
d
-icon-button
*ngIf=
"storage.working"
>
<m
d-icon
class=
"fa-spin"
>
sync
</md
-icon>
<button
m
at
-icon-button
*ngIf=
"storage.working"
>
<m
at-icon
class=
"fa-spin"
>
sync
</mat
-icon>
</button>
<a
href=
"https://accounts.moecube.com/profiles"
target=
"_blank"
m
d
-icon-button
>
<a
href=
"https://accounts.moecube.com/profiles"
target=
"_blank"
m
at
-icon-button
>
<img
id=
"avatar"
[src]=
"login.user.avatar_url"
>
</a>
<button
m
d-icon-button
[md
MenuTriggerFor]=
"menu"
>
<m
d-icon>
add
</md
-icon>
<button
m
at-icon-button
[mat
MenuTriggerFor]=
"menu"
>
<m
at-icon>
add
</mat
-icon>
</button>
<m
d-menu
#menu
="
md
Menu
"
>
<a
[href]=
"login.logout()"
m
d
-menu-item
>
切换用户
</a>
<button
m
d
-menu-item
>
大厅版本 {{version}}
</button>
<button
m
d
-menu-item
*ngIf=
"build"
>
应用版本 {{build.version_name}}
</button>
</m
d
-menu>
</m
d
-toolbar>
<m
at-menu
#menu
="
mat
Menu
"
>
<a
[href]=
"login.logout()"
m
at
-menu-item
>
切换用户
</a>
<button
m
at
-menu-item
>
大厅版本 {{version}}
</button>
<button
m
at
-menu-item
*ngIf=
"build"
>
应用版本 {{build.version_name}}
</button>
</m
at
-menu>
</m
at
-toolbar>
<m
d
-grid-list
cols=
"4"
rowHeight=
"100px"
gutterSize=
"0"
>
<!--<m
d
-grid-tile>-->
<!--<a href="https://accounts.moecube.com/profiles" id="avatar" m
d
-raised-button [style.background-image]="'url(' + login.user.avatar_url + ')'">{{login.user.username}}</a>-->
<!--</m
d
-grid-tile>-->
<m
d
-grid-tile>
<button
m
d
-raised-button
color=
"primary"
(click)=
"ygopro.request_match('athletic')"
>
<m
d-icon
fontSet=
"fa"
fontIcon=
"fa-futbol-o"
></md
-icon>
<m
at
-grid-list
cols=
"4"
rowHeight=
"100px"
gutterSize=
"0"
>
<!--<m
at
-grid-tile>-->
<!--<a href="https://accounts.moecube.com/profiles" id="avatar" m
at
-raised-button [style.background-image]="'url(' + login.user.avatar_url + ')'">{{login.user.username}}</a>-->
<!--</m
at
-grid-tile>-->
<m
at
-grid-tile>
<button
m
at
-raised-button
color=
"primary"
(click)=
"ygopro.request_match('athletic')"
>
<m
at-icon
fontSet=
"fa"
fontIcon=
"fa-futbol-o"
></mat
-icon>
<br>
竞技匹配
</button>
</m
d
-grid-tile>
<m
d
-grid-tile>
<button
m
d
-raised-button
color=
"primary"
(click)=
"ygopro.request_match('entertain')"
>
<m
d-icon>
toys
</md
-icon>
</m
at
-grid-tile>
<m
at
-grid-tile>
<button
m
at
-raised-button
color=
"primary"
(click)=
"ygopro.request_match('entertain')"
>
<m
at-icon>
toys
</mat
-icon>
<br>
娱乐匹配
</button>
</m
d
-grid-tile>
<m
d-grid-tile><a
md
-raised-button
color=
"primary"
routerLink=
"/ygopro/rooms"
>
<m
d-icon>
games
</md
-icon>
<br>
房间列表
</a></m
d
-grid-tile>
<m
d-grid-tile><a
md
-raised-button
color=
"primary"
routerLink=
"/ygopro/rooms/new"
>
<m
d-icon>

</md
-icon>
<!--add_box-->
<br>
创建房间
</a></m
d
-grid-tile>
<m
d-grid-tile><a
md
-raised-button
routerLink=
"/ygopro/windbot"
>
<m
d-icon>

</md
-icon>
<!-- airplanemode_active -->
<br>
单人模式
</a></m
d
-grid-tile>
<m
d-grid-tile><a
md
-raised-button
routerLink=
"/ygopro/watch"
>
<m
d-icon>

</md
-icon>
<!--remove_red_eye-->
<br>
观战
</a></m
d
-grid-tile>
<!--<m
d
-grid-tile>-->
<!--<button m
d
-raised-button (click)="ygopro.watch_replay()">-->
<!--<m
d-icon>history</md
-icon>-->
</m
at
-grid-tile>
<m
at-grid-tile><a
mat
-raised-button
color=
"primary"
routerLink=
"/ygopro/rooms"
>
<m
at-icon>
games
</mat
-icon>
<br>
房间列表
</a></m
at
-grid-tile>
<m
at-grid-tile><a
mat
-raised-button
color=
"primary"
routerLink=
"/ygopro/rooms/new"
>
<m
at-icon>

</mat
-icon>
<!--add_box-->
<br>
创建房间
</a></m
at
-grid-tile>
<m
at-grid-tile><a
mat
-raised-button
routerLink=
"/ygopro/windbot"
>
<m
at-icon>

</mat
-icon>
<!-- airplanemode_active -->
<br>
单人模式
</a></m
at
-grid-tile>
<m
at-grid-tile><a
mat
-raised-button
routerLink=
"/ygopro/watch"
>
<m
at-icon>

</mat
-icon>
<!--remove_red_eye-->
<br>
观战
</a></m
at
-grid-tile>
<!--<m
at
-grid-tile>-->
<!--<button m
at
-raised-button (click)="ygopro.watch_replay()">-->
<!--<m
at-icon>history</mat
-icon>-->
<!--<br>观看录像-->
<!--</button>-->
<!--</m
d
-grid-tile>-->
<m
d
-grid-tile>
<button
m
d
-raised-button
(click)=
"ygopro.edit_deck()"
>
<m
d-icon>
edit
</md
-icon>
<!--</m
at
-grid-tile>-->
<m
at
-grid-tile>
<button
m
at
-raised-button
(click)=
"ygopro.edit_deck()"
>
<m
at-icon>
edit
</mat
-icon>
<br>
编辑卡组
</button>
</m
d
-grid-tile>
<m
d-grid-tile><a
md
-raised-button
href=
"https://ygobbs.com"
target=
"_blank"
>
<m
d-icon>
forum
</md
-icon>
<br>
社区
</a></m
d
-grid-tile>
<m
d-grid-tile><a
md
-raised-button
[href]=
"arena_url"
target=
"_blank"
>
<m
d-icon
fontSet=
"fa"
fontIcon=
"fa-trophy"
></md
-icon>
<br>
决斗数据库
</a></m
d
-grid-tile>
<m
d
-grid-tile>
<button
m
d
-raised-button
(click)=
"ygopro.backHome()"
><span
class=
"icon"
>
233
</span><br>
直连
</button>
</m
d
-grid-tile>
</m
d
-grid-list>
</m
at
-grid-tile>
<m
at-grid-tile><a
mat
-raised-button
href=
"https://ygobbs.com"
target=
"_blank"
>
<m
at-icon>
forum
</mat
-icon>
<br>
社区
</a></m
at
-grid-tile>
<m
at-grid-tile><a
mat
-raised-button
[href]=
"arena_url"
target=
"_blank"
>
<m
at-icon
fontSet=
"fa"
fontIcon=
"fa-trophy"
></mat
-icon>
<br>
决斗数据库
</a></m
at
-grid-tile>
<m
at
-grid-tile>
<button
m
at
-raised-button
(click)=
"ygopro.backHome()"
><span
class=
"icon"
>
233
</span><br>
直连
</button>
</m
at
-grid-tile>
</m
at
-grid-list>
<m
d
-card
*ngIf=
"ygopro.points"
>
<m
d
-grid-list
id=
"points"
cols=
"4"
rowHeight=
"20px"
>
<m
d
-grid-tile>
<m
at
-card
*ngIf=
"ygopro.points"
>
<m
at
-grid-list
id=
"points"
cols=
"4"
rowHeight=
"20px"
>
<m
at
-grid-tile>
<dt>
竞技排名
</dt>
</m
d
-grid-tile>
<m
d
-grid-tile>
</m
at
-grid-tile>
<m
at
-grid-tile>
<dd>
{{ygopro.points.arena_rank}}
</dd>
</m
d
-grid-tile>
<m
d
-grid-tile>
</m
at
-grid-tile>
<m
at
-grid-tile>
<dt>
娱乐排名
</dt>
</m
d
-grid-tile>
<m
d
-grid-tile>
</m
at
-grid-tile>
<m
at
-grid-tile>
<dd>
{{ygopro.points.exp_rank}}
</dd>
</m
d
-grid-tile>
<m
d
-grid-tile>
</m
at
-grid-tile>
<m
at
-grid-tile>
<dt>
竞技胜率
</dt>
</m
d
-grid-tile>
<m
d
-grid-tile>
</m
at
-grid-tile>
<m
at
-grid-tile>
<dd>
{{ygopro.points.athletic_wl_ratio}}%
</dd>
</m
d
-grid-tile>
<m
d
-grid-tile>
</m
at
-grid-tile>
<m
at
-grid-tile>
<dt>
经验
</dt>
</m
d
-grid-tile>
<m
d
-grid-tile>
</m
at
-grid-tile>
<m
at
-grid-tile>
<dd>
{{ygopro.points.exp}}
</dd>
</m
d
-grid-tile>
<m
d
-grid-tile>
</m
at
-grid-tile>
<m
at
-grid-tile>
<dt>
胜场
</dt>
</m
d
-grid-tile>
<m
d
-grid-tile>
</m
at
-grid-tile>
<m
at
-grid-tile>
<dd>
{{ygopro.points.athletic_win}}
</dd>
</m
d
-grid-tile>
<m
d
-grid-tile>
</m
at
-grid-tile>
<m
at
-grid-tile>
<dt>
胜场
</dt>
</m
d
-grid-tile>
<m
d
-grid-tile>
</m
at
-grid-tile>
<m
at
-grid-tile>
<dd>
{{ygopro.points.entertain_win}}
</dd>
</m
d
-grid-tile>
<m
d
-grid-tile>
</m
at
-grid-tile>
<m
at
-grid-tile>
<dt>
负场
</dt>
</m
d
-grid-tile>
<m
d
-grid-tile>
</m
at
-grid-tile>
<m
at
-grid-tile>
<dd>
{{ygopro.points.athletic_lose}}
</dd>
</m
d
-grid-tile>
<m
d
-grid-tile>
</m
at
-grid-tile>
<m
at
-grid-tile>
<dt>
负场
</dt>
</m
d
-grid-tile>
<m
d
-grid-tile>
</m
at
-grid-tile>
<m
at
-grid-tile>
<dd>
{{ygopro.points.entertain_lose}}
</dd>
</m
d
-grid-tile>
<m
d
-grid-tile>
</m
at
-grid-tile>
<m
at
-grid-tile>
<dt>
平局
</dt>
</m
d
-grid-tile>
<m
d
-grid-tile>
</m
at
-grid-tile>
<m
at
-grid-tile>
<dd>
{{ygopro.points.athletic_draw}}
</dd>
</m
d
-grid-tile>
<m
d
-grid-tile>
</m
at
-grid-tile>
<m
at
-grid-tile>
<dt>
平局
</dt>
</m
d
-grid-tile>
<m
d
-grid-tile>
</m
at
-grid-tile>
<m
at
-grid-tile>
<dd>
{{ygopro.points.entertain_draw}}
</dd>
</m
d
-grid-tile>
<m
d
-grid-tile>
</m
at
-grid-tile>
<m
at
-grid-tile>
<dt>
总场
</dt>
</m
d
-grid-tile>
<m
d
-grid-tile>
</m
at
-grid-tile>
<m
at
-grid-tile>
<dd>
{{ygopro.points.athletic_all}}
</dd>
</m
d
-grid-tile>
<m
d
-grid-tile>
</m
at
-grid-tile>
<m
at
-grid-tile>
<dt>
总场
</dt>
</m
d
-grid-tile>
<m
d
-grid-tile>
</m
at
-grid-tile>
<m
at
-grid-tile>
<dd>
{{ygopro.points.entertain_all}}
</dd>
</m
d
-grid-tile>
</m
d
-grid-list>
</m
d
-card>
<m
d
-card
*ngFor=
"let item of ygopro.news"
class=
"example-card"
>
</m
at
-grid-tile>
</m
at
-grid-list>
</m
at
-card>
<m
at
-card
*ngFor=
"let item of ygopro.news"
class=
"example-card"
>
<a
[href]=
"item.url"
target=
"_blank"
>
<m
d
-card-header>
<img
*ngIf=
"item.image"
m
d
-card-avatar
[src]=
"item.image"
>
<m
d-card-title>
{{item.title}}
</md
-card-title>
<m
d-card-subtitle>
{{item.updated_at | date}}
</md
-card-subtitle>
</m
d
-card-header>
<m
at
-card-header>
<img
*ngIf=
"item.image"
m
at
-card-avatar
[src]=
"item.image"
>
<m
at-card-title>
{{item.title}}
</mat
-card-title>
<m
at-card-subtitle>
{{item.updated_at | date}}
</mat
-card-subtitle>
</m
at
-card-header>
</a>
</m
d
-card>
</m
at
-card>
<m
d
-card
*ngFor=
"let item of ygopro.topics | async"
>
<m
at
-card
*ngFor=
"let item of ygopro.topics | async"
>
<a
[href]=
"item.url"
target=
"_blank"
>
<m
d
-card-header>
<img
*ngIf=
"item.image_url"
m
d
-card-avatar
[src]=
"item.image_url"
>
<m
d-card-title>
{{item.title}}
</md
-card-title>
<m
d
-card-subtitle>
by {{item.last_poster_username}} / {{item.last_posted_at | date}}
</m
d
-card-subtitle>
</m
d
-card-header>
<m
at
-card-header>
<img
*ngIf=
"item.image_url"
m
at
-card-avatar
[src]=
"item.image_url"
>
<m
at-card-title>
{{item.title}}
</mat
-card-title>
<m
at
-card-subtitle>
by {{item.last_poster_username}} / {{item.last_posted_at | date}}
</m
at
-card-subtitle>
</m
at
-card-header>
</a>
</m
d
-card>
</m
at
-card>
src/app/match/match.component.css
View file @
cd8508f4
m
d
-icon
{
m
at
-icon
{
width
:
96px
;
height
:
96px
;
font-size
:
96px
;
}
m
d
-dialog-content
{
m
at
-dialog-content
{
display
:
flex
;
}
m
d
-dialog-actions
{
m
at
-dialog-actions
{
justify-content
:
flex-end
}
ul
{
...
...
src/app/match/match.component.html
View file @
cd8508f4
<h2
m
d
-dialog-title
*ngIf=
"arena == 'athletic'"
>
竞技匹配
</h2>
<h2
m
d
-dialog-title
*ngIf=
"arena == 'entertain'"
>
娱乐匹配
</h2>
<h2
m
at
-dialog-title
*ngIf=
"arena == 'athletic'"
>
竞技匹配
</h2>
<h2
m
at
-dialog-title
*ngIf=
"arena == 'entertain'"
>
娱乐匹配
</h2>
<m
d
-dialog-content>
<m
d-icon
*ngIf=
"arena == 'athletic'"
fontSet=
"fa"
fontIcon=
"fa-futbol-o"
class=
"fa-spin"
></md
-icon>
<m
d-icon
*ngIf=
"arena == 'entertain'"
class=
"fa-spin"
>
toys
</md
-icon>
<m
at
-dialog-content>
<m
at-icon
*ngIf=
"arena == 'athletic'"
fontSet=
"fa"
fontIcon=
"fa-futbol-o"
class=
"fa-spin"
></mat
-icon>
<m
at-icon
*ngIf=
"arena == 'entertain'"
class=
"fa-spin"
>
toys
</mat
-icon>
<ul>
<dt>
预计等待时间
</dt>
<dd>
{{expect_wait | async | date: 'mm:ss'}}
</dd>
<dt>
实际等待时间
</dt>
<dd>
{{actual_wait | async | date: 'mm:ss'}}
</dd>
</ul>
</m
d
-dialog-content>
<m
d
-dialog-actions>
<button
m
d-button
md
-dialog-close
>
取消
</button>
</m
d
-dialog-actions>
</m
at
-dialog-content>
<m
at
-dialog-actions>
<button
m
at-button
mat
-dialog-close
>
取消
</button>
</m
at
-dialog-actions>
src/app/match/match.component.ts
View file @
cd8508f4
import
{
Component
,
Inject
,
OnDestroy
,
OnInit
}
from
'
@angular/core
'
;
import
{
Headers
,
Http
}
from
'
@angular/http
'
;
import
{
M
D_DIALOG_DATA
,
Md
DialogRef
}
from
'
@angular/material
'
;
import
{
M
AT_DIALOG_DATA
,
Mat
DialogRef
}
from
'
@angular/material
'
;
import
{
Observable
}
from
'
rxjs/Observable
'
;
import
{
Subscription
}
from
'
rxjs/Subscription
'
;
import
{
LoginService
}
from
'
../login.service
'
;
...
...
@@ -14,34 +14,39 @@ 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
(
MD_DIALOG_DATA
)
public
arena
:
string
,
private
dialogRef
:
MdDialogRef
<
MatchDialogComponent
>
,
private
http
:
Http
,
private
login
:
LoginService
)
{
}
constructor
(
@
Inject
(
MAT_DIALOG_DATA
)
public
arena
:
string
,
private
dialogRef
:
MatDialogRef
<
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
();
}
}
src/app/new-room/new-room.component.css
View file @
cd8508f4
...
...
@@ -11,7 +11,7 @@ form {
/*margin: 0 10px;*/
/*}*/
m
d
-select
{
m
at
-select
{
padding
:
1.2734375em
0
;
}
...
...
src/app/new-room/new-room.component.html
View file @
cd8508f4
<app-toolbar>
创建房间
</app-toolbar>
<form
(submit)=
"ygopro.create_room(room, host_password)"
ngNativeValidate
>
<m
d
-input-container
*ngIf=
"!room.private"
class=
"full-width"
>
<input
m
d
Input
placeholder=
"游戏标题"
name=
"title"
[(ngModel)]=
"room.title"
minlength=
"1"
maxlength=
"12"
required
>
<m
d-hint
align=
"end"
>
{{room.title?.length || 0}} / 12
</md
-hint>
</m
d
-input-container>
<m
d
-input-container
*ngIf=
"room.private"
class=
"full-width"
>
<m
d
-placeholder>
<m
d-icon>

</md
-icon>
<!-- vpn_key -->
<m
at
-input-container
*ngIf=
"!room.private"
class=
"full-width"
>
<input
m
at
Input
placeholder=
"游戏标题"
name=
"title"
[(ngModel)]=
"room.title"
minlength=
"1"
maxlength=
"12"
required
>
<m
at-hint
align=
"end"
>
{{room.title?.length || 0}} / 12
</mat
-hint>
</m
at
-input-container>
<m
at
-input-container
*ngIf=
"room.private"
class=
"full-width"
>
<m
at
-placeholder>
<m
at-icon>

</mat
-icon>
<!-- vpn_key -->
<span>
房间密码
</span>
</m
d
-placeholder>
<input
#hostPasswordInput
m
d
Input
name=
"title"
[(ngModel)]=
"host_password"
readonly
>
<button
type=
"button"
m
d-icon-button
md
Suffix
(click)=
"copy(host_password)"
>
<m
d-icon>

</md
-icon>
<!-- content_copy -->
</m
at
-placeholder>
<input
#hostPasswordInput
m
at
Input
name=
"title"
[(ngModel)]=
"host_password"
readonly
>
<button
type=
"button"
m
at-icon-button
mat
Suffix
(click)=
"copy(host_password)"
>
<m
at-icon>

</mat
-icon>
<!-- content_copy -->
</button>
<button
type=
"button"
m
d-icon-button
md
Suffix
(click)=
"share(host_password)"
>
<m
d-icon>
share
</md
-icon>
<button
type=
"button"
m
at-icon-button
mat
Suffix
(click)=
"share(host_password)"
>
<m
at-icon>
share
</mat
-icon>
</button>
<m
d-hint
align=
"end"
>
把这个分享给你的朋友
</md
-hint>
</m
d
-input-container>
<m
d
-select
class=
"full-width"
placeholder=
"卡片允许"
name=
"rule"
[(ngModel)]=
"room.options.rule"
required
>
<m
d-option
[value]=
"0"
>
OCG
</md
-option>
<m
d-option
[value]=
"1"
>
TCG
</md
-option>
<m
d-option
[value]=
"2"
>
OCG
&
TCG
</md
-option>
<m
d-option
[value]=
"3"
>
专有卡禁止
</md
-option>
</m
d
-select>
<m
d
-select
class=
"full-width"
placeholder=
"决斗模式"
name=
"mode"
[(ngModel)]=
"room.options.mode"
(ngModelChange)=
"set_start_lp()"
required
>
<m
d-option
[value]=
"0"
>
单局模式
</md
-option>
<m
d-option
[value]=
"1"
>
比赛模式
</md
-option>
<m
d-option
[value]=
"2"
>
TAG
</md
-option>
</m
d
-select>
<m
at-hint
align=
"end"
>
把这个分享给你的朋友
</mat
-hint>
</m
at
-input-container>
<m
at
-select
class=
"full-width"
placeholder=
"卡片允许"
name=
"rule"
[(ngModel)]=
"room.options.rule"
required
>
<m
at-option
[value]=
"0"
>
OCG
</mat
-option>
<m
at-option
[value]=
"1"
>
TCG
</mat
-option>
<m
at-option
[value]=
"2"
>
OCG
&
TCG
</mat
-option>
<m
at-option
[value]=
"3"
>
专有卡禁止
</mat
-option>
</m
at
-select>
<m
at
-select
class=
"full-width"
placeholder=
"决斗模式"
name=
"mode"
[(ngModel)]=
"room.options.mode"
(ngModelChange)=
"set_start_lp()"
required
>
<m
at-option
[value]=
"0"
>
单局模式
</mat
-option>
<m
at-option
[value]=
"1"
>
比赛模式
</mat
-option>
<m
at-option
[value]=
"2"
>
TAG
</mat
-option>
</m
at
-select>
<!--<h2>额外选项</h2>-->
<!--<m
d-slide-toggle #extra class="example-margin" color="primary">额外选项</md
-slide-toggle>-->
<!--<m
at-slide-toggle #extra class="example-margin" color="primary">额外选项</mat
-slide-toggle>-->
<m
d
-input-container
class=
"full-width"
>
<input
name=
"start_lp"
[(ngModel)]=
"room.options.start_lp"
m
d
Input
type=
"number"
min=
"1"
max=
"65536"
placeholder=
"初始 LP"
required
>
</m
d
-input-container>
<m
d
-input-container
class=
"full-width"
>
<input
name=
"start_hand"
[(ngModel)]=
"room.options.start_hand"
m
d
Input
type=
"number"
min=
"0"
max=
"16"
placeholder=
"初始手牌数"
required
>
</m
d
-input-container>
<m
d
-input-container
class=
"full-width"
>
<input
name=
"draw_count"
[(ngModel)]=
"room.options.draw_count"
m
d
Input
type=
"number"
min=
"0"
max=
"16"
placeholder=
"每回合抽卡"
required
>
</m
d
-input-container>
<m
at
-input-container
class=
"full-width"
>
<input
name=
"start_lp"
[(ngModel)]=
"room.options.start_lp"
m
at
Input
type=
"number"
min=
"1"
max=
"65536"
placeholder=
"初始 LP"
required
>
</m
at
-input-container>
<m
at
-input-container
class=
"full-width"
>
<input
name=
"start_hand"
[(ngModel)]=
"room.options.start_hand"
m
at
Input
type=
"number"
min=
"0"
max=
"16"
placeholder=
"初始手牌数"
required
>
</m
at
-input-container>
<m
at
-input-container
class=
"full-width"
>
<input
name=
"draw_count"
[(ngModel)]=
"room.options.draw_count"
m
at
Input
type=
"number"
min=
"0"
max=
"16"
placeholder=
"每回合抽卡"
required
>
</m
at
-input-container>
<m
d-checkbox
class=
"full-width"
name=
"room.private"
[(ngModel)]=
"room.private"
>
私密房间
</md
-checkbox>
<m
d
-checkbox
class=
"full-width"
name=
"room.enable_priority"
[(ngModel)]=
"room.options.enable_priority"
>
旧规则
</m
d
-checkbox>
<m
d-checkbox
class=
"full-width"
name=
"room.no_check_deck"
[(ngModel)]=
"room.options.no_check_deck"
>
不检查卡组
</md
-checkbox>
<m
d
-checkbox
class=
"full-width"
name=
"room.no_shuffle_deck"
[(ngModel)]=
"room.options.no_shuffle_deck"
>
不洗切卡组
</m
d
-checkbox>
<m
at-checkbox
class=
"full-width"
name=
"room.private"
[(ngModel)]=
"room.private"
>
私密房间
</mat
-checkbox>
<m
at
-checkbox
class=
"full-width"
name=
"room.enable_priority"
[(ngModel)]=
"room.options.enable_priority"
>
旧规则
</m
at
-checkbox>
<m
at-checkbox
class=
"full-width"
name=
"room.no_check_deck"
[(ngModel)]=
"room.options.no_check_deck"
>
不检查卡组
</mat
-checkbox>
<m
at
-checkbox
class=
"full-width"
name=
"room.no_shuffle_deck"
[(ngModel)]=
"room.options.no_shuffle_deck"
>
不洗切卡组
</m
at
-checkbox>
<div
id=
"actions"
>
<!--<button routerLink="/ygopro/lobby" m
d
-raised-button>返回大厅</button>-->
<button
type=
"submit"
color=
"primary"
m
d
-raised-button
>
创建游戏
</button>
<!--<button routerLink="/ygopro/lobby" m
at
-raised-button>返回大厅</button>-->
<button
type=
"submit"
color=
"primary"
m
at
-raised-button
>
创建游戏
</button>
</div>
</form>
src/app/new-room/new-room.component.ts
View file @
cd8508f4
import
{
Component
,
ElementRef
,
HostBinding
,
ViewChild
}
from
'
@angular/core
'
;
import
{
M
d
SnackBar
}
from
'
@angular/material
'
;
import
{
M
at
SnackBar
}
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
:
M
d
SnackBar
)
{
constructor
(
public
ygopro
:
YGOProService
,
private
login
:
LoginService
,
private
snackBar
:
M
at
SnackBar
)
{
}
copy
(
host_password
:
string
)
{
...
...
src/app/result/result.dialog.css
View file @
cd8508f4
m
d
-list-item
/
deep
/
.mat-list-item-content
{
m
at
-list-item
/
deep
/
.mat-list-item-content
{
justify-content
:
space-between
;
height
:
28px
!important
;
padding
:
0
}
m
d
-grid-list
{
m
at
-grid-list
{
font-size
:
14px
;
}
m
d-grid-tile
dt
,
md
-grid-tile
dd
{
m
at-grid-tile
dt
,
mat
-grid-tile
dd
{
width
:
100%
;
}
m
d
-grid-tile
{
m
at
-grid-tile
{
text-align
:
left
;
}
m
d
-grid-tile
dd
{
m
at
-grid-tile
dd
{
margin
:
0
;
text-align
:
left
;
}
...
...
src/app/result/result.dialog.html
View file @
cd8508f4
<h2
m
d
-dialog-title
*ngIf=
"result === 'win'"
>
胜利
</h2>
<h2
m
d
-dialog-title
*ngIf=
"result === 'lose'"
>
败北
</h2>
<h2
m
d
-dialog-title
*ngIf=
"result === 'draw'"
>
平局
</h2>
<m
d
-dialog-content>
<m
d
-list
[ngClass]=
"result"
*ngIf=
"dp || exp || firstWin"
>
<m
d
-list-item
*ngIf=
"dp"
>
<h2
m
at
-dialog-title
*ngIf=
"result === 'win'"
>
胜利
</h2>
<h2
m
at
-dialog-title
*ngIf=
"result === 'lose'"
>
败北
</h2>
<h2
m
at
-dialog-title
*ngIf=
"result === 'draw'"
>
平局
</h2>
<m
at
-dialog-content>
<m
at
-list
[ngClass]=
"result"
*ngIf=
"dp || exp || firstWin"
>
<m
at
-list-item
*ngIf=
"dp"
>
<dt>
D.P
</dt>
<dd>
{{dp}}
</dd>
</m
d
-list-item>
<m
d
-list-item
*ngIf=
"exp"
>
</m
at
-list-item>
<m
at
-list-item
*ngIf=
"exp"
>
<dt>
EXP
</dt>
<dd>
{{exp}}
</dd>
</m
d
-list-item>
<m
d
-list-item
*ngIf=
"firstWin"
>
</m
at
-list-item>
<m
at
-list-item
*ngIf=
"firstWin"
>
<dt>
D.P (首胜)
</dt>
<dd>
{{firstWin}}
</dd>
</m
d
-list-item>
</m
d
-list>
</m
d
-dialog-content>
<m
d
-dialog-actions>
<button
m
d-button
md
-dialog-close
>
关闭
</button>
</m
at
-list-item>
</m
at
-list>
</m
at
-dialog-content>
<m
at
-dialog-actions>
<button
m
at-button
mat
-dialog-close
>
关闭
</button>
<!-- Can optionally provide a result for the closing dialog. -->
<button
m
d
-button
(click)=
"again()"
>
再来一局
</button>
</m
d
-dialog-actions>
<button
m
at
-button
(click)=
"again()"
>
再来一局
</button>
</m
at
-dialog-actions>
src/app/result/result.dialog.ts
View file @
cd8508f4
import
{
Component
,
Inject
}
from
'
@angular/core
'
;
import
{
Http
}
from
'
@angular/http
'
;
import
{
M
D_DIALOG_DATA
,
MdDialog
,
Md
DialogRef
}
from
'
@angular/material
'
;
import
{
M
AT_DIALOG_DATA
,
MatDialog
,
Mat
DialogRef
}
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
(
M
D
_DIALOG_DATA
)
public
last
:
any
,
constructor
(@
Inject
(
M
AT
_DIALOG_DATA
)
public
last
:
any
,
public
login
:
LoginService
,
private
http
:
Http
,
public
dialog
:
M
d
Dialog
,
private
dialogRef
:
M
d
DialogRef
<
MatchDialogComponent
>
)
{
public
dialog
:
M
at
Dialog
,
private
dialogRef
:
M
at
DialogRef
<
MatchDialogComponent
>
)
{
if
(
this
.
last
.
userscorea
===
this
.
last
.
userscoreb
)
{
this
.
result
=
'
draw
'
;
}
else
if
(
this
.
last
.
winner
===
this
.
login
.
user
.
username
)
{
...
...
src/app/room-list/room-list.component.css
View file @
cd8508f4
...
...
@@ -26,7 +26,7 @@
flex
:
2
}
m
d
-table
{
m
at
-table
{
flex
:
1
;
padding-bottom
:
36px
;
}
...
...
src/app/room-list/room-list.component.html
View file @
cd8508f4
<app-toolbar>
房间列表
</app-toolbar>
<div
class=
"hint"
*ngIf=
"dataSource.loading"
><m
d-spinner></md
-spinner></div>
<div
class=
"hint"
*ngIf=
"dataSource.loading"
><m
at-spinner></mat
-spinner></div>
<div
class=
"hint"
*ngIf=
"dataSource.empty"
>
现在没有等待中的游戏,可以自行创建一个房间或者去匹配
</div>
<div
class=
"hint"
*ngIf=
"dataSource.error"
>
网络错误
</div>
<m
d
-table
#table
[dataSource]=
"dataSource"
>
<m
at
-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
cdk
ColumnDef=
"title"
>
<m
d-header-cell
class=
"game-title"
*cdkHeaderCellDef
>
游戏标题
</md
-header-cell>
<m
d-cell
class=
"game-title"
*cdkCellDef=
"let room"
>
{{room.title}}
</md
-cell>
<ng-container
mat
ColumnDef=
"title"
>
<m
at-header-cell
class=
"game-title"
*matHeaderCellDef
>
游戏标题
</mat
-header-cell>
<m
at-cell
class=
"game-title"
*matCellDef=
"let room"
>
{{room.title}}
</mat
-cell>
</ng-container>
<!-- Progress Column -->
<ng-container
cdk
ColumnDef=
"users"
>
<m
d-header-cell
*cdkHeaderCellDef
>
玩家
</md
-header-cell>
<m
d-cell
*cdk
CellDef=
"let room"
>
<ng-container
mat
ColumnDef=
"users"
>
<m
at-header-cell
*matHeaderCellDef
>
玩家
</mat
-header-cell>
<m
at-cell
*mat
CellDef=
"let room"
>
<img
*ngFor=
"let user of room.users"
class=
"avatar"
[src]=
"login.avatar(user.username)"
>
</m
d
-cell>
</m
at
-cell>
</ng-container>
<!-- Name Column -->
<ng-container
cdk
ColumnDef=
"mode"
>
<m
d-header-cell
*cdkHeaderCellDef
>
决斗模式
</md
-header-cell>
<m
d-cell
*cdk
CellDef=
"let room"
>
<ng-container
mat
ColumnDef=
"mode"
>
<m
at-header-cell
*matHeaderCellDef
>
决斗模式
</mat
-header-cell>
<m
at-cell
*mat
CellDef=
"let room"
>
<span
*ngIf=
"room.options.mode === 0"
>
单局模式
</span>
<span
*ngIf=
"room.options.mode === 1"
>
比赛模式
</span>
<span
*ngIf=
"room.options.mode === 2"
>
TAG
</span>
</m
d
-cell>
</m
at
-cell>
</ng-container>
<!-- Color Column -->
<ng-container
cdk
ColumnDef=
"extra"
>
<m
d-header-cell
*cdkHeaderCellDef
>
额外选项
</md
-header-cell>
<m
d-cell
*cdk
CellDef=
"let room"
>
<ng-container
mat
ColumnDef=
"extra"
>
<m
at-header-cell
*matHeaderCellDef
>
额外选项
</mat
-header-cell>
<m
at-cell
*mat
CellDef=
"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>
</m
d
-cell>
</m
at
-cell>
</ng-container>
<m
d-header-row
*cdkHeaderRowDef=
"displayedColumns"
></md
-header-row>
<m
d-row
*cdkRowDef=
"let room; columns: displayedColumns;"
(click)=
"ygopro.join_room(room)"
></md
-row>
</m
d
-table>
<m
at-header-row
*matHeaderRowDef=
"displayedColumns"
></mat
-header-row>
<m
at-row
*matRowDef=
"let room; columns: displayedColumns;"
(click)=
"ygopro.join_room(room)"
></mat
-row>
</m
at
-table>
<form
(submit)=
"ygopro.join_private(joinPassword.value)"
ngNativeValidate
>
<input
#joinPassword
placeholder=
"在这输入你朋友的私密房间密码就可以进去了哦!"
required
>
<button
m
d
-raised-button
color=
"primary"
>
加入私密房间
</button>
<button
m
at
-raised-button
color=
"primary"
>
加入私密房间
</button>
</form>
src/app/storage.service.ts
View file @
cd8508f4
...
...
@@ -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
(
data
.
buffer
).
toString
(
'
base64
'
));
window
.
ygopro
.
writeFile
(
local_path
,
Buffer
.
from
(
<
ArrayBuffer
>
data
.
buffer
).
toString
(
'
base64
'
));
window
.
ygopro
.
setFileLastModified
(
local_path
,
time
);
// console.log(local_path, time);
localStorage
.
setItem
(
index_path
,
time
.
toString
());
...
...
src/app/toolbar/toolbar.component.html
View file @
cd8508f4
<m
d
-toolbar
color=
"primary"
>
<button
m
d
-icon-button
(click)=
"history.back()"
>
<m
d-icon>

</md
-icon>
<!--arrow_back-->
</button>
<m
at
-toolbar
color=
"primary"
>
<button
m
at
-icon-button
(click)=
"history.back()"
>
<m
at-icon>

</mat
-icon>
<!--arrow_back-->
</button>
<span><ng-content></ng-content></span>
</m
d
-toolbar>
</m
at
-toolbar>
src/app/watch/watch.component.html
View file @
cd8508f4
<app-toolbar>
观战
</app-toolbar>
<div
class=
"hint"
*ngIf=
"dataSource.loading"
><m
d-spinner></md
-spinner></div>
<div
class=
"hint"
*ngIf=
"dataSource.loading"
><m
at-spinner></mat
-spinner></div>
<div
class=
"hint"
*ngIf=
"dataSource.empty"
>
现在没有进行中的游戏
</div>
<div
class=
"hint"
*ngIf=
"dataSource.error"
>
网络错误
</div>
<m
d
-table
#table
[dataSource]=
"dataSource"
>
<m
at
-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
cdk
ColumnDef=
"mode"
>
<m
d-header-cell
*cdkHeaderCellDef
>
游戏模式
</md
-header-cell>
<m
d-cell
*cdk
CellDef=
"let room"
>
<ng-container
mat
ColumnDef=
"mode"
>
<m
at-header-cell
*matHeaderCellDef
>
游戏模式
</mat
-header-cell>
<m
at-cell
*mat
CellDef=
"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>
</m
d
-cell>
</m
at
-cell>
</ng-container>
<!-- ID Column -->
<ng-container
cdk
ColumnDef=
"title"
>
<m
d-header-cell
class=
"game-title"
*cdkHeaderCellDef
>
游戏标题
</md
-header-cell>
<m
d-cell
class=
"game-title"
*cdk
CellDef=
"let room"
>
<ng-container
mat
ColumnDef=
"title"
>
<m
at-header-cell
class=
"game-title"
*matHeaderCellDef
>
游戏标题
</mat
-header-cell>
<m
at-cell
class=
"game-title"
*mat
CellDef=
"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>
</m
d
-cell>
</m
at
-cell>
</ng-container>
<!-- Progress Column -->
<ng-container
cdk
ColumnDef=
"users"
>
<m
d-header-cell
*cdkHeaderCellDef
>
玩家
</md
-header-cell>
<m
d-cell
*cdk
CellDef=
"let room"
>
<ng-container
mat
ColumnDef=
"users"
>
<m
at-header-cell
*matHeaderCellDef
>
玩家
</mat
-header-cell>
<m
at-cell
*mat
CellDef=
"let room"
>
<img
*ngFor=
"let user of room.users"
class=
"avatar"
[src]=
"login.avatar(user.username)"
>
</m
d
-cell>
</m
at
-cell>
</ng-container>
<!-- Color Column -->
<ng-container
cdk
ColumnDef=
"extra"
>
<m
d-header-cell
*cdkHeaderCellDef
>
额外选项
</md
-header-cell>
<m
d-cell
*cdk
CellDef=
"let room"
>
<ng-container
mat
ColumnDef=
"extra"
>
<m
at-header-cell
*matHeaderCellDef
>
额外选项
</mat
-header-cell>
<m
at-cell
*mat
CellDef=
"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>
</m
d
-cell>
</m
at
-cell>
</ng-container>
<m
d-header-row
*cdkHeaderRowDef=
"displayedColumns"
></md
-header-row>
<m
d-row
*cdkRowDef=
"let room; columns: displayedColumns;"
(click)=
"ygopro.join_room(room)"
></md
-row>
</m
d
-table>
<m
at-header-row
*matHeaderRowDef=
"displayedColumns"
></mat
-header-row>
<m
at-row
*matRowDef=
"let room; columns: displayedColumns;"
(click)=
"ygopro.join_room(room)"
></mat
-row>
</m
at
-table>
src/app/windbot/windbot.component.html
View file @
cd8508f4
<app-toolbar>
单人模式
</app-toolbar>
<m
d
-list>
<h3
m
d
-subheader
>
选择对手
</h3>
<m
d
-list-item
(click)=
"ygopro.join_windbot()"
>
<m
d-icon
md-list-icon
>

</md
-icon>
<!-- airplanemode_active -->
<h4
m
d
-line
>
随机
</h4>
</m
d
-list-item>
<m
d
-list-item
*ngFor=
"let windbot of ygopro.windbot"
(click)=
"ygopro.join_windbot(windbot)"
>
<img
m
d
-list-icon
[src]=
"login.avatar(windbot)"
>
<h4
m
d
-line
>
{{windbot}}
</h4>
</m
d
-list-item>
</m
d
-list>
<m
at
-list>
<h3
m
at
-subheader
>
选择对手
</h3>
<m
at
-list-item
(click)=
"ygopro.join_windbot()"
>
<m
at-icon
mat-list-icon
>

</mat
-icon>
<!-- airplanemode_active -->
<h4
m
at
-line
>
随机
</h4>
</m
at
-list-item>
<m
at
-list-item
*ngFor=
"let windbot of ygopro.windbot"
(click)=
"ygopro.join_windbot(windbot)"
>
<img
m
at
-list-icon
[src]=
"login.avatar(windbot)"
>
<h4
m
at
-line
>
{{windbot}}
</h4>
</m
at
-list-item>
</m
at
-list>
src/app/ygopro.service.ts
View file @
cd8508f4
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,7 +42,6 @@ export interface Options {
time_limit
?:
number
;
}
export
interface
Server
{
id
?:
string
;
url
?:
string
;
...
...
@@ -110,7 +109,6 @@ export interface Points {
@
Injectable
()
export
class
YGOProService
{
news
:
News
[];
windbot
:
string
[];
topics
:
Observable
<
any
>
;
...
...
@@ -131,52 +129,62 @@ 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
:
MdDialog
,
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
:
MatDialog
,
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
)
{
...
...
@@ -201,7 +209,10 @@ 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
);
}
...
...
@@ -209,18 +220,20 @@ 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
(()
=>
{
...
...
@@ -238,8 +251,10 @@ 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
)
{
...
...
@@ -247,27 +262,28 @@ 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
&
0x
FF
,
0
);
options_buffer
.
writeUInt8
(
checksum
&
0x
ff
,
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('/', '_');
...
...
@@ -286,7 +302,7 @@ export class YGOProService {
for
(
let
i
=
1
;
i
<
options_buffer
.
length
;
i
++
)
{
checksum
-=
options_buffer
.
readUInt8
(
i
);
}
options_buffer
.
writeUInt8
(
checksum
&
0x
FF
,
0
);
options_buffer
.
writeUInt8
(
checksum
&
0x
ff
,
0
);
const
secret
=
this
.
login
.
user
.
external_id
%
65535
+
1
;
for
(
let
i
=
0
;
i
<
options_buffer
.
length
;
i
+=
2
)
{
...
...
@@ -305,14 +321,14 @@ export class YGOProService {
for
(
let
i
=
1
;
i
<
options_buffer
.
length
;
i
++
)
{
checksum
-=
options_buffer
.
readUInt8
(
i
);
}
options_buffer
.
writeUInt8
(
checksum
&
0x
FF
,
0
);
options_buffer
.
writeUInt8
(
checksum
&
0x
ff
,
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
(
0x
FEFF
));
const
name
=
options_buffer
.
toString
(
'
base64
'
)
+
password
.
replace
(
/
\s
/
,
String
.
fromCharCode
(
0x
feff
));
this
.
join
(
name
,
this
.
servers
[
0
]);
}
...
...
@@ -329,10 +345,12 @@ 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
]
})
);
}
}
...
...
@@ -341,7 +359,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
:
[]
}));
}
}
...
...
@@ -350,7 +368,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
:
[]
}));
}
}
...
...
@@ -359,7 +377,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
:
[]
}));
}
}
...
...
@@ -368,7 +386,7 @@ export class YGOProService {
window
.
ygopro
.
openDrawer
();
}
catch
(
error
)
{
console
.
error
(
error
);
alert
(
JSON
.
stringify
({
method
:
'
openDrawer
'
,
params
:
[]
}));
alert
(
JSON
.
stringify
({
method
:
'
openDrawer
'
,
params
:
[]
}));
}
}
...
...
@@ -377,7 +395,7 @@ export class YGOProService {
window
.
ygopro
.
backHome
();
}
catch
(
error
)
{
console
.
error
(
error
);
alert
(
JSON
.
stringify
({
method
:
'
backHome
'
,
params
:
[]
}));
alert
(
JSON
.
stringify
({
method
:
'
backHome
'
,
params
:
[]
}));
}
}
...
...
@@ -386,21 +404,18 @@ 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
};
export
class
RoomListDataSource
extends
DataSource
<
any
>
{
|
{
event
:
'
init
'
;
data
:
Room
[]
}
|
{
event
:
'
update
'
;
data
:
Room
}
|
{
event
:
'
create
'
;
data
:
Room
}
|
{
event
:
'
delete
'
;
data
:
string
};
export
class
RoomListDataSource
extends
DataSource
<
Room
>
{
loading
=
true
;
empty
=
false
;
error
:
any
;
...
...
@@ -411,52 +426,57 @@ export class RoomListDataSource extends DataSource<any> {
/** 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
({
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
;
}
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
;
})
// 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
()
{
.
catch
(
error
=>
{
this
.
loading
=
false
;
this
.
error
=
error
;
return
[];
})
);
}
disconnect
()
{}
}
tsconfig.json
View file @
cd8508f4
...
...
@@ -15,6 +15,7 @@
"typeRoots"
:
[
"node_modules/@types"
],
"skipLibCheck"
:
true
,
"lib"
:
[
"esnext"
,
"dom.iterable"
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment