WIP: Implement frontend

This commit is contained in:
grimsi
2022-07-22 15:16:19 +02:00
parent a06dfa7c47
commit e11611bbe6
11 changed files with 88 additions and 48 deletions
@@ -28,7 +28,7 @@ public class LibraryController {
if(downloadImages) downloadImages();
}
@GetMapping(value = "/download_images")
@GetMapping(value = "/download-images")
public void downloadImages() {
filesystemService.downloadGameCovers();
filesystemService.downloadGameScreenshots();
@@ -1,6 +1,6 @@
gameyfin:
root: C:\Projects\privat\gameyfin-library
#root: \\NAS-Simon\Öffentlich\Spiele
#root: C:\Projects\privat\gameyfin-library
root: \\NAS-Simon\Öffentlich\Spiele
cache: ${gameyfin.root}\.gameyfin\cache
db: ${gameyfin.root}\.gameyfin\db # Currently unused
igdb:
+10
View File
@@ -0,0 +1,10 @@
import {Observable} from "rxjs";
import {DetectedGameDto} from "../models/dtos/DetectedGameDto";
import {GameOverviewDto} from "../models/dtos/GameOverviewDto";
import {HttpResponse} from "@angular/common/http";
export interface LibraryApi {
scanLibrary(): Observable<HttpResponse<Response>>;
downloadImages(): Observable<HttpResponse<Response>>;
getFiles(): Observable<string[]>;
}
+5 -1
View File
@@ -31,6 +31,8 @@ import {MatPaginatorModule} from "@angular/material/paginator";
import {MatSortModule} from "@angular/material/sort";
import { GameCoverComponent } from './components/game-cover/game-cover.component';
import { GameDetailViewComponent } from './components/game-detail-view/game-detail-view.component';
import {MatSnackBarModule} from '@angular/material/snack-bar';
import {MatGridListModule} from "@angular/material/grid-list";
@NgModule({
declarations: [
@@ -66,7 +68,9 @@ import { GameDetailViewComponent } from './components/game-detail-view/game-deta
MatProgressSpinnerModule,
MatTableModule,
MatPaginatorModule,
MatSortModule
MatSortModule,
MatSnackBarModule,
MatGridListModule
],
providers: [
{
@@ -6,6 +6,6 @@
@include mat.elevation(4);
&:hover {
@include mat.elevation(12);
@include mat.elevation(24);
}
}
@@ -1,2 +1,8 @@
<mat-toolbar role="heading">
<span class="spacer"></span>
<button mat-icon-button (click)="reloadLibrary()">
<mat-icon>youtube_searched_for</mat-icon>
</button>
</mat-toolbar>
@@ -1,9 +1,8 @@
import {Component, OnInit} from '@angular/core';
import {NavMenuItem} from '../../models/objects/NavMenuItem';
import {Title} from '@angular/platform-browser';
import {Config} from '../../config/Config';
import {Icon} from '../../models/enums/Icon';
import {DropDownMenuItem} from "../../models/objects/DropDownMenuItem";
import {LibraryService} from "../../services/library.service";
import {MatSnackBar} from '@angular/material/snack-bar';
import {timeInterval} from "rxjs";
@Component({
selector: 'app-header',
@@ -12,29 +11,19 @@ import {DropDownMenuItem} from "../../models/objects/DropDownMenuItem";
})
export class HeaderComponent implements OnInit {
tabNavItems: NavMenuItem[] = [
new NavMenuItem('Servers', Icon.dns, '/servers', true),
new NavMenuItem('Games', Icon.controller, '/games', true),
new NavMenuItem('Info', Icon.info, '/info', true),
new NavMenuItem('Config', Icon.settings, '/config', true),
];
dropDownItems: DropDownMenuItem[] = [
new DropDownMenuItem('Log out', Icon.lock_open, () => {
alert("Logout not implemented");
}, true)
];
activeItem: NavMenuItem | undefined;
constructor(private titleService: Title) {
constructor(private libraryService: LibraryService,
private snackBar: MatSnackBar) {
}
ngOnInit() {
}
setActiveItem(item: NavMenuItem) {
this.activeItem = item;
this.titleService.setTitle(`${Config.baseTitle} - ${item.title}`);
reloadLibrary() {
this.libraryService.scanLibrary().pipe(timeInterval()).subscribe({
next: value => this.snackBar.open(`Library scan completed in ${Math.trunc(value.interval/1000)} seconds.`),
error: error => this.snackBar.open(`Error while scanning library: ${error}`)
})
}
}
@@ -10,3 +10,16 @@
align-items: center;
justify-content: center;
}
.content {
padding: 16px;
}
.content > mat-card {
margin-bottom: 16px;
}
.column-label {
margin-right: 8px;
font-size: 1rem;
}
@@ -3,12 +3,16 @@
<mat-spinner></mat-spinner>
<h2>Loading library...</h2>
</div>
<div fxLayout="row" fxLayoutAlign="center center">
<div *ngIf="!this.loading && this.detectedGames.length === 0">
<h2>Your game library is empty!</h2>
</div>
<div fxLayout="row" fxLayoutGap="12px" [style.margin-top.px]="12" *ngIf="!this.loading && this.detectedGames.length > 0">
<game-cover fxLayout="column" *ngFor="let game of detectedGames" [game]="game"></game-cover>
<div fxLayout="row" fxLayoutAlign="center center" *ngIf="!this.loading && this.detectedGames.length === 0">
<h2>Your game library is empty!</h2>
</div>
<div class="content">
<div fxLayout="row wrap" fxLayoutGap="16px grid">
<div fxFlex="25% 1" fxFlex.xs="100%" fxFlex.sm="33%" *ngFor="let game of detectedGames">
<game-cover [game]="game"></game-cover>
</div>
</div>
</div>
</div>
@@ -1,16 +0,0 @@
import { TestBed } from '@angular/core/testing';
import { GamesService } from './games.service';
describe('GameserverApiService', () => {
let service: GamesService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(GamesService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
@@ -0,0 +1,30 @@
import {Injectable} from '@angular/core';
import {GamesApi} from "../api/GamesApi";
import {HttpClient, HttpResponse} from "@angular/common/http";
import {Observable} from "rxjs";
import {DetectedGameDto} from "../models/dtos/DetectedGameDto";
import {GameOverviewDto} from "../models/dtos/GameOverviewDto";
import {LibraryApi} from "../api/LibraryApi";
@Injectable({
providedIn: 'root'
})
export class LibraryService implements LibraryApi {
private readonly apiPath = '/library';
constructor(private http: HttpClient) {
}
scanLibrary(): Observable<HttpResponse<Response>> {
return this.http.get<HttpResponse<Response>>(`${this.apiPath}/scan`);
}
downloadImages(): Observable<HttpResponse<Response>> {
return this.http.get<HttpResponse<Response>>(`${this.apiPath}/download-images`);
}
getFiles(): Observable<string[]> {
return this.http.get<string[]>(`${this.apiPath}/files`);
}
}