Commit 7bf51dcb authored by 神楽坂玲奈's avatar 神楽坂玲奈

更换动画,fix结果页

parent e2d51b9d
...@@ -7,6 +7,30 @@ ...@@ -7,6 +7,30 @@
"root": "", "root": "",
"sourceRoot": "src", "sourceRoot": "src",
"projectType": "application", "projectType": "application",
"prefix": "app",
"schematics": {
"@schematics/angular:class": {
"spec": false
},
"@schematics/angular:component": {
"spec": false
},
"@schematics/angular:directive": {
"spec": false
},
"@schematics/angular:guard": {
"spec": false
},
"@schematics/angular:module": {
"spec": false
},
"@schematics/angular:pipe": {
"spec": false
},
"@schematics/angular:service": {
"spec": false
}
},
"architect": { "architect": {
"build": { "build": {
"builder": "@angular-devkit/build-angular:browser", "builder": "@angular-devkit/build-angular:browser",
...@@ -14,11 +38,11 @@ ...@@ -14,11 +38,11 @@
"outputPath": "dist", "outputPath": "dist",
"index": "src/index.html", "index": "src/index.html",
"main": "src/main.ts", "main": "src/main.ts",
"tsConfig": "src/tsconfig.app.json",
"polyfills": "src/polyfills.ts", "polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.app.json",
"assets": [ "assets": [
"src/assets", "src/favicon.ico",
"src/favicon.ico" "src/assets"
], ],
"styles": [ "styles": [
"src/styles.css" "src/styles.css"
...@@ -27,6 +51,12 @@ ...@@ -27,6 +51,12 @@
}, },
"configurations": { "configurations": {
"production": { "production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true, "optimization": true,
"outputHashing": "all", "outputHashing": "all",
"sourceMap": true, "sourceMap": true,
...@@ -36,13 +66,7 @@ ...@@ -36,13 +66,7 @@
"extractLicenses": true, "extractLicenses": true,
"vendorChunk": false, "vendorChunk": false,
"buildOptimizer": true, "buildOptimizer": true,
"serviceWorker": true, "serviceWorker": true
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
]
} }
} }
}, },
...@@ -67,16 +91,16 @@ ...@@ -67,16 +91,16 @@
"builder": "@angular-devkit/build-angular:karma", "builder": "@angular-devkit/build-angular:karma",
"options": { "options": {
"main": "src/test.ts", "main": "src/test.ts",
"karmaConfig": "./karma.conf.js",
"polyfills": "src/polyfills.ts", "polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.spec.json", "tsConfig": "src/tsconfig.spec.json",
"scripts": [], "karmaConfig": "src/karma.conf.js",
"styles": [ "styles": [
"src/styles.css" "src/styles.css"
], ],
"scripts": [],
"assets": [ "assets": [
"src/assets", "src/favicon.ico",
"src/favicon.ico" "src/assets"
] ]
} }
}, },
...@@ -95,23 +119,25 @@ ...@@ -95,23 +119,25 @@
} }
}, },
"mycard-mobile-e2e": { "mycard-mobile-e2e": {
"root": "", "root": "e2e/",
"sourceRoot": "e2e",
"projectType": "application", "projectType": "application",
"architect": { "architect": {
"e2e": { "e2e": {
"builder": "@angular-devkit/build-angular:protractor", "builder": "@angular-devkit/build-angular:protractor",
"options": { "options": {
"protractorConfig": "./protractor.conf.js", "protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "mycard-mobile:serve" "devServerTarget": "mycard-mobile:serve"
},
"configurations": {
"production": {
"devServerTarget": "mycard-mobile:serve:production"
}
} }
}, },
"lint": { "lint": {
"builder": "@angular-devkit/build-angular:tslint", "builder": "@angular-devkit/build-angular:tslint",
"options": { "options": {
"tsConfig": [ "tsConfig": "e2e/tsconfig.e2e.json",
"e2e/tsconfig.e2e.json"
],
"exclude": [ "exclude": [
"**/node_modules/**" "**/node_modules/**"
] ]
...@@ -120,31 +146,5 @@ ...@@ -120,31 +146,5 @@
} }
} }
}, },
"defaultProject": "mycard-mobile", "defaultProject": "mycard-mobile"
"schematics": {
"@schematics/angular:class": {
"spec": false
},
"@schematics/angular:component": {
"spec": false,
"prefix": "app",
"styleext": "css"
},
"@schematics/angular:directive": {
"spec": false,
"prefix": "app"
},
"@schematics/angular:guard": {
"spec": false
},
"@schematics/angular:module": {
"spec": false
},
"@schematics/angular:pipe": {
"spec": false
},
"@schematics/angular:service": {
"spec": false
}
}
} }
{ {
"name": "mycard-mobile", "name": "mycard-mobile",
"version": "1.0.26", "version": "1.0.27",
"license": "UNLISENCED", "license": "UNLISENCED",
"scripts": { "scripts": {
"ng": "ng", "ng": "ng",
"start": "ng serve --aot", "start": "ng serve --aot --host 0.0.0.0",
"build": "ng build --i18n-locale zh-CN --base-href /mobile/ --prod && npm run fuck", "build": "ng build --i18n-locale zh-CN --base-href /mobile/ --prod && npm run fuck",
"build:dev": "ng build --i18n-locale zh-CN --base-href /mobile2/ --prod && npm run fuck", "build:dev": "ng build --i18n-locale zh-CN --base-href /mobile2/ --prod && npm run fuck",
"fuck": "patch -i service-worker.patch dist/ngsw-worker.js", "fuck": "patch -i service-worker.patch dist/ngsw-worker.js",
......
...@@ -7,6 +7,7 @@ import { NewRoomComponent } from './new-room/new-room.component'; ...@@ -7,6 +7,7 @@ import { NewRoomComponent } from './new-room/new-room.component';
import { RoomListComponent } from './room-list/room-list.component'; import { RoomListComponent } from './room-list/room-list.component';
import { WatchComponent } from './watch/watch.component'; import { WatchComponent } from './watch/watch.component';
import { WindbotComponent } from './windbot/windbot.component'; import { WindbotComponent } from './windbot/windbot.component';
import { DecksComponent } from './decks/decks.component';
const routes: Routes = [ const routes: Routes = [
{ {
...@@ -18,7 +19,8 @@ const routes: Routes = [ ...@@ -18,7 +19,8 @@ const routes: Routes = [
{ path: 'ygopro/rooms', component: RoomListComponent }, { path: 'ygopro/rooms', component: RoomListComponent },
{ path: 'ygopro/lobby', component: LobbyComponent }, { path: 'ygopro/lobby', component: LobbyComponent },
{ path: 'ygopro/windbot', component: WindbotComponent }, { path: 'ygopro/windbot', component: WindbotComponent },
{ path: 'ygopro/watch', component: WatchComponent } { path: 'ygopro/watch', component: WatchComponent },
{ path: 'ygopro/decks', component: DecksComponent }
] ]
} }
]; ];
......
import { ErrorHandler, NgModule } from '@angular/core'; import { ErrorHandler, isDevMode, NgModule, Provider } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { import {
MatAutocompleteModule, MatAutocompleteModule,
...@@ -38,10 +38,8 @@ import { WindbotComponent } from './windbot/windbot.component'; ...@@ -38,10 +38,8 @@ import { WindbotComponent } from './windbot/windbot.component';
import { YGOProService } from './ygopro.service'; import { YGOProService } from './ygopro.service';
import { HttpClientModule } from '@angular/common/http'; import { HttpClientModule } from '@angular/common/http';
import * as Raven from 'raven-js'; import * as Raven from 'raven-js';
import { DecksComponent } from './decks/decks.component';
Raven.config('https://a43997ca0d3a4aee8640ab90af35144b@sentry.io/1227659', { import { ConfirmDialogComponent } from './confirm-dialog/confirm-dialog.component';
release: environment.version
}).install();
export class RavenErrorHandler implements ErrorHandler { export class RavenErrorHandler implements ErrorHandler {
handleError(err: any): void { handleError(err: any): void {
...@@ -49,6 +47,14 @@ export class RavenErrorHandler implements ErrorHandler { ...@@ -49,6 +47,14 @@ export class RavenErrorHandler implements ErrorHandler {
} }
} }
let sentry: Provider[] = [];
if (!isDevMode()) {
Raven.config('https://a43997ca0d3a4aee8640ab90af35144b@sentry.io/1227659', {
release: environment.version
}).install();
sentry = [{ provide: ErrorHandler, useClass: RavenErrorHandler }];
}
@NgModule({ @NgModule({
declarations: [ declarations: [
AppComponent, AppComponent,
...@@ -59,7 +65,9 @@ export class RavenErrorHandler implements ErrorHandler { ...@@ -59,7 +65,9 @@ export class RavenErrorHandler implements ErrorHandler {
WindbotComponent, WindbotComponent,
WatchComponent, WatchComponent,
ToolbarComponent, ToolbarComponent,
ResultDialogComponent ResultDialogComponent,
DecksComponent,
ConfirmDialogComponent
], ],
imports: [ imports: [
BrowserModule, BrowserModule,
...@@ -86,8 +94,8 @@ export class RavenErrorHandler implements ErrorHandler { ...@@ -86,8 +94,8 @@ export class RavenErrorHandler implements ErrorHandler {
MatMenuModule, MatMenuModule,
MatProgressSpinnerModule MatProgressSpinnerModule
], ],
providers: [YGOProService, StorageService, { provide: ErrorHandler, useClass: RavenErrorHandler }], providers: [YGOProService, StorageService, ...sentry],
bootstrap: [AppComponent], bootstrap: [AppComponent],
entryComponents: [MatchDialogComponent, ResultDialogComponent] entryComponents: [MatchDialogComponent, ResultDialogComponent, ConfirmDialogComponent]
}) })
export class AppModule {} export class AppModule {}
<h2 mat-dialog-title>{{data.title}}</h2>
<mat-dialog-content>{{data.content}}</mat-dialog-content>
<mat-dialog-actions>
<button mat-button mat-dialog-close>取消</button>
<button mat-button [mat-dialog-close]="true" color="warn">删除</button>
</mat-dialog-actions>
import { Component, Inject, OnInit } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
@Component({
selector: 'app-confirm-dialog',
templateUrl: './confirm-dialog.component.html',
styleUrls: ['./confirm-dialog.component.css']
})
export class ConfirmDialogComponent implements OnInit {
constructor(public dialogRef: MatDialogRef<ConfirmDialogComponent>, @Inject(MAT_DIALOG_DATA) public data: any) {}
ngOnInit() {}
}
:host {
background: white;
position: absolute;
top: 0;
height: 100%;
width: 100%;
z-index: 1;
}
mat-toolbar button {
margin-left: -8px;
margin-right: 24px;
}
mat-toolbar span {
flex: 1;
}
<mat-toolbar color="primary">
<button mat-icon-button (click)="history.back()">
<mat-icon>arrow_back</mat-icon>
</button>
<span>卡组编辑</span>
<button mat-icon-button>
<mat-icon>done_all</mat-icon>
</button>
</mat-toolbar>
<mat-nav-list>
<mat-list-item *ngFor="let deck of decks">
<a matLine href="...">{{ deck }}</a>
<button mat-icon-button (click)="remove(deck)">
<mat-icon>delete_forever</mat-icon>
</button>
<button mat-icon-button (click)="true">
<mat-icon>edit</mat-icon>
</button>
<button mat-icon-button (click)="true">
<mat-icon>share</mat-icon>
</button>
</mat-list-item>
</mat-nav-list>
<!--<mat-selection-list>-->
<!--<mat-list-option *ngFor="let deck of decks">-->
<!--<div mat-line>{{deck}}</div>-->
<!--<button mat-icon-button>-->
<!--<mat-icon>info</mat-icon>-->
<!--</button>-->
<!--</mat-list-option>-->
<!--</mat-selection-list>-->
import { Component, OnInit } from '@angular/core';
import { YGOProService } from '../ygopro.service';
import { StorageService } from '../storage.service';
import * as path from 'path';
import { MatDialog } from '@angular/material';
import { ConfirmDialogComponent } from '../confirm-dialog/confirm-dialog.component';
@Component({
selector: 'app-decks',
templateUrl: './decks.component.html',
styleUrls: ['./decks.component.css']
})
export class DecksComponent implements OnInit {
history = history;
decks: string[] = ['test1'];
constructor(private ygopro: YGOProService, private storage: StorageService, private dialog: MatDialog) {}
ngOnInit() {
if (!window.ygopro) {
return;
}
this.decks = this.storage.local_files_do('deck', '.ydk').map(file => path.basename(file, '.ydk'));
// for (const file of ) {
// // const data = this.storage.read_local(file);
// console.log(file, data);
// }
}
async remove(deck: string) {
const dialogRef = this.dialog.open(ConfirmDialogComponent, { data: [deck] });
if (await dialogRef.afterClosed().toPromise()) {
this.decks.splice(this.decks.indexOf(deck), 1);
return this.storage.remove(path.join('deck', `${deck}.ydk`));
}
}
async edit(deck: string) {
this.ygopro.edit_deck(deck);
}
async share() {}
}
:host {
display: block;
position: absolute;
top: 0;
height: 100%;
width: 100%;
overflow-y: auto;
}
#menu { #menu {
margin-left: -8px; margin-left: -8px;
margin-right: 24px; margin-right: 24px;
...@@ -42,15 +51,16 @@ mat-form-field { ...@@ -42,15 +51,16 @@ mat-form-field {
[mat-raised-button] { [mat-raised-button] {
border-radius: 0; border-radius: 0;
box-shadow: none; box-shadow: none;
} }
[mat-button], [mat-raised-button] { [mat-button],
[mat-raised-button] {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
a[mat-button], a[mat-raised-button] { a[mat-button],
a[mat-raised-button] {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
...@@ -91,12 +101,13 @@ a { ...@@ -91,12 +101,13 @@ a {
text-decoration: inherit; text-decoration: inherit;
} }
#points dt, #points dd { #points dt,
#points dd {
width: 56px; width: 56px;
font-size: 14px; font-size: 14px;
} }
#points dd { #points dd {
text-align: right; text-align: right;
margin: 0 margin: 0;
} }
...@@ -80,8 +80,8 @@ ...@@ -80,8 +80,8 @@
<button mat-raised-button (click)="ygopro.backHome()"><span class="icon">233</span><br>直连</button> <button mat-raised-button (click)="ygopro.backHome()"><span class="icon">233</span><br>直连</button>
</mat-grid-tile> </mat-grid-tile>
<!--<mat-grid-tile><a mat-raised-button>--> <!--<mat-grid-tile><a mat-raised-button>-->
<!--<mat-icon>casino</mat-icon>--> <!--<mat-icon>casino</mat-icon>-->
<!--<br>轮抽 (开发中)</a></mat-grid-tile>--> <!--<br>轮抽 (开发中)</a></mat-grid-tile>-->
</mat-grid-list> </mat-grid-list>
<mat-card *ngIf="ygopro.points"> <mat-card *ngIf="ygopro.points">
...@@ -173,7 +173,7 @@ ...@@ -173,7 +173,7 @@
<mat-card *ngFor="let item of ygopro.topics | async"> <mat-card *ngFor="let item of ygopro.topics | async">
<a [href]="item.url" target="_blank"> <a [href]="item.url" target="_blank">
<mat-card-header> <mat-card-header>
<img *ngIf="item.image_url" mat-card-avatar [src]="item.image_url" referrerpolicy="no-referrer"> <img *ngIf="item.image_url" mat-card-avatar [src]="item.image_url">
<mat-card-title>{{item.title}}</mat-card-title> <mat-card-title>{{item.title}}</mat-card-title>
<mat-card-subtitle>by {{item.last_poster_username}} / {{item.last_posted_at | date}} <mat-card-subtitle>by {{item.last_poster_username}} / {{item.last_posted_at | date}}
</mat-card-subtitle> </mat-card-subtitle>
......
...@@ -2,7 +2,7 @@ import { Component, HostBinding } from '@angular/core'; ...@@ -2,7 +2,7 @@ import { Component, HostBinding } from '@angular/core';
import { FormControl } from '@angular/forms'; import { FormControl } from '@angular/forms';
import { environment } from '../../environments/environment'; import { environment } from '../../environments/environment';
import { LoginService } from '../login.service'; import { LoginService } from '../login.service';
import { routerTransition2 } from '../router.animations'; import { routerTransition } from '../router.animations';
import { StorageService } from '../storage.service'; import { StorageService } from '../storage.service';
import { YGOProService } from '../ygopro.service'; import { YGOProService } from '../ygopro.service';
...@@ -13,10 +13,10 @@ import { distinctUntilChanged, filter, map, switchMap } from 'rxjs/internal/oper ...@@ -13,10 +13,10 @@ import { distinctUntilChanged, filter, map, switchMap } from 'rxjs/internal/oper
selector: 'app-lobby', selector: 'app-lobby',
templateUrl: 'lobby.component.html', templateUrl: 'lobby.component.html',
styleUrls: ['lobby.component.css'], styleUrls: ['lobby.component.css'],
animations: [routerTransition2] animations: routerTransition
}) })
export class LobbyComponent { export class LobbyComponent {
@HostBinding('@routerTransition2') animation: ''; @HostBinding('@routerTransition2') animation;
version = environment.version; version = environment.version;
build: BuildConfig; build: BuildConfig;
......
:host {
background: white;
position: absolute;
top: 0;
height: 100%;
width: 100%;
z-index: 1;
}
form { form {
padding: 8px; padding: 8px;
} }
...@@ -8,7 +17,7 @@ form { ...@@ -8,7 +17,7 @@ form {
} }
/*.example-margin {*/ /*.example-margin {*/
/*margin: 0 10px;*/ /*margin: 0 10px;*/
/*}*/ /*}*/
mat-select { mat-select {
......
...@@ -8,11 +8,10 @@ import { YGOProService } from '../ygopro.service'; ...@@ -8,11 +8,10 @@ import { YGOProService } from '../ygopro.service';
selector: 'app-new-room', selector: 'app-new-room',
templateUrl: 'new-room.component.html', templateUrl: 'new-room.component.html',
styleUrls: ['new-room.component.css'], styleUrls: ['new-room.component.css'],
animations: [routerTransition] animations: routerTransition
}) })
export class NewRoomComponent { export class NewRoomComponent {
@HostBinding('@routerTransition') animation = ''; @HostBinding('@routerTransition') animation;
@ViewChild('hostPasswordInput') hostPasswordInput: ElementRef; @ViewChild('hostPasswordInput') hostPasswordInput: ElementRef;
host_password = (this.login.user.external_id ^ 0x54321).toString(); host_password = (this.login.user.external_id ^ 0x54321).toString();
...@@ -23,8 +22,7 @@ export class NewRoomComponent { ...@@ -23,8 +22,7 @@ export class NewRoomComponent {
options: { ...this.ygopro.default_options } options: { ...this.ygopro.default_options }
}; };
constructor(public ygopro: YGOProService, private login: LoginService, private snackBar: MatSnackBar) { constructor(public ygopro: YGOProService, private login: LoginService, private snackBar: MatSnackBar) {}
}
copy(host_password: string) { copy(host_password: string) {
try { try {
......
import { Component, Inject } from '@angular/core'; import { Component, Inject } from '@angular/core';
import { Http } from '@angular/http';
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material'; import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material';
import { LoginService } from '../login.service'; import { LoginService } from '../login.service';
import { MatchDialogComponent } from '../match/match.component'; import { MatchDialogComponent } from '../match/match.component';
...@@ -15,11 +14,12 @@ export class ResultDialogComponent { ...@@ -15,11 +14,12 @@ export class ResultDialogComponent {
exp: string | undefined; exp: string | undefined;
firstWin: string | undefined; firstWin: string | undefined;
constructor(@Inject(MAT_DIALOG_DATA) public last: any, constructor(
public login: LoginService, @Inject(MAT_DIALOG_DATA) public last: any,
private http: Http, public login: LoginService,
public dialog: MatDialog, public dialog: MatDialog,
private dialogRef: MatDialogRef<MatchDialogComponent>) { private dialogRef: MatDialogRef<MatchDialogComponent>
) {
if (this.last.userscorea === this.last.userscoreb) { if (this.last.userscorea === this.last.userscoreb) {
this.result = 'draw'; this.result = 'draw';
} else if (this.last.winner === this.login.user.username) { } else if (this.last.winner === this.login.user.username) {
...@@ -41,7 +41,7 @@ export class ResultDialogComponent { ...@@ -41,7 +41,7 @@ export class ResultDialogComponent {
format(current: number, ex: number = 0) { format(current: number, ex: number = 0) {
const result = Math.round(current) - Math.round(ex); const result = Math.round(current) - Math.round(ex);
return result ? `${(result < 0 ? '' : '+')}${Math.round(result)}` : undefined; return result ? `${result < 0 ? '' : '+'}${Math.round(result)}` : undefined;
} }
again() { again() {
......
...@@ -2,6 +2,11 @@ ...@@ -2,6 +2,11 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%; height: 100%;
width: 100%;
background: white;
position: absolute;
top: 0;
z-index: 1;
} }
.hint { .hint {
......
...@@ -4,28 +4,21 @@ import { LoginService } from '../login.service'; ...@@ -4,28 +4,21 @@ import { LoginService } from '../login.service';
import { routerTransition } from '../router.animations'; import { routerTransition } from '../router.animations';
import { RoomListDataSource, YGOProService } from '../ygopro.service'; import { RoomListDataSource, YGOProService } from '../ygopro.service';
@Component({ @Component({
selector: 'app-room-list', selector: 'app-room-list',
styleUrls: ['room-list.component.css'], styleUrls: ['room-list.component.css'],
templateUrl: 'room-list.component.html', templateUrl: 'room-list.component.html',
animations: [routerTransition] animations: routerTransition
}) })
export class RoomListComponent implements OnInit { export class RoomListComponent implements OnInit {
@HostBinding('@routerTransition') animation;
@HostBinding('@routerTransition')
animation: '';
displayedColumns = ['title', 'users', 'mode', 'extra']; displayedColumns = ['title', 'users', 'mode', 'extra'];
dataSource = new RoomListDataSource(this.ygopro.servers.filter(server => server.custom)); dataSource = new RoomListDataSource(this.ygopro.servers.filter(server => server.custom!));
constructor(public login: LoginService, public ygopro: YGOProService, private changeDetector: ChangeDetectorRef) { constructor(public login: LoginService, public ygopro: YGOProService, private changeDetector: ChangeDetectorRef) {}
}
ngOnInit() { ngOnInit() {
this.changeDetector.detectChanges(); this.changeDetector.detectChanges();
} }
} }
import { animate, state, style, transition, trigger } from '@angular/animations'; import { animate, state, style, transition, trigger } from '@angular/animations';
export const routerTransition = trigger('routerTransition', [ const enter = transition(':enter', animate('175ms cubic-bezier(0, 0, .2, 1)'));
state('void', style({ position: 'absolute', width: '100%' })), const leave = transition(':leave', animate('175ms cubic-bezier(.4, 0, 1, 1)'));
state('*', style({ position: 'absolute', width: '100%' })),
transition(':enter', [ export const routerTransition = [
// before 2.1: transition('void => *', [ trigger('routerTransition', [
style({ transform: 'translateX(100%)' }), state('void', style({ transform: 'translateY(164px)', opacity: 0 })),
animate('.4s', style({ transform: 'translateX(0%)' })) state('*', style({ transform: 'translateY(0)', opacity: 1 })),
]), enter,
transition(':leave', [ leave
// before 2.1: transition('* => void', [
style({ transform: 'translateX(0%)' }),
animate('.4s', style({ transform: 'translateX(100%)' }))
])
]);
export const routerTransition2 = trigger('routerTransition2', [
state('void', style({ position: 'absolute', width: '100%' })),
state('*', style({ position: 'absolute', width: '100%' })),
transition(':enter', [
// before 2.1: transition('void => *', [
style({ transform: 'translateX(-100%)' }),
animate('.4s', style({ transform: 'translateX(0%)' }))
]), ]),
transition(':leave', [ // trigger('toolbarTransition', [
// before 2.1: transition('* => void', [ // transition(':enter', [
style({ transform: 'translateX(0%)' }), // style({ opacity: 0 }),
animate('.4s', style({ transform: 'translateX(-100%)' })) // animate('175ms cubic-bezier(0, 0, .2, 1)')
// ]),
// transition(':leave', [
// style({ opacity: 1 }),
// animate('175ms cubic-bezier(.4, 0, 1, 1)', style({ opacity: 0 }))
// ])
// ]),
trigger('routerTransition2', [
state('void', style({ transform: 'translateY(-24px)' })),
state('*', style({ transform: 'translateY(0)' })),
enter,
leave
]) ])
]); ];
...@@ -24,20 +24,21 @@ type Stats = DirectoryStats | FileStats; ...@@ -24,20 +24,21 @@ type Stats = DirectoryStats | FileStats;
@Injectable() @Injectable()
export class StorageService { export class StorageService {
client = webdav('https://api.mycard.moe/storage/', this.login.user.username, this.login.user.external_id.toString()); app_id = 'ygopro';
working: boolean; client = webdav('https://api.mycard.moe/storage/', this.login.user.username, this.login.user.external_id.toString());
working = false;
constructor(private login: LoginService) {} constructor(private login: LoginService) {}
async sync(app_id: string) { async sync() {
if (!window.ygopro || !window.ygopro.getFileLastModified) { if (!window.ygopro || !window.ygopro.getFileLastModified) {
return; return;
} }
// console.log('sync', 'start'); // console.log('sync', 'start');
const root = path.join('/', app_id); const root = path.join('/', this.app_id);
// 远程有 本地有 // 远程有 本地有
// 远程=本地 更新记录 // 远程=本地 更新记录
...@@ -126,7 +127,7 @@ export class StorageService { ...@@ -126,7 +127,7 @@ export class StorageService {
async upload(local_path: string, remote_path: string, index_path: string) { async upload(local_path: string, remote_path: string, index_path: string) {
this.working = true; this.working = true;
// console.log('upload', local_path, remote_path, index_path); // console.log('upload', local_path, remote_path, index_path);
const data = Buffer.from(window.ygopro.readFile(local_path), 'base64'); const data = this.read_local(local_path);
await this.client.putFileContents(remote_path, data); await this.client.putFileContents(remote_path, data);
const item: FileStats = await this.client.stat(remote_path); const item: FileStats = await this.client.stat(remote_path);
const time = Date.parse(item.lastmod); const time = Date.parse(item.lastmod);
...@@ -135,8 +136,11 @@ export class StorageService { ...@@ -135,8 +136,11 @@ export class StorageService {
localStorage.setItem(index_path, time.toString()); localStorage.setItem(index_path, time.toString());
} }
// 其实没必要 async,只是看着整齐一点 read_local(local_path: string) {
async remove_local(local_path: string, remote_path: string, index_path: string) { return Buffer.from(window.ygopro.readFile(local_path), 'base64');
}
remove_local(local_path: string, remote_path: string, index_path: string) {
this.working = true; this.working = true;
window.ygopro.unlink(local_path); window.ygopro.unlink(local_path);
localStorage.removeItem(index_path); localStorage.removeItem(index_path);
...@@ -148,12 +152,19 @@ export class StorageService { ...@@ -148,12 +152,19 @@ export class StorageService {
localStorage.removeItem(index_path); localStorage.removeItem(index_path);
} }
async remove(local_path: string) {
const root = path.join('/', this.app_id);
const remote_path = path.join(root, local_path);
const index_path = '_FILE_' + remote_path;
this.working = true;
window.ygopro.unlink(local_path);
await this.client.deleteFile(remote_path);
localStorage.removeItem(index_path);
}
local_files() { local_files() {
return [ return [...this.local_files_do('deck', '.ydk'), ...this.local_files_do('replay', '.yrp'), ...this.local_files_do('single', '.lua')];
...this.local_files_do('deck', '.ydk'),
...this.local_files_do('replay', '.yrp'),
...this.local_files_do('single', '.lua'),
];
} }
local_files_do(directory, extname): string[] { local_files_do(directory, extname): string[] {
......
<mat-toolbar color="primary"> <mat-toolbar color="primary">
<button mat-icon-button (click)="history.back()"> <button mat-icon-button (click)="history.back()">
<mat-icon>&#xe5c4;</mat-icon><!--arrow_back--></button> <mat-icon>arrow_back</mat-icon>
</button>
<span><ng-content></ng-content></span> <span><ng-content></ng-content></span>
</mat-toolbar> </mat-toolbar>
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { routerTransition } from '../router.animations';
@Component({ @Component({
selector: 'app-toolbar', selector: 'app-toolbar',
templateUrl: './toolbar.component.html', templateUrl: './toolbar.component.html',
styleUrls: ['./toolbar.component.css'] styleUrls: ['./toolbar.component.css'],
animations: [routerTransition]
}) })
export class ToolbarComponent { export class ToolbarComponent {
history = history; history = history;
constructor() { constructor() {}
}
} }
...@@ -2,6 +2,11 @@ ...@@ -2,6 +2,11 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%; height: 100%;
width: 100%;
background: white;
position: absolute;
top: 0;
z-index: 1;
} }
.hint { .hint {
......
...@@ -7,21 +7,17 @@ import { RoomListDataSource, YGOProService } from '../ygopro.service'; ...@@ -7,21 +7,17 @@ import { RoomListDataSource, YGOProService } from '../ygopro.service';
selector: 'app-watch', selector: 'app-watch',
templateUrl: './watch.component.html', templateUrl: './watch.component.html',
styleUrls: ['./watch.component.css'], styleUrls: ['./watch.component.css'],
animations: [routerTransition] animations: routerTransition
}) })
export class WatchComponent implements OnInit { export class WatchComponent implements OnInit {
@HostBinding('@routerTransition') animation;
@HostBinding('@routerTransition')
animation = '';
displayedColumns = ['mode', 'title', 'users', 'extra']; displayedColumns = ['mode', 'title', 'users', 'extra'];
dataSource = new RoomListDataSource(this.ygopro.servers, 'started'); dataSource = new RoomListDataSource(this.ygopro.servers, 'started');
constructor(public login: LoginService, public ygopro: YGOProService, private changeDetector: ChangeDetectorRef) { constructor(public login: LoginService, public ygopro: YGOProService, private changeDetector: ChangeDetectorRef) {}
}
ngOnInit() { ngOnInit() {
this.changeDetector.detectChanges(); this.changeDetector.detectChanges();
} }
} }
:host {
background: white;
position: absolute;
top: 0;
height: 100%;
width: 100%;
z-index: 1;
}
.avatar { .avatar {
width: 24px; width: 24px;
height: 24px; height: 24px;
......
...@@ -7,12 +7,10 @@ import { YGOProService } from '../ygopro.service'; ...@@ -7,12 +7,10 @@ import { YGOProService } from '../ygopro.service';
selector: 'app-windbot', selector: 'app-windbot',
templateUrl: './windbot.component.html', templateUrl: './windbot.component.html',
styleUrls: ['./windbot.component.css'], styleUrls: ['./windbot.component.css'],
animations: [routerTransition] animations: routerTransition
}) })
export class WindbotComponent { export class WindbotComponent {
@HostBinding('@routerTransition') @HostBinding('@routerTransition') animation;
animation = '';
constructor(public login: LoginService, public ygopro: YGOProService) { constructor(public login: LoginService, public ygopro: YGOProService) {}
}
} }
...@@ -54,7 +54,7 @@ export interface Server { ...@@ -54,7 +54,7 @@ export interface Server {
replay?: boolean; replay?: boolean;
} }
class News { interface News {
title: string; title: string;
text: string; text: string;
url: string; url: string;
...@@ -152,7 +152,7 @@ export class YGOProService { ...@@ -152,7 +152,7 @@ export class YGOProService {
]; ];
constructor(private login: LoginService, private http: HttpClient, private dialog: MatDialog, private storage: StorageService) { constructor(private login: LoginService, private http: HttpClient, private dialog: MatDialog, private storage: StorageService) {
this.load().catch(alert); this.load();
} }
async load() { async load() {
...@@ -170,7 +170,7 @@ export class YGOProService { ...@@ -170,7 +170,7 @@ export class YGOProService {
) )
); );
this.storage.sync('ygopro'); this.storage.sync();
this.load_points(); this.load_points();
await this.load_result(false); await this.load_result(false);
...@@ -238,13 +238,13 @@ export class YGOProService { ...@@ -238,13 +238,13 @@ export class YGOProService {
fromEvent(document, evtname).subscribe(() => { fromEvent(document, evtname).subscribe(() => {
if (!document[hidden]) { if (!document[hidden]) {
this.load_result(); this.load_result();
this.storage.sync('ygopro'); this.storage.sync();
} }
}); });
} else { } else {
fromEvent(window, 'focus').subscribe(() => { fromEvent(window, 'focus').subscribe(() => {
this.load_result(); this.load_result();
this.storage.sync('ygopro'); this.storage.sync();
}); });
} }
} }
...@@ -352,12 +352,20 @@ export class YGOProService { ...@@ -352,12 +352,20 @@ export class YGOProService {
} }
} }
edit_deck() { edit_deck(deck?: string) {
try { if (deck) {
window.ygopro.edit_deck(); try {
} catch (error) { window.ygopro.edit_deck(deck);
console.error(error); } catch {
alert(JSON.stringify({ method: 'edit_deck', params: [] })); this.edit_deck();
}
} else {
try {
window.ygopro.edit_deck();
} catch (error) {
console.error(error);
alert(JSON.stringify({ method: 'edit_deck', params: [] }));
}
} }
} }
......
...@@ -9,6 +9,7 @@ html, body { ...@@ -9,6 +9,7 @@ html, body {
body { body {
margin: 0; margin: 0;
overflow: hidden;
} }
#loading { #loading {
......
...@@ -4,7 +4,7 @@ interface Window { ...@@ -4,7 +4,7 @@ interface Window {
join(address: string, port: number, username: string, password: string): void; join(address: string, port: number, username: string, password: string): void;
// 编辑卡组 // 编辑卡组
edit_deck(): void; edit_deck(deck?: string): void;
// 观看录像,进入观看录像界面 // 观看录像,进入观看录像界面
watch_replay(): void; watch_replay(): void;
......
...@@ -8,7 +8,10 @@ ...@@ -8,7 +8,10 @@
"moduleResolution": "node", "moduleResolution": "node",
"emitDecoratorMetadata": true, "emitDecoratorMetadata": true,
"experimentalDecorators": true, "experimentalDecorators": true,
"target": "es2017", "target": "es2016",
"strict": true,
"noImplicitAny": false,
"strictPropertyInitialization": false,
"typeRoots": [ "typeRoots": [
"node_modules/@types" "node_modules/@types"
], ],
......
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