mirror of
https://github.com/BrenBroZAYT/gameyfin.git
synced 2026-06-16 08:15:48 +00:00
WIP: Implement frontend
This commit is contained in:
@@ -28,7 +28,7 @@ public class LibraryController {
|
|||||||
if(downloadImages) downloadImages();
|
if(downloadImages) downloadImages();
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping(value = "/download_images")
|
@GetMapping(value = "/download-images")
|
||||||
public void downloadImages() {
|
public void downloadImages() {
|
||||||
filesystemService.downloadGameCovers();
|
filesystemService.downloadGameCovers();
|
||||||
filesystemService.downloadGameScreenshots();
|
filesystemService.downloadGameScreenshots();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
gameyfin:
|
gameyfin:
|
||||||
root: C:\Projects\privat\gameyfin-library
|
#root: C:\Projects\privat\gameyfin-library
|
||||||
#root: \\NAS-Simon\Öffentlich\Spiele
|
root: \\NAS-Simon\Öffentlich\Spiele
|
||||||
cache: ${gameyfin.root}\.gameyfin\cache
|
cache: ${gameyfin.root}\.gameyfin\cache
|
||||||
db: ${gameyfin.root}\.gameyfin\db # Currently unused
|
db: ${gameyfin.root}\.gameyfin\db # Currently unused
|
||||||
igdb:
|
igdb:
|
||||||
|
|||||||
@@ -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[]>;
|
||||||
|
}
|
||||||
@@ -31,6 +31,8 @@ import {MatPaginatorModule} from "@angular/material/paginator";
|
|||||||
import {MatSortModule} from "@angular/material/sort";
|
import {MatSortModule} from "@angular/material/sort";
|
||||||
import { GameCoverComponent } from './components/game-cover/game-cover.component';
|
import { GameCoverComponent } from './components/game-cover/game-cover.component';
|
||||||
import { GameDetailViewComponent } from './components/game-detail-view/game-detail-view.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({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@@ -66,7 +68,9 @@ import { GameDetailViewComponent } from './components/game-detail-view/game-deta
|
|||||||
MatProgressSpinnerModule,
|
MatProgressSpinnerModule,
|
||||||
MatTableModule,
|
MatTableModule,
|
||||||
MatPaginatorModule,
|
MatPaginatorModule,
|
||||||
MatSortModule
|
MatSortModule,
|
||||||
|
MatSnackBarModule,
|
||||||
|
MatGridListModule
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,6 +6,6 @@
|
|||||||
@include mat.elevation(4);
|
@include mat.elevation(4);
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
@include mat.elevation(12);
|
@include mat.elevation(24);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1,8 @@
|
|||||||
<mat-toolbar role="heading">
|
<mat-toolbar role="heading">
|
||||||
|
|
||||||
|
<span class="spacer"></span>
|
||||||
|
|
||||||
|
<button mat-icon-button (click)="reloadLibrary()">
|
||||||
|
<mat-icon>youtube_searched_for</mat-icon>
|
||||||
|
</button>
|
||||||
</mat-toolbar>
|
</mat-toolbar>
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import {Component, OnInit} from '@angular/core';
|
import {Component, OnInit} from '@angular/core';
|
||||||
import {NavMenuItem} from '../../models/objects/NavMenuItem';
|
import {NavMenuItem} from '../../models/objects/NavMenuItem';
|
||||||
import {Title} from '@angular/platform-browser';
|
import {LibraryService} from "../../services/library.service";
|
||||||
import {Config} from '../../config/Config';
|
import {MatSnackBar} from '@angular/material/snack-bar';
|
||||||
import {Icon} from '../../models/enums/Icon';
|
import {timeInterval} from "rxjs";
|
||||||
import {DropDownMenuItem} from "../../models/objects/DropDownMenuItem";
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-header',
|
selector: 'app-header',
|
||||||
@@ -12,29 +11,19 @@ import {DropDownMenuItem} from "../../models/objects/DropDownMenuItem";
|
|||||||
})
|
})
|
||||||
export class HeaderComponent implements OnInit {
|
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;
|
activeItem: NavMenuItem | undefined;
|
||||||
|
|
||||||
constructor(private titleService: Title) {
|
constructor(private libraryService: LibraryService,
|
||||||
|
private snackBar: MatSnackBar) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
}
|
}
|
||||||
|
|
||||||
setActiveItem(item: NavMenuItem) {
|
reloadLibrary() {
|
||||||
this.activeItem = item;
|
this.libraryService.scanLibrary().pipe(timeInterval()).subscribe({
|
||||||
this.titleService.setTitle(`${Config.baseTitle} - ${item.title}`);
|
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;
|
align-items: center;
|
||||||
justify-content: 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>
|
<mat-spinner></mat-spinner>
|
||||||
<h2>Loading library...</h2>
|
<h2>Loading library...</h2>
|
||||||
</div>
|
</div>
|
||||||
<div fxLayout="row" fxLayoutAlign="center center">
|
|
||||||
<div *ngIf="!this.loading && this.detectedGames.length === 0">
|
<div fxLayout="row" fxLayoutAlign="center center" *ngIf="!this.loading && this.detectedGames.length === 0">
|
||||||
<h2>Your game library is empty!</h2>
|
<h2>Your game library is empty!</h2>
|
||||||
</div>
|
</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 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>
|
</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`);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user